Jump to content

  • Log In with Google      Sign In   
  • Create Account

Explosive tangent impulses causes extreme rotation

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
12 replies to this topic

#1 Finalspace   Members   -  Reputation: 675


Posted 17 June 2014 - 02:51 PM

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:



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,


#2 Madhed   Crossbones+   -  Reputation: 4089


Posted 18 June 2014 - 08:49 AM

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

#3 Randy Gaul   Members   -  Reputation: 2066


Posted 18 June 2014 - 12:19 PM

Should be able to compare your stuff with Box2D Lite.

#4 Finalspace   Members   -  Reputation: 675


Posted 18 June 2014 - 01:00 PM

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:



                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

#5 Madhed   Crossbones+   -  Reputation: 4089


Posted 18 June 2014 - 01:23 PM

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,

#6 Finalspace   Members   -  Reputation: 675


Posted 18 June 2014 - 04:22 PM

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)

Edited by Finalspace, 18 June 2014 - 04:27 PM.

#7 Finalspace   Members   -  Reputation: 675


Posted 19 June 2014 - 02:55 AM

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?



Edited by Finalspace, 19 June 2014 - 02:56 AM.

#8 Finalspace   Members   -  Reputation: 675


Posted 19 June 2014 - 04:45 AM

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):


Edited by Finalspace, 19 June 2014 - 06:02 AM.

#9 Dirk Gregorius   Members   -  Reputation: 2011


Posted 19 June 2014 - 10:30 AM

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.

#10 Finalspace   Members   -  Reputation: 675


Posted 19 June 2014 - 12:29 PM

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.

#11 ferrous   Members   -  Reputation: 4834


Posted 19 June 2014 - 02:00 PM

Don't get too discouraged, if you are doing it for the purposes of learning a physics engine, I think the current path you are heading down is completely fine, and a little frustration and debugging are normal and part of the process.


On the other hand, if your desire is to just get the game part started, then I'd probably just expand box2d lite.

#12 Finalspace   Members   -  Reputation: 675


Posted 20 June 2014 - 01:08 AM

Oh it seems i fixed it. The relative velocity for angular rotation was incorrect - now it works :-)


Original box2d lite:


// Relative velocity at contact
dv = b2->velocity + Cross(b2->angularVelocity, c->r2) - b1->velocity - Cross(b1->angularVelocity, c->r1);
my old impl:
                    var tempVec = Vec2Pool.get();
                    var rva = Vec2Pool.get();
                    var rvb = Vec2Pool.get();
                    math.vec2CrossSV(tempVec, bodyA.angularVelocity, contact.rA);
                    math.vec2Add(rva, bodyA.velocity, tempVec);
                    math.vec2CrossSV(tempVec, bodyB.angularVelocity, contact.rB);
                    math.vec2Sub(rvb, bodyB.velocity, tempVec);
                    math.vec2Sub(relVelocity, rvb, rva);
new working impl:
                    var tmp = Vec2Pool.get();
                    math.vec2CrossSV(tmp, bodyB.angularVelocity, contact.rB);
                    math.vec2Add(relVelocity, bodyB.velocity, tmp);
                    math.vec2Sub(relVelocity, relVelocity, bodyA.velocity);
                    math.vec2CrossSV(tmp, bodyA.angularVelocity, contact.rA);
                    math.vec2Sub(relVelocity, relVelocity, tmp);
Javascript does not support operator overload - therefore i needed to make this ugly code -.-

#13 Finalspace   Members   -  Reputation: 675


Posted 20 June 2014 - 01:26 AM

Ah i am really happy right now, now i can go to the next step, implement contact caching + warm starting, better broadphase and finally polygon bodies.

If you want to see my progress, you can check my youtube channel frequently - i upload there things i have made - but mostly in javascript tongue.png


Thread can be closed.

Edited by Finalspace, 21 June 2014 - 01:10 AM.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.