Game Development Reference

In-Depth Information

As with Jakobsen, we solve the constraints directly by projecting the vertices

to positions that satisfy the constraints. To satisfy the constraint, the distance

between the vertices must be the same as it was initially (
currentLength =

restLength
).

So we compare the current length to the initial length. We find the delta and

divide it by two. Each vertex then receives a portion of this delta in the direction

that would bring the vertices closer together or further apart depending on if the

constraint is stretched or compressed. Because the results of the last iteration are

fed into the current iteration, the mesh
evolves
into a smooth shape. Listing 13.4

shows this is in pseudocode.

float
pushStrength = 0.1;

float
pullStrength = 0.5;

int
iterations = 10;

for
(eachIteration)

{
for
(eachConstraint)

{

//Calculate vector from vertex A to vertex B

vector3d AB;

AB = constraint.vertexA.pos

constraint.vertexB.pos;

//Calculate delta and divide in half

delta = ( constraint.restLength

−

−

AB.length() )

∗

0.5;

//Factor in push/pull strength parameters

if
(delta
>
0)

delta
∗
= pushStrength;

else

delta
∗
= pullStrength;

//Add the deltas for point A and point B

AB.normalize();

constraint.vertexA.pos += AB
∗
delta;

constraint.vertexB.pos

−

=AB

∗

delta;

}

}

Listing 13.4.
This is the
Deform()
function of a relaxation deformer. We are solving

position constraints by projecting positions for each constraint individually. Doing several

iterations smooths out the errors and approaches a stable solution.

You will notice two additional parameters,
pushStrength
and

pullStrength
, which describe how much of the delta to correct with each

iteration. As can be seen, the
pushStrength
parameter describes how much to

correct deformations that involve compression and
pullStrength
is applied