bevy_silk 0.4.0

Cloth physics implementation in bevy
Documentation
#![allow(
    clippy::needless_pass_by_value,
    clippy::type_complexity,
    clippy::option_if_let_else
)]

use crate::components::cloth::Cloth;
use crate::components::cloth_builder::ClothBuilder;
use crate::components::cloth_rendering::ClothRendering;
use crate::config::ClothConfig;
use crate::wind::Winds;
use bevy::log::{debug, error, warn};
use bevy::math::Vec3;
use bevy::prelude::*;

pub fn update(
    mut query: Query<(&mut Cloth, &GlobalTransform, Option<&ClothConfig>)>,
    anchor_query: Query<&GlobalTransform, Without<Cloth>>,
    config: Res<ClothConfig>,
    wind: Option<Res<Winds>>,
    time: Res<Time>,
) {
    let delta_time = time.delta_seconds();
    let wind_force = wind.map_or(Vec3::ZERO, |w| w.current_velocity(time.elapsed_seconds()));
    for (mut cloth, transform, custom_config) in query.iter_mut() {
        let config: &ClothConfig = custom_config.unwrap_or(&config);
        cloth.update_points(
            config.friction_coefficient(),
            config.smoothed_acceleration(wind_force + config.gravity, delta_time),
        );
        cloth.update_anchored_points(transform, |entity| {
            if let Ok(t) = anchor_query.get(entity) {
                Some(t)
            } else {
                error!("Could not find cloth anchor target entity {:?}", entity);
                None
            }
        });
        cloth.update_sticks(config.sticks_computation_depth);
    }
}

pub fn render(
    mut cloth_query: Query<(&Cloth, &mut ClothRendering, &GlobalTransform, &Handle<Mesh>)>,
    mut meshes: ResMut<Assets<Mesh>>,
) {
    for (cloth, mut rendering, transform, handle) in cloth_query.iter_mut() {
        if let Some(mesh) = meshes.get_mut(handle) {
            rendering.update_positions(cloth.compute_vertex_positions(transform));
            rendering.apply(mesh);
        } else {
            warn!("A Cloth has a `ClothRendering` component without a loaded mesh handle");
        }
    }
}

pub fn init(
    mut commands: Commands,
    query: Query<(Entity, &ClothBuilder, &GlobalTransform, &Handle<Mesh>), Without<Cloth>>,
    meshes: Res<Assets<Mesh>>,
) {
    for (entity, builder, transform, handle) in query.iter() {
        if let Some(mesh) = meshes.get(handle) {
            let matrix = transform.compute_matrix();
            debug!("Initializing Cloth entity {:?}", entity);
            let rendering = ClothRendering::init(mesh, builder.normals_computing).unwrap();
            let cloth = Cloth::new(
                &rendering.vertex_positions,
                &rendering.indices,
                builder.anchored_vertex_ids(mesh),
                builder.stick_generation,
                builder.stick_length,
                &matrix,
            );
            // TODO: should the cloth builder be removed ?
            commands.entity(entity).insert((rendering, cloth));
        }
    }
}