MaximumSpeedConstraint crash (call stack included)

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
BrianL
Posts: 54
Joined: Wed Jun 25, 2008 4:41 pm
Location: Panama City Beach, FL

MaximumSpeedConstraint crash (call stack included)

Post by BrianL »

I'm using a MaximumSpeedConstraint in my scene. After a few seconds at high speed I can reliably get it to crash 100% of the time with the following call stack. The test is being run with a Box and StaticTriangleGroup with the Box as the moving Entity. Looks like some vectors are becoming invalid...possibly due to the constraint's interaction?

Code: Select all

mscorlib.dll!System.Math.Sign(float value = NaN) + 0x23 bytes	
BEPUphysics.dll!BEPUphysics.Box.getExtremePoint(ref Microsoft.Xna.Framework.Vector3 d = {X:-1 Y:0 Z:0}, float margin = 0.04, ref Microsoft.Xna.Framework.Vector3 linearVelocity = {X:NaN Y:NaN Z:NaN}, ref Microsoft.Xna.Framework.Vector3 backwardLinearVelocity = {X:NaN Y:NaN Z:NaN}) + 0x17 bytes	
BEPUphysics.dll!BEPUphysics.Entity.getExtremePoints(ref Microsoft.Xna.Framework.Vector3 d = {X:1 Y:0 Z:0}, out Microsoft.Xna.Framework.Vector3 min = {X:0 Y:0 Z:0}, out Microsoft.Xna.Framework.Vector3 max = {X:0 Y:0 Z:0}, float margin = 0.04, ref Microsoft.Xna.Framework.Vector3 linearVelocity = {X:NaN Y:NaN Z:NaN}, ref Microsoft.Xna.Framework.Vector3 backwardLinearVelocity = {X:NaN Y:NaN Z:NaN}) + 0x1b bytes	
BEPUphysics.dll!BEPUphysics.Entity.findBoundingBox(ref Microsoft.Xna.Framework.Vector3 linearVelocity = {X:NaN Y:NaN Z:NaN}, ref Microsoft.Xna.Framework.Vector3 backwardLinearVelocity = {X:NaN Y:NaN Z:NaN}) + 0x17 bytes	
BEPUphysics.dll!BEPUphysics.Space.update(float dt = 0.0166667, float timeSinceLastFrame = 0.0168094635) + 0x58a bytes	
BEPUphysics.dll!BEPUphysics.Space.update(Microsoft.Xna.Framework.GameTime gameTime = {Microsoft.Xna.Framework.GameTime}) + 0x42 bytes	
User avatar
Zukarakox
Not a Site Admin
Posts: 426
Joined: Mon Jul 10, 2006 4:28 am

Re: MaximumSpeedConstraint crash (call stack included)

Post by Zukarakox »

YOU BROKEEE ITTTT....
i has multiple toes
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: MaximumSpeedConstraint crash (call stack included)

Post by Norbo »

Could you create a little reproduction setup for this error?

My current theory as to why this might happen relates to the inertia tensor of the box; have you modified it at all, perhaps setting rows to zero or anything? The maximum speed constraint won't play well with that sort of thing. Other than that, there isn't really anything else obviously/directly related to the constraint that could cause NaN-spam.

That exception specifically is the result of a propagation of NaN's, and is generally the catch-all for annoying velocity bugs.
BrianL
Posts: 54
Joined: Wed Jun 25, 2008 4:41 pm
Location: Panama City Beach, FL

Re: MaximumSpeedConstraint crash (call stack included)

Post by BrianL »

No, I'm not setting anything related to the inertia tensor of the box. Simply calling Box.applyImpulse each frame to accelerate the cube. I was procedurally rotating the linearMomentum vector but have disabled all of that in an attempt to pinpoint a possible culprit. However, none of that has helped so far. At this point, I've reduced it to Box.applyImpulse calls and Box.rotate calls for the update loop. I did have the maximumAngularSpeed set to 0.0f on the MaximumSpeedConstraint, so I tried setting it to some positive value. Didn't help.

At this point it's kind of tough to put together a simple repro case for this aside from sending over the whole project as it currently exists. It's a 360 only project at the moment. Is it possible to run an exe built for the 360 on the 360 without Visual Studio? Or do you pretty much have to have the solution and source code and build locally and then deploy in order to debug?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: MaximumSpeedConstraint crash (call stack included)

Post by Norbo »

