Sign in to follow this  
BrickInTheWall

This problem is creeping me out...

Recommended Posts

Hi everyone, I am working on the collision response for some basic moving poly vs. static poly collision engine. Once I detect a hit, I calculate a new velocity vector, based on the current velocity, the direction of the edge being hit, aswell as bounce and friction values. This all works really fine except when I turn bounce completely off. Setting friction to 1.0 (can only be between 0 and 1), means NO friction. Setting bounce to 0 (can only be between 0 and 1) means NO bounce. What I do is I calculate the components of the new velocity vector that are perpendicular and orthogonal to the edge being hit, and then multiply them by bounce and friction factors, and then add the two vectors together. This all works well, except when I set bounce to 0. Weird stuff starts to happen and the program eventually crashes. The reason for this crash is rather complicated and I've figured it out, but what I can't figure out is this: Take a look at my CalculateNewVelocity function (its simple vector maths):
Quote:
public static Vector2D CalculateNewVelocity(Vector2D currentVelocity, Vector2D minimumTranslationVector, double friction, double bounce)
        {
            Console.WriteLine("Now in CalculateNewVelocity. Start debug sequence...");

            // Create copies of the sent vectors.
            // The direction of the edge that is being hit is the normal of the MTV.
            Vector2D collisionEdge = new Vector2D();
            collisionEdge.X = -minimumTranslationVector.Y;
            collisionEdge.Y = minimumTranslationVector.X;
            Vector2D mtv = new Vector2D();
            mtv.X = minimumTranslationVector.X;
            mtv.Y = minimumTranslationVector.Y;

            Console.WriteLine("MTV: x = {0}, y = {1}", mtv.X, mtv.Y);

            Vector2D newVelocity;

            // First, get the angle between the two vectors (convert to radians).
            double dotProductResult = currentVelocity * collisionEdge;

            // If they are facing away from each other, the edge should face the same way
            // as the velocity, to make calculations easier.
            if (dotProductResult < 0)
                collisionEdge = collisionEdge * (-1);

            double angle = CalculateTheAngle(currentVelocity, collisionEdge);
            Console.WriteLine("Angle (in deg): {0}", angle);
            angle = angle * Math.PI / 180;
            Console.WriteLine("Angle (in rad): {0}", angle);

            // Get magnitudes of v components parallel and orthogonal to the collisionEdge.
            double vPar = currentVelocity.Length * Math.Cos(angle);
            double vOrth = currentVelocity.Length * Math.Sin(angle);
            Console.WriteLine("Magnitude of vPar = {0}", vPar);
            Console.WriteLine("Magnitude of vOrth = {0}", vOrth);

            // Calculate the component of the new vector that is parallel to the collisionEdge.
            // For this, use the normalized direction of the collisionEdge (should point the right way now).
            // The multiply be friction factor.
            collisionEdge.Normalize();
            Vector2D vNewPar = collisionEdge * vPar;
            vNewPar = vNewPar * friction;
            Console.WriteLine("vNewPar: x = {0}, y = {1}", vNewPar.X, vNewPar.Y);

            // Calculate the component of the new vector that is orthogonal to the collisionEdge.
            // For this, use the normalized MTV.
            // The multiply by bounce factor.
            mtv.Normalize();
            Vector2D vNewOrth = mtv * vOrth;
            vNewOrth = vNewOrth * bounce;
            Console.WriteLine("vNewOrth: x = {0}, y = {1}", vNewOrth.X, vNewOrth.Y);

            // Now simply add the two components.
            newVelocity = vNewPar + vNewOrth;

            return newVelocity;
        }
I put a bunch of console statements in there so I could trace what was going on. Basically, when frictiong is 0 (1.0 for the friction value) and bounce is 0, the tile should just slide along the surface of the static polygon. It does this for a really short time and then crashes. The result of the crash is linked to the fact, that the newVelocity vector eventually gets messed up (After 5 iterations I've figured out). Here is my main() code (not that important...all you need to know is I keep checking for collisions and calculating the newVelocity vector each time I get one. I get collisions even when its "sliding" along the surface).
Quote:
        static void Main(string[] args)
        {
            // Initialize the polygons.
            Polygon polygonA = new Polygon();
            polygonA.AddVector(new Vector2D(110, 100));
            polygonA.AddVector(new Vector2D(200, 120));
            polygonA.AddVector(new Vector2D(190, 150));
            polygonA.AddVector(new Vector2D(100, 130));

            Polygon polygonB = new Polygon();
            polygonB.AddVector(new Vector2D(210, 300));
            polygonB.AddVector(new Vector2D(300, 320));
            polygonB.AddVector(new Vector2D(290, 350));
            polygonB.AddVector(new Vector2D(200, 330));

            Vector2D velocity = new Vector2D(2, 4);

            Console.WriteLine("Friction = 1.0, Bounce = 0.0");
            double friction = 1.0;
            double bounce = 0.0;

            CollisionResult result = new CollisionResult();
            result = SeperatingAxisClass.TestCollision(polygonA, polygonB);

            while (!result.IsIntersecting)
            {
                polygonA += velocity;
                result = SeperatingAxisClass.TestCollision(polygonA, polygonB);
            }

            Console.WriteLine("Current center of polygonA: x = {0}, y = {1}", polygonA.Center.X, polygonA.Center.Y);
            velocity = CalculateNewVelocity(velocity, result.MinimumTranslationVector, friction, bounce);
            Console.WriteLine("New velocity vector: x = {0}, y = {1}", velocity.X, velocity.Y);

            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine();
                Console.WriteLine("Moving polygonA by velocity vector and checking for hit...");
                polygonA += velocity;
                result = SeperatingAxisClass.TestCollision(polygonA, polygonB);
                if (result.IsIntersecting)
                {
                    Console.WriteLine("Calculating new velocity vector...should be the same.");
                    velocity = CalculateNewVelocity(velocity, result.MinimumTranslationVector, friction, bounce);
                    Console.WriteLine("New velocity vector: x = {0}, y = {1}", velocity.X, velocity.Y);
                }

                Console.WriteLine("Iteration: {0}", i);
            }

            Console.ReadKey();
        }
