Convex Hulls don't match with center of model

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
vendetta
Posts: 18
Joined: Sat Dec 31, 2011 7:49 pm

Convex Hulls don't match with center of model

Post by vendetta »

Hi Norbo, sorry for all the questions recently :roll:

I'm having a strange bug with dynamic physics entities in my game, their models don't match up with the physics entity. It seems as though they aren't correctly centered, however using this fix viewtopic.php?f=4&t=1494&p=8826 doesn't solve my problem.

I'm creating my entity as follows:

Code: Select all

 
                                    var modelWorld = Matrix.CreateWorld(position, forward, up);
                                    Vector3[] vertices;
                                    int[] indices;

                                    TriangleMesh.GetVerticesAndIndicesFromModel(model, out vertices, out indices);

                                    var convexHull = new ConvexHull(vertices, 1);

                                    //This line doesn't seem to do anything
                                    convexHull.CollisionInformation.LocalPosition = position;

                                    TransformableShape shape = new TransformableShape(convexHull.CollisionInformation.Shape,
                                        Matrix3X3.CreateFromMatrix(modelWorld));

                                    var SpaceObject = new Entity<ConvexCollidable<TransformableShape>>(
                                        new ConvexCollidable<TransformableShape>(shape), 1, convexHull.LocalInertiaTensor, convexHull.Volume);
                                    SpaceObject.Position = position;
                                    SpaceObject.BecomeDynamic(convexHull.Mass);                                                                       

                                    Engine.PhysicsEngineComponent.Space.Add(SpaceObject);

                                    var dynModel = new DynamicMapObject(model, SpaceObject, scale);
                                    Engine.RenderComponent.SubmitDynamicMapObject(dynModel);
(This is my DynamicMapObject class:)

Code: Select all

  public class DynamicMapObject
    {
        public Entity PhysicsEntity;
        public SceneObject SceneObject;
        public Vector3 ModelScale;
        public DynamicMapObject(Model model, Entity obj, Vector3 Scale)
        {
            this.ModelScale = Scale;
            PhysicsEntity = obj;
            SceneObject = new SceneObject(model);
        }

        public void Update()
        {
            if (SceneObject != null)
            {
                SceneObject.World = Matrix.CreateScale(ModelScale) * PhysicsEntity.WorldTransform;              
            }
        }
    }
All of my model's scales are 1,1,1, and completely removing scales from the code doesn't remove the bug, either (they still draw the same either with or without Matrix.CreateScale...).

Here is are screenshots of the bug: phys3.jpg, phys4.jpg, phys1.jpg, phys2.jpg

The static physics objects work great, it only appears to be the convex / dynamic shapes that are affected.

Is there a way to fix this offsetting?

Thank you for all of your work on bepu and supporting such a wonderful library :)
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Convex Hulls don't match with center of model

Post by Norbo »

Entities rotate around their center of mass/volume, not the origin defined in a modelling program. For example, when constructing a convex hull, the points passed into the constructor will be used to compute a center position. That center position is subtracted from all the shape's points so that they are all in the proper local space. The computed center position can be outputted by an alternate constructor of the ConvexHullShape.

This is how the prefab entity types such as the ConvexHull work. They create a ConvexHullShape, take the position the constructor outputs, and set that as their Position. That way, the collision shape ends up starting in the same place as the vertices were defined.

When making a model in a modelling program, it's very rare that the origin will be at the volumetric center as opposed to the bottom of the mesh or some other convenient base. If the graphical mesh is transformed by the entity's world transform directly with no pre-modification, the graphical mesh will appear offset because the origin of the entity's collision shape does not match the origin of the graphical mesh.

For shapes which have nontrivial center computations like the ConvexHullShape, you can use the previously computed center position to offset the graphical mesh before transforming it by the entity's world transform. The pre-transform brings the graphical mesh into alignment with the collision shape.

When dealing with TransformableShapes, a bit more care is required. The shape given to the TransformableShape constructor has already been recentered, so the center position the TransformableShape constructor can output isn't the full offset alone.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Convex Hulls don't match with center of model

Post by Norbo »

I should also explain what the LocalPosition is and why it is typically not used to address this issue.

When LocalPosition is the zero vector, the collision shape's origin is perfectly aligned with the Entity's Position property. The Entity rotates around the Position property. In effect, the entity rotates around the center of the collision shape.

Sometimes, you don't want to rotate exactly around the center of the collision shape. The LocalPosition allows you to specify an offset to the collision shape. So, given identity orientation and a LocalPosition of (0, 1, 0), the collision shape's center would be one unit higher than the Entity's Position. It would look like the collision shape is 'swinging' around.

Since changing LocalPosition changes the pivot point of rotation relative to the collision shape, it's not usually a good way to align graphics to a collision shape. The original post in the thread you linked suggests a way to offset the collision shape to match a graphic and use the graphical model's pivot point. It's more physically 'correct' and far more common to use the physical center of mass as the pivot point, which means offsetting the graphic to match the collision shape.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Convex Hulls don't match with center of model

