Advertisement

Explosive tangent impulses causes extreme rotation

Started by June 17, 2014 08:51 PM
11 comments, last by Finalspace 10 years, 8 months ago

Hi there,

i got my html5/javascript 2D Sequential-Impulse based physics engine working - yay - but got issues with some weird behaviours :-(

It looks stable, but contacts creates explosive tangent impulses which increases the angular velocity.

Here are a video of some stacking circles which shows the weird effect (after forcing the collapse, the circles rotation goes faster and faster.

Another video showing the issue on a smaller scale:

I nearly use the same approach as box2d - except i added the position correction directly to the velocity bias. The friction code is identical and should be a direct port with one minor difference: i calculate the tangent normal once in the contact initialization - because the normal does not change for each contact/frame.

Source for contact solver + initialization:

http://pastebin.com/70pz2YXG

No idea what causing these problems. I also tried to use a static/dynamic friction method, but had some more worse effects.

Would be really great, if you can help me to identify the issue.

Thanks in regards,

Final

Looks like a wrong sign issue... maybe you can add debug visuals for the forces involved.

Advertisement

Should be able to compare your stuff with Box2D Lite.

I added simple contact force visualization which shows the final accumulated normal and tangent impulses.

See the following videos:

Should be able to compare your stuff with Box2D Lite.

I have already compared the solver stuff and have nearly an identical port now, but with some small differences:

box2d:

contact.velocityBias = this.baumGarte * dtInv * Math.min(0.0, contact.penetration + this.allowedPenetration);

my (added negative sign + penetration are switched):

contact.velocityBias = -this.baumGarte * dtInv * Math.min(0.0, -contact.penetration + this.allowedPenetration);

Maybe my contact generation is not correct? For this case, i also created a video to show the contact generation. I love creating videos :D

The circle-circle friction seems to be inverted. In the first video you can see, when the circle that gets pushed up falls onto the fast spinning circle, it starts to turn in the wrong direction,

After analyzing box2d lite again, i added normal visualization and as i suspected, all normals are always the correct surface normals from the surface.

In my case - sometimes its correct, sometimes its not and i has to do with my contact generation.

For example, a simple halfspace and circle contact is created in my system like this:

- Get the distance vector between any point on the halfspace (in my case this is the halfspaces center - because its defined as normal * -distance) and the position of the circle.

- Now make a vector projection on the planes collision normal against this distance vector and invert the result

- If this projection is greater than the radius - we create a contact, otherwise not

- Contact point is circle position + planes collision normal * negative projection.

- Penetration is circle radius - projection

- The result contact normal is the inverted plane collision normal (If i use the actual plane normal, the relative velocity projection fails in the solver and the circle falls through the plane. (Even with the basic impulse like this: j = -(1.0 + restitution) * velAlongNormal )

I am not sure, what i am doing wrong here.

I also double checked my broadphase system which do simply two for loops, the outer goes from zero to the body count. The inner goes from the outer + 1 to the body count - These should create unique pairs always - of course static vs static are skipped as well.

Secondly i run the actual contact generation function from a jump table based on the bodies shape type:


        function flipContacts(list, count) {
            if (count > 0) {
                for (var i = list.size()-1; i > list.size()-1-count; i--){
                    var contact = list.item(i);
                    math.vec2MultScalar(contact.normal, contact.normal, -1);
                    var tmp = contact.bodyA;
                    contact.bodyA = contact.bodyB;
                    contact.bodyB = tmp;
                }
            }
            return count;
        }

        function createContactCircleToHalfSpace(a, b, list) {
            var aDef = a.shape;
            var bDef = b.shape;

            var normal = bDef.normal;
            var pos = a.position;
            var pC = b.position;

            var sub = Vec2Pool.get();
            math.vec2Sub(sub, pC, pos);
            var proj = -math.vec2Dot(normal, sub);
            if (proj >= aDef.radius) {
                return 0;
            }

            var contact = list.add();
            contact.bodyA = a;
            contact.bodyB = b;
            contact.penetration = aDef.radius - proj;
            math.vec2MultScalar(contact.normal, normal, -1);
            math.vec2AddMultScalar(contact.contactPoint, pos, normal, -proj);
            return 1;
        }

        function createContactHalfSpaceToCircle(a, b, list) {
            return flipContacts(list, createContactCircleToHalfSpace(b, a, list));
        }

        var contactFunctions = [];

        function addContactFunction(typeA, typeB, func) {
            if (typeof contactFunctions[typeA] == "undefined") {
                contactFunctions[typeA] = [];
            }
            contactFunctions[typeA][typeB] = func;
        }

        addContactFunction(ShapeType.Circle,ShapeType.HalfSpace, createContactCircleToHalfSpace);
        addContactFunction(ShapeType.HalfSpace,ShapeType.Circle, createContactHalfSpaceToCircle);


As you can see, the createContactHalfSpaceToCircle method is called when, bodyA is a halfspace and bodyB is a circle (inverted implementation of createContactCircleToHalfSpace) - therefore i flip the generated contacts (bodyA is bodyB and vice versa + invert the contact normal)

Advertisement

k i think i need to start this from the beginning, therefore i made a really simple one-file javascript demo which shows 2 circles and a plane, with one iteration and accumulation disabled + no tangent impulses or rotations whatever. Seems to be working fine, but the contact normal for plane against circle is just wrong - i need to invert the plane normal as resulting contact normal - otherwise the circle falls through the plane. Why does this happens?

http://jsfiddle.net/6egN3/1/

i fixed the flipped plane normal issue - the plane needs to be always the first body, not the circle - the relative velocity was negative all the time.

But now the bodies sinks into each other over time - even its now a port of box2d lite with much simpler geometry.

Here you can see the sinking (Takes a while to take place):

http://jsfiddle.net/6egN3/2/

I recommend starting from Box2D *Lite*. Then you can start playing around from a working solution. Regarding the changes you made to Box2D I wonder what problem you try to solve and where you think your solution is better. I personally would only make such changes if it solves a particular problem while not breaking anything else.

Its just i want to learn how a physics engine really works (i have bought several books for this), what are the maths behind and understand it in a simple way, so that i can implement it myself. In the last couple of months i looked deep in the box2d and box2d lite source nearly every day, tried to understand and visualize it - if i can visualize something - i can implement it. In the last few years i got highly interested in creating physics simulations, therefore i have read tons of papers, several books, tutorials - to learn all the math/methods behind it and now i am in the process of creating things - of course my final goal is to create a game based on that. But i think you are right, i think i will port box2d lite to javascript (dont like the existing ports) and expand it to my needs.

This topic is closed to new replies.

Advertisement