I am not 100% sure, but I think it would require the whole solution for deployment purposes.

Only thing I can think of is to check all of the velocities of the object after each apply impulse, and the orientation after each rotation. If all of them come out fine and yet it still explodes, I'll probably have to take a closer look. For those NaN's to pop up, there needs to be something nasty going on, and the only thing that I can see that could possibly cause them in the constraint is a matrix inversion, which apparently isn't the cause.
BrianL
Posts: 54
Joined: Wed Jun 25, 2008 4:41 pm
Location: Panama City Beach, FL

Re: MaximumSpeedConstraint crash (call stack included)

Post by BrianL »

Okay, I've got assertions checking just about every component of every vector or matrix (that I have access to) that can change at the Entity level...and nothing is getting hit. Here's the state of the cube at the time of the crash:

I see that some of the "my" and "previous" member variables are also NaN...

Code: Select all

-		m_Cube	{BEPUphysics.Box}	BEPUphysics.Box
-		base	{BEPUphysics.Box}	BEPUphysics.Entity {BEPUphysics.Box}
		allowedPenetration	0.025	float
		angularDamping	0.75	float
+		angularMomentum	{X:NaN Y:NaN Z:NaN}	Microsoft.Xna.Framework.Vector3
+		angularVelocity	{X:81.73529 Y:-97.50146 Z:5.956311}	Microsoft.Xna.Framework.Vector3
		bounciness	0.0	float
+		boundingBox	{Min:{X:-3.158347 Y:40.80492 Z:250.8726} Max:{X:5.326904 Y:49.29885 Z:255.7614}}	Microsoft.Xna.Framework.BoundingBox
+		centerPosition	{X:1.084278 Y:45.05188 Z:253.317}	Microsoft.Xna.Framework.Vector3
		collisionFilter	18446744073709551615	ulong
		collisionMargin	0.04	float
		compoundActivity	true	bool
+		compoundAngularMomentum	{X:NaN Y:NaN Z:NaN}	Microsoft.Xna.Framework.Vector3
+		compoundAngularVelocity	{X:NaN Y:NaN Z:NaN}	Microsoft.Xna.Framework.Vector3
		compoundBody	null	BEPUphysics.CompoundBody
+		compoundCorrectiveAngularVelocity	{X:0 Y:0 Z:0}	Microsoft.Xna.Framework.Vector3
+		compoundCorrectiveLinearVelocity	{X:0 Y:0 Z:0}	Microsoft.Xna.Framework.Vector3
+		compoundInertiaTensorInverse	{ {M11:0.02026436 M12:-0.001954478 M13:-0.0008725619 M14:0} {M21:-0.001954478 M22:0.01064112 M23:-0.001182511 M24:0} {M31:-0.000872562 M32:-0.001182512 M33:0.01140407 M34:0} {M41:0 M42:0 M43:0 M44:0.9999999} }	Microsoft.Xna.Framework.Matrix
+		compoundLinearMomentum	{X:1634.706 Y:-1950.029 Z:119.1262}	Microsoft.Xna.Framework.Vector3
+		compoundLinearVelocity	{X:81.73529 Y:-97.50146 Z:5.956311}	Microsoft.Xna.Framework.Vector3
		compoundMass	20.0	float
+		compoundOrientationQuaternion	{X:NaN Y:NaN Z:NaN W:NaN}	Microsoft.Xna.Framework.Quaternion
+		compoundPosition	{X:1.084278 Y:45.05188 Z:253.317}	Microsoft.Xna.Framework.Vector3
+		compoundRotationMatrix	{ {M11:NaN M12:NaN M13:NaN M14:0} {M21:NaN M22:NaN M23:NaN M24:0} {M31:NaN M32:NaN M33:NaN M34:0} {M41:0 M42:0 M43:0 M44:1} }	Microsoft.Xna.Framework.Matrix
+		constraints	{System.Collections.Generic.List<BEPUphysics.Constraint>}	System.Collections.Generic.List<BEPUphysics.Constraint>
+		controllers	{System.Collections.Generic.List<BEPUphysics.Controller>}	System.Collections.Generic.List<BEPUphysics.Controller>
+		correctiveAngularVelocity	{X:0 Y:0 Z:0}	Microsoft.Xna.Framework.Vector3
+		correctiveLinearVelocity	{X:0 Y:0 Z:0}	Microsoft.Xna.Framework.Vector3
		density	0.8333333	float