I traced the values in the CalculateNewVelocity function and noticed it all messes up on the 5th iteration. Infact, right when the new angle is calculated. Here is my output: http://i28.tinypic.com/2uii2pj.jpg So I noticed the angle is already n. def. so I checked the function I use to calculate the angle, and this is the important part:
Quote:
public static double CalculateTheAngle(Vector2D vectA, Vector2D vectB)
        {
            double angleDeg;
            double angleRad;
            double x = (vectA * vectB) / (vectA.Length * vectB.Length);

            Console.WriteLine("   Now in CalculateTheAngle function...");

            // Make positive
            if (x < 0)
                x = x * (-1);

            Console.WriteLine("   x which will be passed to cosine: x = {0}", x);

            angleRad = Math.Acos(x);
            Console.WriteLine("   angleRad = {0}", angleRad);
            angleDeg = (angleRad * 180) / Math.PI;
            Console.WriteLine("   angleDeg = {0}", angleDeg);
            Console.WriteLine("   Returning back to CalculateNewVelocity function...");

            return angleDeg;
        }
As you can see, I put some Console statements in there too and noticed that the line "angleRad = Math.Acos(x);" (bold in the code) returns n. def. eventhough the value passed to it (x) is 1...as you can see in the picture with my output code. To make along story short, why does this arc cos function fail to return a valid value? x is not greater or smaller than 1...so it should work. Is this a problem in my floating point arithmetic? Will checking to see if x > 1 and setting it to 1 if it is, solve the problem in the best manner? Any help would be great, Chris

Share this post


Link to post
Share on other sites
I'm not entirely sure what funny stuff is going on and I'm not sure at the moment what to say about your arccos function. I will say, however, that setting bounce to zero is going to yield funny results unless you have calculated a normal force to keep your box from falling through the ground. By funny results, I mean the box will eventually just sink through the ground since you will have a velocity accumulation due to gravity. I realize that this does not seem like the solution to your problem, but see what happens if you at least rig up some kind of force that will balance gravity when the dynamic body hits the ground.

Share this post


Link to post
Share on other sites
I think your dot product calculation in CalculateTheAngle is not quite right. It should be

double x = vectA.normalize() * vectB.normalize();


I assume this is C#, which I'm not very familiar with, but is it possible that the double x is being converted (truncated) to an int when writing to the console? If x is really something like 1.000000000001, then that would cause the acos function to return NaN. I think you definitely should clip the x value to 1.0 to be safe.

Share this post


Link to post
Share on other sites
Quote:
Original post by thepog
I'm not entirely sure what funny stuff is going on and I'm not sure at the moment what to say about your arccos function. I will say, however, that setting bounce to zero is going to yield funny results unless you have calculated a normal force to keep your box from falling through the ground. By funny results, I mean the box will eventually just sink through the ground since you will have a velocity accumulation due to gravity. I realize that this does not seem like the solution to your problem, but see what happens if you at least rig up some kind of force that will balance gravity when the dynamic body hits the ground.

Yes it's a general rule, that is almost always missed, that the object has to be moved out of the collision during the response (has to be done as precisely as possible), setting forces/speeds is not enough.
It produces sinking/shaking/throwing of the colliding objects.

Share this post


Link to post
Share on other sites
Thanks for the help so far guys. Some of the decimals are probably being truncated when output to the console. Why would I have to normalize both vectors though? Should work without.

Anyways, I'm glad you guys also mentioned the problem of gravity which I could also use some help on. I was thinking about it while trying to sleep and noticed that if its sliding along the surface and I keep incrementing the y component of the speed vector, that it will eventually fall through since it will be projected out to the other side.
I haven't implemented any gravity yet as I just finished collision detection and it works great. Quite honestly I haven't thought about it a lot yet. What I was thinking of doing is calculating the vector that is added due to gravity while it is sliding there in a different way. I thought I could just project the gravity vector onto the direction vector of the edge being hit. So if I do:
gravityVector * directionVector(normalized) and then calculate the vector I need to add.
Can anyone give me any tips on how to best implement gravity while being causious to all that stuff that can go wrong? It might be a good idea to just leave this "bounce = 0" case away for now and work on this more important issue.

Thanks,
Chris

Share this post


Link to post
Share on other sites
I've made an image to display better what I am doing and how I plan on handeling gravity with a bounce of 0.
I haven't ever worked with gravity like here so I need some tips on how to implement it, what to watch out for, or just the standard way it is done. Here is the image:

http://i32.tinypic.com/4iisg3.png

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this