Prevent Entities From Entering Each Other

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
mcmonkey
Posts: 92
Joined: Fri Apr 17, 2015 11:42 pm

Prevent Entities From Entering Each Other

Post by mcmonkey »

Is there any way to ensure entities will never enter each other, even partially?
Generally it's not a problem, but sometimes I get some weird results, EG today a box landed as shown below after a tumbling fall
Image
If you can't tell from the image, it's partially inside the ground and rotated unreasonably.
Bumping it around failed to knock it into a more sane orientation.
While attempting to replicate it, I accomplished this:
Image
It's literally lying on an edge rather than falling flat.

I had to bounce it off a wall to reorient it.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Prevent Entities From Entering Each Other

Post by Norbo »

While continuous collision detection is supported, it cannot stop all penetration and it would probably not help with this issue.

Assuming the graphics match the physical shape, it looks like the simulation is tuned for a much larger scale than is being used. Here's a few ways which this type of problem can manifest:
1) The default value of CollisionDetectionSettings.AllowedPenetration is .01. If that box's width is around 0.01-0.04, then the contact depths will be so small relative to the default threshold that the penetration will be left mostly uncorrected.
2) CollisionDetectionSettings.DefaultMargin is 0.04. Shapes with internal margins like Boxes and Cylinders smaller than 2 * collisionMargin can cause odd behavior since some collision routines will view them as inverted, and even if they aren't inverted, a high margin will make the shapes very round. (Note that the collision margin can be set on a per-shape basis.)
3) Overly large contact invalidation thresholds may let old contacts stick around, providing support when they should not.

The default tuning expects a simulation with individual object sizes of around 0.5 to 10 units, and a gravity around -10. If units are interpreted as meters and seconds, this would be around the usual scale for characters and interactive objects in a human-sized FPS. If your objects are much smaller than this or your gravity is much higher relative to the size, try using something like the BEPUphysicsDemos ConfigurationHelper.ApplyScale to adjust all of the tuning factors to match.
mcmonkey
Posts: 92
Joined: Fri Apr 17, 2015 11:42 pm

Re: Prevent Entities From Entering Each Other

Post by mcmonkey »

I did actually assume 1 unit = 1 meter. That box is 1x1x1.

However,

Code: Select all

            CollisionDetectionSettings.AllowedPenetration = 0.001f;
and now I can't replicate it at all :D

In addition, my character is no longer inside the floor. I never bothered posting about that as Bullet had me used to it, but it's nice to see my character at 1.001 rather that 0.999

Of course, forcing an object powerfully into another yields some degree of penetration significantly higher than 0.001 units... but as long as it doesn't go through anything ever, I'm quite happy :)

I must say, I'm not regretting the conversion from Bullet to BEPU at all. No more fall-through, more in-depth configuration, very quick and helpful support responses, no arbitrary slowdowns ... (there are of course some hitches like the lack of per-entity gravity and all, but still)

Thanks for providing such an amazing system!
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Prevent Entities From Entering Each Other

Post by Norbo »

I did actually assume 1 unit = 1 meter. That box is 1x1x1.

However,

Code: Select all

            CollisionDetectionSettings.AllowedPenetration = 0.001f;
and now I can't replicate it at all
That is unusual; 0.01 should not cause any issue at all on a 1x1x1 box, and if there was a problem, moving to 0.001 should not fix it. Beware, I don't think the problem is actually fixed :P

Is the box actually a MobileMesh? Is there anything else odd about the simulation, like extreme gravity? If not, could you try reproducing the issue in the latest BEPUphysicsDemos for me to look at?
Thanks for providing such an amazing system!
Glad it's working for you!
mcmonkey
Posts: 92
Joined: Fri Apr 17, 2015 11:42 pm

Re: Prevent Entities From Entering Each Other

Post by mcmonkey »

Welp... you're right, that didn't fix it. It just made it less common if anything at all.

The box is a box prefab. Gravity is 0,0,-9.8