+		force	{X:54.90942 Y:18.10596 Z:-36.97366}	Microsoft.Xna.Framework.Vector3
+		forces	{System.Collections.Generic.List<BEPUphysics.Force>}	System.Collections.Generic.List<BEPUphysics.Force>
		framesBelowAngularVelocityThreshold	0	int
		framesBelowLinearVelocityThreshold	0	int
		friction	0.3	float
+		inertiaTensorInverse	{ {M11:0.02026436 M12:-0.001954478 M13:-0.0008725619 M14:0} {M21:-0.001954478 M22:0.01064112 M23:-0.001182511 M24:0} {M31:-0.000872562 M32:-0.001182512 M33:0.01140407 M34:0} {M41:0 M42:0 M43:0 M44:0.9999999} }	Microsoft.Xna.Framework.Matrix
		internalIterationFlag	0	byte
		isActive	true	bool
		isAffectedByGravity	true	bool
		isAlwaysActive	false	bool
		isDeactivationCandidate	false	bool
		isMemberOfRayCastableContainer	false	bool
		isPhysicallySimulated	true	bool
		isSubBodyOfCompound	false	bool
		isTangible	true	bool
		linearDamping	0.0	float
+		linearMomentum	{X:1634.706 Y:-1950.029 Z:119.1262}	Microsoft.Xna.Framework.Vector3
+		linearVelocity	{X:81.73529 Y:-97.50146 Z:5.956311}	Microsoft.Xna.Framework.Vector3
+		localInertiaTensor	{ {M11:81.66667 M12:0 M13:0 M14:0} {M21:0 M22:106.6667 M23:0 M24:0} {M31:0 M32:0 M33:48.33334 M34:0} {M41:0 M42:0 M43:0 M44:1} }	Microsoft.Xna.Framework.Matrix
+		localInertiaTensorInverse	{ {M11:0.0122449 M12:0 M13:0 M14:0} {M21:0 M22:0.009374999 M23:0 M24:0} {M31:0 M32:0 M33:0.02068965 M34:0} {M41:0 M42:0 M43:0 M44:0.9999999} }	Microsoft.Xna.Framework.Matrix
+		localSpaceInertiaTensor	{ {M11:81.66667 M12:0 M13:0 M14:0} {M21:0 M22:106.6667 M23:0 M24:0} {M31:0 M32:0 M33:48.33334 M34:0} {M41:0 M42:0 M43:0 M44:1} }	Microsoft.Xna.Framework.Matrix
		margin	0.04	float
		marginSquared	0.0016	float
		mass	20.0	float
+		myAngularVelocity	{X:NaN Y:NaN Z:NaN}	Microsoft.Xna.Framework.Vector3
+		myLinearVelocity	{X:81.73529 Y:-97.50146 Z:5.956311}	Microsoft.Xna.Framework.Vector3
+		mySpace	{BEPUphysics.Space}	BEPUphysics.Space
+		nonCollidableEntities	{System.Collections.Generic.List<BEPUphysics.Entity>}	System.Collections.Generic.List<BEPUphysics.Entity>
+		orientation	{X:NaN Y:NaN Z:NaN W:NaN}	Microsoft.Xna.Framework.Quaternion
+		orientationQuaternion	{X:NaN Y:NaN Z:NaN W:NaN}	Microsoft.Xna.Framework.Quaternion
+		position	{X:1.084278 Y:45.05188 Z:253.317}	Microsoft.Xna.Framework.Vector3
+		previousAngularMomentum	{X:NaN Y:NaN Z:NaN}	Microsoft.Xna.Framework.Vector3
+		previousLinearMomentum	{X:1634.706 Y:-1950.029 Z:119.1262}	Microsoft.Xna.Framework.Vector3
+		rotation	{ {M11:NaN M12:NaN M13:NaN M14:0} {M21:NaN M22:NaN M23:NaN M24:0} {M31:NaN M32:NaN M33:NaN M34:0} {M41:0 M42:0 M43:0 M44:1} }	Microsoft.Xna.Framework.Matrix
+		rotationMatrix	{ {M11:NaN M12:NaN M13:NaN M14:0} {M21:NaN M22:NaN M23:NaN M24:0} {M31:NaN M32:NaN M33:NaN M34:0} {M41:0 M42:0 M43:0 M44:1} }	Microsoft.Xna.Framework.Matrix
+		simulationIsland	{BEPUphysics.SimulationIsland}	BEPUphysics.SimulationIsland
+		space	{BEPUphysics.Space}	BEPUphysics.Space
		tag	null	object