Post by Norbo »

Since this issue comes up so frequently I went ahead and cobbled a little paint.net image together explaining it visually:
offsetexplanation.jpg
offsetexplanation.jpg (235.24 KiB) Viewed 13334 times
vendetta
Posts: 18
Joined: Sat Dec 31, 2011 7:49 pm

Re: Convex Hulls don't match with center of model

Post by vendetta »

That makes sense, and I believe it should be relatively easy to implement.

I tried modifying my DynamicMapObject's update method to look like this:

Code: Select all

 SceneObject.World = Matrix.CreateScale(ModelScale) * Matrix.CreateFromQuaternion(PhysicsEntity.Orientation) *
                    Matrix.CreateTranslation(PhysicsEntity.Position + DrawDifference);              
DrawDifference is a Vector3 that I calculate after constructing the ConvexHull for my model:

Code: Select all

     var convexHull = new ConvexHull(vertices, 1);
     Vector3 difference = Vector3.Zero - convexHull.Position;
     Console.WriteLine("DrawDistance: " + difference);
This works fine when the model isn't rotated, like so: chestLid1.jpg
However, when I pick the lid up and rotate it on its top, it sinks into the ground (obviously due to the offsetting): chestLid2.jpg

I know this isn't specifically a physics bug, but do you know of a way I could solve this?
Thanks for the help, and that diagram made it a lot easier to understand the problem!
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Convex Hulls don't match with center of model

Post by Norbo »

The offset needs to be applied in local space. So, instead of applying the offset with the final translation, use a separate translation that is applied before the entity's world transform (immediately before or after the scale depending on how it's being used). That way, when the world transform is applied, it's changing the already offset configuration and everything goes to where it needs to go.
vendetta
Posts: 18
Joined: Sat Dec 31, 2011 7:49 pm

Re: Convex Hulls don't match with center of model

Post by vendetta »

I'm still having issues after I followed (or attempted to follow) your last post.

I modified my World update code to look like this:

Code: Select all

               var rotMatrix = Matrix.CreateFromQuaternion(PhysicsEntity.Orientation);
                SceneObject.World = Matrix.CreateScale(ModelScale); 
                SceneObject.World *= Matrix.CreateTranslation(DrawDifference);  //I added this line          
                SceneObject.World *= Matrix.CreateWorld(PhysicsEntity.Position, rotMatrix.Forward, rotMatrix.Up);
Adding that line helped, but the offset is still present. It can't easily be seen between the floor and the convex hull prop, but it can be seen if I do something like this:
balance1.jpg

Am I doing the local offset correctly or am I completely off?

Thank you for all of your help, I'm a noob at these types of things :cry:
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Convex Hulls don't match with center of model

Post by Norbo »

In terms of the applied transforms, that looks technically correct. You could cut out some complexity by just using the Entity.WorldTransform instead of using Matrix.CreateWorld.

The remaining 'offset' may not be an offset at all. The general convex-convex collision detection system makes use of a collision margin to allow faster, robust algorithms. The margin is basically a slight spherical expansion around all convex shapes. This old post includes a picture of what a sphere-expanded box might look like: viewtopic.php?f=4&t=409

Collision margins default to 0.04 for most shapes, including the ConvexHullShape. You can set a ConvexShape's CollisionMargin to something else that's smaller to lessen the gap, but be warned that this will force the collision detection system to fall back to a more expensive algorithm more often. Setting the margin to zero will eliminate the gap with constant extra cost.

If the performance is needed, an alternative to shrinking the margin is to create the collision shape from a simplified model which takes into account the existence of the collision margin. That way, when expanded, it will match the graphic without gaps.

Boxes, spheres, capsules, and cylinders have 'internal' collision margins, which means instead of expanding outward, the core shape is shrunk such that the margin-expanded surface matches the proper dimensions. Other shapes don't have internal margins because it can change the shape too dramatically (consider the result of an internal margin on a sharp cone). Special case collision detection systems like box-box operate directly on the full dimensions of the shape.
vendetta
Posts: 18
Joined: Sat Dec 31, 2011 7:49 pm

Re: Convex Hulls don't match with center of model

Post by vendetta »

Ah, that makes perfect sense!

I also came up with a solution that is working for my models, and I thought I would post it here in case anyone else ever needs it.

I first changed the default margin to 0.02, which is half of the default.

Then I looped through the vertices extracted from the TriangleMesh method and applied 1/2 of the collision margin (so in my case the convex hull is slightly smaller than the model it was created from):

Code: Select all

                                   Vector3[] vertices;
                                    int[] indices;
                                    TriangleMesh.GetVerticesAndIndicesFromModel(model, out vertices, out indices);

                                   //0.01 is half of my default collision margin
                                    for (int i = 0; i < vertices.Length; i++)                                                                            
                                        vertices[i] = Vector3.Transform(vertices[i], Matrix.CreateScale(1 - 0.01f) * 
                                            Matrix.CreateScale(ModelScale));
This works great for me, thank you for all of your help Norbo. :mrgreen:
Post Reply