Trying to replicate on the demos now...

Actually, the physics going on in the demo just looks straight... different from what I see in my creation.

Am I perhaps rendering something wrong?

I'm using OpenTK.

Code: Select all

        public OpenTK.Matrix4 GetTransformationMatrix()
        {
            Matrix mat = Body.WorldTransform;
            return new OpenTK.Matrix4(mat.M11, mat.M12, mat.M13, mat.M14, mat.M21, mat.M22, mat.M23,
                mat.M24, mat.M31, mat.M32, mat.M33, mat.M34, mat.M41, mat.M42, mat.M43, mat.M44);
        }
"Body" is the BEPU entity. Named Body because it was originally a Bullet RigidBody.

Code: Select all

        public override void Render()
        {
            Matrix4 mat = Matrix4.CreateScale((float)HalfSize.X, (float)HalfSize.Y, (float)HalfSize.Z) * GetTransformationMatrix();
            GL.UniformMatrix4(2, false, ref mat);
            TheClient.Rendering.SetMinimumLight(0.0f);
            for (int i = 0; i < VBOs.Count; i++)
            {
                VBOs[i].Render(true); // TODO: TheClient.RenderTextures
            }
        }
The VBOs definitely render a cube from (-1,-1,-1) to (1,1,1)
The GL.UniformMatrix4 call sends the matrix as the Model matrix in the shader I use for rendering.
In the shader it's used like so:

Code: Select all


	gl_Position = proj_matrix * mv_matrix * position;
Where proj_matrix is a known-to-be-accurate left-hand (EDIT: actually, is it left handed? I'm not sure) projection/view matrix, and mv_matrix is the uploaded above.

This seems solid to me, but I get all sorts of weird bits of physics - the opening post lists ones, I've seen entities rotating backwards, ... I ... I don't know what I could be doing wrong D:
It's something somewhere on my end, otherwise the demos would have the same problem... but I don't have any idea where to start looking.
Perhaps a BEPUutilities matrix doesn't perfectly correspond to an OpenTK matrix? (EG Left-Hand vs. Right-Hand)? (I don't know too much about matrices, I just know how to use them for rendering tricks, and how to extract basic information from them)

EDIT: Tried to open the demo source code in Visual Studio 2013 Community, got an error: https://i.imgur.com/VlySMjE.png
EDIT2: Helps if I download XNA, doesn't it?
EDIT3: Nope, have XNA, still the same error
EDIT4: Ooh, C# 2010 can open it though
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Prevent Entities From Entering Each Other

Post by Norbo »

The symptoms sound a bit like the orientation is effectively inverted at some point during the graphical preparation. This would be very easy to accidentally introduce- the inverse of a rotation matrix is the transpose of that rotation matrix.

I suspect a mismatch in notation. The BEPUphysics matrix follows XNA conventions, assuming that:
resultRowVector = inputRowVector * bepuTransform

So, for example, if the transform was the world transform of an entity and inputRowVector represented the model space position of a vertex, then resultRowVector would be the world space position of the vertex.

If you use the opposite convention:
resultColumnVector = bepuTransform * inputColumnVector
without adapting the transform to match the convention, then resultColumnVector will not contain the same series of values as resultRowVector above.

From the fact that transpose(A * B) = transpose(B) * transpose(A), you can see the relationship between the two conventions.
resultRowVector = inputRowVector * bepuTransform = transpose(resultColumnVector) = transpose(inputColumnVector) * transpose(bepuTransform)

This choice of convention affects the multiplication order of matrices as well.

So, try transposing the matrix provided by BEPUphysics before using it in operations using the other convention.

Here's a decent article that works through some of the common confusion:
http://seanmiddleditch.com/matrices-han ... notations/
mcmonkey
Posts: 92
Joined: Fri Apr 17, 2015 11:42 pm

Re: Prevent Entities From Entering Each Other

Post by mcmonkey »