+		torque	{X:NaN Y:NaN Z:NaN}	Microsoft.Xna.Framework.Vector3
+		totalForce	{X:54.90942 Y:18.10596 Z:-36.97366}	Microsoft.Xna.Framework.Vector3
+		totalTorque	{X:NaN Y:NaN Z:NaN}	Microsoft.Xna.Framework.Vector3
		useContinuousDetection	true	bool
		useOneShotManifolds	true	bool
		volume	24.0	float
		halfHeight	0.5	float
		halfLength	3.0	float
		halfWidth	2.0	float
		height	1.0	float
		length	6.0	float
		width	4.0	float
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: MaximumSpeedConstraint crash (call stack included)

Post by Norbo »

I managed to find the source; it was just an issue with the normalization of velocities eventually resulting in infinities due to the extremely small values involved (I probably should have noticed that sooner :P). Unfortunately this can't be fixed externally, but it's pretty simple and can work as an example of using the constraint framework so I'll go ahead and release the source code:

Code: Select all

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using System.Diagnostics;

namespace BEPUphysics
{
    /// <summary>
    /// Prevents the target entity from moving faster than the specified speeds.
    /// </summary>
    public class MaximumSpeedConstraint:SingleBodyConstraint
    {
        /// <summary>
        /// Maximum linear speed allowed.
        /// </summary>
        public float maximumLinearSpeed;
        /// <summary>
        /// Maximum angular speed allowed.
        /// </summary>
        public float maximumAngularSpeed;

        Vector3 linearVelocityDirection;
        Vector3 angularVelocityDirection;
        Matrix inertiaTensor;

        /// <summary>
        /// Constructs a maximum speed constraint.
        /// </summary>
        /// <param name="e">Entity to target.</param>
        /// <param name="maxLinearSpeed">Maximum linear speed allowed.</param>
        /// <param name="maxAngularSpeed">Maximum angular speed allowed.</param>
        public MaximumSpeedConstraint(Entity e, float maxLinearSpeed, float maxAngularSpeed)
        {
            entity = e;
            maximumLinearSpeed = maxLinearSpeed;
            maximumAngularSpeed = maxAngularSpeed;
        }

        /// <summary>
        /// Calculates necessary information for velocity solving.
        /// Called automatically by space.
        /// </summary>
        /// <param name="dt">Time in seconds since the last update.</param>
        public override void preStep(float dt)
        {
            float linearVelocityMagnitudeSquared = entity.linearVelocity.LengthSquared();
            if (linearVelocityMagnitudeSquared > 1E-40f)
                linearVelocityDirection = entity.linearVelocity / (float)Math.Sqrt(linearVelocityMagnitudeSquared);
            else
                linearVelocityDirection = Vector3.Zero;
            float angularVelocityMagnitudeSquared = entity.angularVelocity.LengthSquared();
            if (angularVelocityMagnitudeSquared > 1E-40f)
                angularVelocityDirection = entity.angularVelocity / (float)Math.Sqrt(angularVelocityMagnitudeSquared);
            else
                angularVelocityDirection = Vector3.Zero;

            inertiaTensor = Matrix.Invert(entity.inertiaTensorInverse);
        }
        /// <summary>
        /// Calculates and applies corrective impulses.
        /// Called automatically by space.
        /// </summary>
        /// <param name="dt">Time in seconds since the last update.</param>
        public override void applyImpulse(float dt)
        {
            float linearVelocity = Vector3.Dot(entity.myLinearVelocity, linearVelocityDirection);

            if (linearVelocity > maximumLinearSpeed)
            {
                float diff = maximumLinearSpeed - linearVelocity;
                Vector3 linearImpulse = (diff * entity.mass) * linearVelocityDirection;
                entity.linearMomentum += linearImpulse;
                entity.myLinearVelocity = entity.linearMomentum / entity.mass;
            }
            float angularVelocity = Vector3.Dot(entity.myAngularVelocity, angularVelocityDirection);
            if (angularVelocity > maximumAngularSpeed)
            {
                float diff = maximumAngularSpeed - angularVelocity;
                Vector3 angularImpulse = Vector3.Transform(diff * angularVelocityDirection, inertiaTensor);
                entity.angularMomentum += angularImpulse;
                entity.myAngularVelocity = Vector3.Transform(entity.angularMomentum, entity.inertiaTensorInverse);
            }
        }

    }
}
The above source is made available under the same permissive zlib-style license as the demos, which can be found at http://www.bepu-games.com/BEPUphysics/demoslicense.txt.
BrianL
Posts: 54
Joined: Wed Jun 25, 2008 4:41 pm
Location: Panama City Beach, FL

