diff --git a/src_rbd/pipeline/rbd_state_from_rapier.rs b/src_rbd/pipeline/rbd_state_from_rapier.rs index 92bdd1e..0a34830 100644 --- a/src_rbd/pipeline/rbd_state_from_rapier.rs +++ b/src_rbd/pipeline/rbd_state_from_rapier.rs @@ -146,6 +146,10 @@ impl RbdState { // the equal-topology invariant and to set `BatchIndices::bodies_len`. let mut all_env_body_counts: Vec = Vec::new(); let mut shape_buffers = ShapeBuffers::default(); + // TriMesh dedupe: a `SharedShape` cloned across envs (e.g. shared + // terrain) is serialized into `shape_buffers` once and its `Shape` + // descriptor reused — keyed by the parry shape data pointer. + let mut trimesh_cache: HashMap = HashMap::new(); let mut joint_envs: Vec<( &ImpulseJointSet, HashMap, @@ -273,9 +277,24 @@ impl RbdState { } }; - all_shapes.push( - shape_from_parry(co.shape(), &mut shape_buffers).expect("Unsupported shape"), - ); + let gpu_shape = match co.shape().as_typed_shape() { + crate::parry::shape::TypedShape::TriMesh(tm) => { + let key = tm as *const _ as *const u8 as usize; + match trimesh_cache.get(&key) { + Some(&s) => s, + None => { + let s = shape_from_parry(co.shape(), &mut shape_buffers) + .expect("Unsupported shape"); + trimesh_cache.insert(key, s); + s + } + } + } + _ => { + shape_from_parry(co.shape(), &mut shape_buffers).expect("Unsupported shape") + } + }; + all_shapes.push(gpu_shape); all_collider_local_poses.push(collider_local_pose); all_collision_groups.push(co.collision_groups()); all_collider_materials.push(collider_material_from_rapier(co));