Neither .transpose() nor .inverted() (OpenTK method) return anything remote useable. Invert puts everything backwards, transpose produces... I'm not sure what, just everything is way off.
Switching columns/rows around manually also produces pure nonsense.

Code: Select all

           Matrix4 mat = GetTransformationMatrix() * Matrix4.CreateScale((float)HalfSize.X, (float)HalfSize.Y, (float)HalfSize.Z);
is also nonsense.

If it helps, here's a quick .gif of what's going on (in a test environment):

Image

UPDATE:
Cheating a bit, I changed my render code to

Code: Select all

        public override void Render()
        {
            Location loc = GetAngles();
            Matrix4 mat = Matrix4.CreateScale((float)HalfSize.X, (float)HalfSize.Y, (float)HalfSize.Z)
                * Matrix4.CreateRotationX((float)(loc.X * Utilities.PI180))
                * Matrix4.CreateRotationY((float)(loc.Y * Utilities.PI180))
                * Matrix4.CreateRotationZ((float)(loc.Z * Utilities.PI180))
                * Matrix4.CreateTranslation(GetPosition().ToOVector());
            GL.UniformMatrix4(2, false, ref mat);
            TheClient.Rendering.SetMinimumLight(0.0f);
            for (int i = 0; i < VBOs.Count; i++)
            {
                VBOs[i].Render(true); // TODO: TheClient.RenderTextures
            }
        }
with

Code: Select all

        public virtual Location GetAngles()
        {
            if (Body != null)
            {
                WorldTransform = Body.WorldTransform;
            }
            Location rot;
            rot.X = Math.Atan2(WorldTransform.M32, WorldTransform.M33) * 180 / Math.PI;
            rot.Y = -Math.Asin(WorldTransform.M31) * 180 / Math.PI;
            rot.Z = Math.Atan2(WorldTransform.M21, WorldTransform.M11) * 180 / Math.PI;
            return rot;
        }
and now it renders as expected... however, this is a /lot/ of math for every last entity to run every single frame and I would very much like to avoid it.

With the above, is there any hints as to why boxes might be rotating backwards?


EDIT: This code is entirely unoptimized, pay no mind to the pointless switching between degrees/radians. That getangles is used for stuff that takes degrees >.>

EDIT: Also, can't replicate entities landing on their edge in this rendering code, so that was probably a matrix issue as well...
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Prevent Entities From Entering Each Other

Post by Norbo »

Still looks a lot like the orientation taken from BEPUphysics is effectively transposed (either directly, or by use in multiplication). The fact that simply reinterpreting the orientation helped is also partially evidence for this.
mcmonkey
Posts: 92
Joined: Fri Apr 17, 2015 11:42 pm

Re: Prevent Entities From Entering Each Other

Post by mcmonkey »

When I just do mat.transpose();
I get this:
Image

There's no way it's just a transpose. I don't have the slightest clue what's going on or what to do about it.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Prevent Entities From Entering Each Other

Post by Norbo »

That looks like a lot more than just orientation was transposed.

Try taking the entity.Orientation (the quaternion property) and the entity.Position separately. Entity.WorldTransform is derived from these properties anyway. Convert them each to OpenTK types, and then build your world transform using them. If orientation still appears reversed, conjugate the orientation quaternion before building the transform.
mcmonkey
Posts: 92
Joined: Fri Apr 17, 2015 11:42 pm

Re: Prevent Entities From Entering Each Other

Post by mcmonkey »

Okay so

Code: Select all

        public OpenTK.Matrix4 GetOrientationMatrix()
        {
            Matrix3x3 omat = Body.OrientationMatrix;
            omat.Transpose();
            Matrix mat = Matrix3x3.ToMatrix4X4(omat);
            return new OpenTK.Matrix4(mat.M11, mat.M12, mat.M13, mat.M14, mat.M21, mat.M22,
                mat.M23, mat.M24, mat.M31, mat.M32, mat.M33, mat.M34, mat.M41, mat.M42, mat.M43, mat.M44);
        }
alongside