Re: MaximumSpeedConstraint crash (call stack included)

Post by BrianL »

Awesome. Thank you very much for taking the time to look through it and ultimately finding what the problem was/is.

Edit:

The following function doesn't have access to the "myLinearVelocity" and "myAngularVelocity" member variables, unless I'm just missing some silly C#-ism. I tried using just linearVelocity and angularVelocity instead, but the visual results are telling me that the two are not the same internally. :)

Code: Select all

public override void applyImpulse(float dt)
        {
            float linearVelocity = Vector3.Dot(entity.myLinearVelocity, linearVelocityDirection);

            if (linearVelocity > maximumLinearSpeed)
            {
                float diff = maximumLinearSpeed - linearVelocity;
                Vector3 linearImpulse = (diff * entity.mass) * linearVelocityDirection;
                entity.linearMomentum += linearImpulse;
                entity.myLinearVelocity = entity.linearMomentum / entity.mass;
            }
            float angularVelocity = Vector3.Dot(entity.myAngularVelocity, angularVelocityDirection);
            if (angularVelocity > maximumAngularSpeed)
            {
                float diff = maximumAngularSpeed - angularVelocity;
                Vector3 angularImpulse = Vector3.Transform(diff * angularVelocityDirection, inertiaTensor);
                entity.angularMomentum += angularImpulse;
                entity.myAngularVelocity = Vector3.Transform(entity.angularMomentum, entity.inertiaTensorInverse);
            }
        }
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: MaximumSpeedConstraint crash (call stack included)

Post by Norbo »

Sorry about that, forgot about the ridiculous bug I had fixed that causes the angularVelocity property to get the linearVelocity. Here's a workaround for the applyImpulse method, since setting the property still works in v0.5.2.

Code: Select all

        /// <summary>
        /// Calculates and applies corrective impulses.
        /// Called automatically by space.
        /// </summary>
        /// <param name="dt">Time in seconds since the last update.</param>
        public override void applyImpulse(float dt)
        {
            float linearVelocity = Vector3.Dot(entity.linearVelocity, linearVelocityDirection);

            if (linearVelocity > maximumLinearSpeed)
            {
                float diff = maximumLinearSpeed - linearVelocity;
                Vector3 linearImpulse = (diff * entity.mass) * linearVelocityDirection;
                entity.linearMomentum += linearImpulse;
                entity.linearVelocity = entity.linearMomentum / entity.mass;
            }

            float angularVelocity = Vector3.Dot(Vector3.Transform(entity.angularMomentum, entity.inertiaTensorInverse), angularVelocityDirection);
            if (angularVelocity > maximumAngularSpeed)
            {
                float diff = maximumAngularSpeed - angularVelocity;
                Vector3 angularImpulse = Vector3.Transform(diff * angularVelocityDirection, inertiaTensor);
                entity.angularVelocity = Vector3.Transform(Vector3.Transform(entity.angularMomentum + angularImpulse, entity.inertiaTensorInverse), entity.inertiaTensorInverse);
            }
        }
BrianL
Posts: 54
Joined: Wed Jun 25, 2008 4:41 pm
Location: Panama City Beach, FL

Re: MaximumSpeedConstraint crash (call stack included)

Post by BrianL »

Ha! Yeah, that's the behavior I was seeing. The angularVelocity was somehow ending up with the linearVelocity. LOL It's all good. Thanks for the workaround. I'll either try it tonight or in the morning and report back.
Norbo wrote:Sorry about that, forgot about the ridiculous bug I had fixed that causes the angularVelocity property to get the linearVelocity. Here's a workaround for the applyImpulse method, since setting the property still works in v0.5.2.
BrianL
Posts: 54
Joined: Wed Jun 25, 2008 4:41 pm
Location: Panama City Beach, FL

Re: MaximumSpeedConstraint crash (call stack included)

Post by BrianL »

So far so good on the fix. Thanks.
Post Reply