Release Type: latest
Version: Master
Describe the bug
ConvexHullCollider.AddToCompoundBuilder builds the Bepu shape with new ConvexHull(points, pool, out var center). Bepu recenters the hull points on the hull's center of mass and returns that center so the caller can put the shape back where the points were. The collider does this:
|
foreach (var (hull, center) in _cache.Hulls) |
|
{ |
|
var poseForThisHull = localPose; |
|
poseForThisHull.Position += center; |
|
builder.Add(hull, poseForThisHull, Mass); |
|
} |
center is expressed in the hull's local frame, but it is added to localPose.Position as if it were already in the compound's frame. The result is only correct when RotationLocal is identity. For any rotated ConvexHullCollider child, the physics shape ends up offset from the rendered mesh by center - Rotate(center, RotationLocal), which can be a large fraction of the shape size for hulls whose center of mass is far from the local origin (wedges, ramps, pyramids, rocks, anything asymmetric).
To Reproduce
Steps to reproduce the behavior:
- Create a hull asset from an asymmetric mesh, e.g. a wedge (triangular prism), so that its center of mass is not at the local origin.
- Add it as a ConvexHullCollider to a CompoundCollider, together with a BoxCollider for reference, and give the hull a non-identity RotationLocal (a 90° or 180° turn is enough).
- Enable physics debug draw, or ray cast against the collidable, and compare the collision surface with the rendered mesh.
Observed: the box collides exactly where it is drawn, the rotated hull collides offset from its mesh by center - Rotate(center, RotationLocal). With identity rotation the hull matches the mesh exactly.
Expected behavior
The hull shape should occupy exactly the volume of the source mesh regardless of RotationLocal. The recentering offset has to be rotated into the compound frame before it is added:
var poseForThisHull = localPose;
poseForThisHull.Position += System.Numerics.Vector3.Transform(center, localPose.Orientation);
builder.Add(hull, poseForThisHull, Mass);
(localPose.Orientation is a System.Numerics.Quaternion, so Vector3.Transform from System.Numerics applies directly.)
Additional context
The bug is invisible for hulls whose center of mass is at the local origin (symmetric meshes centered on their pivot) and for identity RotationLocal, which is probably why it went unnoticed.
Release Type: latest
Version: Master
Describe the bug
ConvexHullCollider.AddToCompoundBuilder builds the Bepu shape with new ConvexHull(points, pool, out var center). Bepu recenters the hull points on the hull's center of mass and returns that center so the caller can put the shape back where the points were. The collider does this:
stride/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Colliders/ConvexHullCollider.cs
Lines 64 to 69 in d00acb2
center is expressed in the hull's local frame, but it is added to localPose.Position as if it were already in the compound's frame. The result is only correct when RotationLocal is identity. For any rotated ConvexHullCollider child, the physics shape ends up offset from the rendered mesh by center - Rotate(center, RotationLocal), which can be a large fraction of the shape size for hulls whose center of mass is far from the local origin (wedges, ramps, pyramids, rocks, anything asymmetric).
To Reproduce
Steps to reproduce the behavior:
Observed: the box collides exactly where it is drawn, the rotated hull collides offset from its mesh by center - Rotate(center, RotationLocal). With identity rotation the hull matches the mesh exactly.
Expected behavior
The hull shape should occupy exactly the volume of the source mesh regardless of RotationLocal. The recentering offset has to be rotated into the compound frame before it is added:
(localPose.Orientation is a System.Numerics.Quaternion, so Vector3.Transform from System.Numerics applies directly.)
Additional context
The bug is invisible for hulls whose center of mass is at the local origin (symmetric meshes centered on their pivot) and for identity RotationLocal, which is probably why it went unnoticed.