Code: Select all

            Matrix4 mat = (Matrix4.CreateScale((float)HalfSize.X, (float)HalfSize.Y, (float)HalfSize.Z) * GetOrientationMatrix() * Matrix4.CreateTranslation(GetPosition().ToOVector()));
Works... but now I wonder, /why/ does that work. Why is the orientation transposed? Why does this create issues in my OpenTK environment but not in the demos?

I'm not sure, and I'm sorry if I'm making a baseless accusation here, but it looks like the demos don't even use the transformation matrices... and the matrices returned by BEPU are just transposed as some side effect of being set incorrectly.
I say this because I know Bullet relies on valid world transforms, and theirs works perfectly in my rendering code - which is, of course, very simple straightforward code that it's hard to mess up.

Your code for it is

Code: Select all

            float qX2 = quaternion.X + quaternion.X;
            float qY2 = quaternion.Y + quaternion.Y;
            float qZ2 = quaternion.Z + quaternion.Z;
            float XX = qX2 * quaternion.X;
            float YY = qY2 * quaternion.Y;
            float ZZ = qZ2 * quaternion.Z;
            float XY = qX2 * quaternion.Y;
            float XZ = qX2 * quaternion.Z;
            float XW = qX2 * quaternion.W;
            float YZ = qY2 * quaternion.Z;
            float YW = qY2 * quaternion.W;
            float ZW = qZ2 * quaternion.W;

            result.M11 = 1 - YY - ZZ;
            result.M21 = XY - ZW;
            result.M31 = XZ + YW;

            result.M12 = XY + ZW;
            result.M22 = 1 - XX - ZZ;
            result.M32 = YZ - XW;

            result.M13 = XZ - YW;
            result.M23 = YZ + XW;
            result.M33 = 1 - XX - YY;
Which doesn't quite match up with http://www.euclideanspace.com/maths/geo ... nToMatrix/ if I'm reading it correctly.
(To be fair, I feel like I'm going blind trying to match things up... but it looks like a few bits are reversed I think maybe possibly)

I hate to make a post like this, particularly if I turn out to be wrong, but is it possible you're converting from Quaternions to Matrices wrong in BEPU's code?

It has to be that part alone, because the translation and all that is done correctly.

It's not like we're using two different matrix orders... it looks more like BEPU is doing that with itself internally :/
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Prevent Entities From Entering Each Other

Post by Norbo »

The BEPUutilities math types were built as a drop-in replacement for the XNA math types. The results from the Microsoft.Xna.Framework.Matrix.CreateFromQuaternion and BEPUutilities.Matrix(3x3).CreateFromQuaternion (and pretty much everything else) are the same.

In fact, OpenTK seems to use the same conventions as XNA did. For example, OpenTK.Matrix3.CreateFromQuaternion produces the same result as BEPUutilities.Matrix3x3.CreateFromQuaternion. That shader snippet you posted earlier, however, uses column vectors with post multiply. While that can be okay depending on the uploaded data layout and interpretation, it does require some care.

Bullet physics appears to use the opposite convention (column vectors with post multiply), which may explain why the problem is new. Is there any part of the application that might have partially compensated for the convention mismatch with Bullet, which is now redundant and producing incorrect results? Other than that, I can't be much help other than to say it's probably not an inconsistency in the engine.
Why does this create issues in my OpenTK environment but not in the demos?

I'm not sure, and I'm sorry if I'm making a baseless accusation here, but it looks like the demos don't even use the transformation matrices...
The BEPUphysicsDemos don't suffer any issues because everything, from physics to graphics, uses the same conventions. While it's true that the BEPUphysicsDrawer builds world transforms itself from interpolated states rather than raw states and so bypasses the Entity.WorldTransform property, it does mathematically exactly the same thing that the Entity.WorldTransform property does internally. This can be demonstrated by changing the DisplayEntityCollidable.Update function to just directly set the WorldTransform = MathConverter.Convert(DisplayedObject.Entity.WorldTransform).
Post Reply