Not logged in, Join Here! or Log In Below:  
 
News Articles Search    
 

 Home / Game Design & Programming / Angular Constraints in Verlet (2D) Account Manager
 
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.
 
arctwelve

January 25, 2005, 01:21 PM

Has anyone modeled angular constraints in Verlet with the same stability as stick constraints? It seems like angular constraints are prone to a lot of instability, if they are resolved in the same way as sticks -- that is, if the angle is not correct between AB and BC then set it to the correct angle by moving A and C each half the total distance between the current angle and the required angle.

When angular constraints are stressed they seem to generate a lot of extra energy. This is helped a bit by softening them, but to some degree the problem persists.

Another problem is leverage is not modeled correctly -- e.g., angle ABC with AB length of 10 and BC length of 100, constrainted to say Math.PI / 2, and with particle B 'pinned' in place. BC will not be 'pulled down' lower due to gravity. In fact, the opposite seems to occur.

Below is my code. Forgive the homebrewed the trig there -- Im sure it could be tightened up. I used an additional reference line to get angles, which is probably not necessary.

Also, what is the correct way to add inverse mass values to the resolution?

  1.  
  2. AngularConstraint.prototype.resolve = function() {
  3.        
  4.    // make sure the reference line position gets updated
  5.    // lineC is pBpD
  6.    this.lineC.p2.x = this.lineC.p1.x + 0;
  7.    this.lineC.p2.y = this.lineC.p1.y - 1;
  8.        
  9.    abRadius = this.pA.distance(this.pB);
  10.    bcRadius = this.pB.distance(this.pC);
  11.                        
  12.    thetaABC = this.calcTheta(this.pA, this.pB, this.pC);
  13.    thetaABD = this.calcTheta(this.pA, this.pB, this.pD);
  14.    thetaCBD = this.calcTheta(this.pC, this.pB, this.pD);
  15.        
  16.    halfTheta = (this.targetTheta - thetaABC) / 2;
  17.    paTheta = thetaABD + halfTheta * this.coeffStiff;
  18.    pcTheta = thetaCBD - halfTheta * this.coeffStiff;
  19.        
  20.    this.pA.x = abRadius * Math.sin(paTheta) + this.pB.x;
  21.    this.pA.y = abRadius * Math.cos(paTheta) + this.pB.y;
  22.    this.pC.x = bcRadius * Math.sin(pcTheta) + this.pB.x;
  23.    this.pC.y = bcRadius * Math.cos(pcTheta) + this.pB.y;
  24. }
  25.  
  26.  
  27. AngularConstraint.prototype.calcTheta = function(pa, pb, pc) {
  28.        
  29.    AB = new Vector(pb.x - pa.x, pb.y - pa.y);
  30.    BC = new Vector(pc.x - pb.x, pc.y - pb.y);
  31.                
  32.    dotProd = AB.dot(BC);
  33.    crossProd = AB.cross(BC);
  34.    return Math.atan2(crossProd, dotProd);
  35. }
  36.  


 
arctwelve

January 26, 2005, 03:44 PM

Well, after some investigation I think answered my own question, except for the leverage problem. The solution is to not only set the constraint to its correct angle, but also to center it based on its pre angle corrected center. In other words you store the center of ABC before you do the angle correction. After the angle is corrected, find its new center and then move that to the old center location. This moves all 3 particles of the constraint, not 2, and doesn't introduce unnatural energy into the system.

You can do this with the centroid version of a triangles center, which is just averaging the center point:

  1.  
  2. AngularConstraint.prototype.resolve = function() {
  3.        
  4.    center = this.getCentroid();
  5.    // make sure the reference line position gets updated
  6.    this.lineC.p2.x = this.lineC.p1.x + 0;
  7.    this.lineC.p2.y = this.lineC.p1.y - 1;
  8.        
  9.    abRadius = this.pA.distance(this.pB);
  10.    bcRadius = this.pB.distance(this.pC);
  11.                        
  12.    thetaABC = this.calcTheta(this.pA, this.pB, this.pC);
  13.    thetaABD = this.calcTheta(this.pA, this.pB, this.pD);
  14.    thetaCBD = this.calcTheta(this.pC, this.pB, this.pD);
  15.        
  16.    halfTheta = (this.targetTheta - thetaABC) / 2;
  17.    paTheta = thetaABD + halfTheta * this.coeffStiff;
  18.    pcTheta = thetaCBD - halfTheta * this.coeffStiff;
  19.        
  20.    this.pA.x = abRadius * Math.sin(paTheta) + this.pB.x;
  21.    this.pA.y = abRadius * Math.cos(paTheta) + this.pB.y;
  22.    this.pC.x = bcRadius * Math.sin(pcTheta) + this.pB.x;
  23.    this.pC.y = bcRadius * Math.cos(pcTheta) + this.pB.y;
  24.        
  25.    // move corrected angle to pre corrected center
  26.    newCenter = this.getCentroid();
  27.    dfx = newCenter.x - center.x;
  28.    dfy = newCenter.y - center.y;
  29.        
  30.    this.pA.x -= dfx;
  31.    this.pA.y -= dfy;
  32.    this.pB.x -= dfx;  
  33.    this.pB.y -= dfy;
  34.    this.pC.x -= dfx;  
  35.    this.pC.y -= dfy;
  36. }
  37. AngularConstraint.prototype.getCentroid = function() {
  38.    avgX = (this.pA.x + this.pB.x + this.pC.x) / 3;
  39.    avgY = (this.pA.y + this.pB.y + this.pC.y) / 3;
  40.    return new Vector(avgX, avgY);
  41. }
  42.  


If anyone knows how to add particle mass to the above code, please let me know.

 
Reedbeta

January 26, 2005, 07:52 PM

"if the angle is not correct between AB and BC then set it to the correct angle by moving A and C each half the total distance between the current angle and the required angle."

You can introduce particle masses into this by altering the fraction of movement - instead of splitting the correction equally between A and C, split it proportional to their inverse masses, so that an infinite-mass particle (invmass = 0) gets no movement at all, and the less massive a particle, the more movement it gets.

 
Danny Chapman

January 27, 2005, 02:30 AM

In fact, if you use particle masses somewhere, I think you'll have to use them everywhere - it's important that when resolving "internal" constraint violations you don't introduce momentum/angular momentum to the system as a whole.

 
arctwelve

January 27, 2005, 10:32 AM

Good point. Verlet behaves very nicely until you break this rule.

 
arctwelve

January 27, 2005, 10:43 AM


Looking at the psuedo-code in Jakobsen's article on Verlet he has:

  1.  
  2. delta = x2-x1;
  3. deltalength = sqrt(delta*delta);
  4. diff = (deltalength - restlength) / deltalength * (invmass1 + invmass2));
  5. x1 -= invmass1 * delta * diff;
  6. x2 += invmass2 * delta * diff;
  7.  


It should be possible to apply something similar to angular constraints (as you suggest). Although it may be difficult with the method I worked out since the first step solves the angle, and the second step corrects the displacement. The masses of all particles need to be considered, the question is -- how? Particles A and C can have their masses applied in the angle correction, but what to do with B in the displacement correction.

Verlet's stability depends on proper resolution of constraints.

 
This thread contains 6 messages.
 
 
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.