Book Corrections for Game Physics (2nd edition)


Book Corrections Organized by Date of Change

12 Feb 2022, page 232. Equation (5.55) is not correct as stated. The displacement x is rotated to a displacement y = RTx, but the velocity vector must be rotated similarly, say, s = RTv, and the error vector must be rotated, say, φ = RTε. Equation (5.54) is v(p+x) = v(p) + α × x + Ex + ε which is multiplied first by RT followed by the algebraic manipulations indicated on page 232: s(p+Ry) = s(p) + β×y + E'y + φ The enumerated list of 3 items is about quantities relative to the displacement y and should say (1) s(p) represents a linear translation in p, (2) β × y is a velocity that corresponds to rotation about a line with direction β and containing p, and (3) E'y = e0y0 + e1 y1 + e2 y2 is a velocity that represents stretching the volume at p and is called pure strain.

26 Nov 2017, page 832. Example 14.3 claims that there is a cycle in the LCP iterations. This is incorrect. It is true that one of the variables enters the dictionary a second time, but this can happen--it is not the definition of a cycle. The correct definition of a cycle is that the tableau formed by q and M repeats, which is not the case for this example. Several more iterations in the example finally leads to a terminal dictionary. The LCP solution is w = (0,0,0,3/4,0) and z = (1/4,9/4,1/2,0,1/2). Apparently cycling is a rare event; I have been unable to create an example where this happens when using the min-ratio algorithm for selecting variables that leave the dictionary.

26 Nov 2017, page 837. The Section 14.2.3 title should say "The Complementary Variable Cannot Enter the Dictionary".

14 Dec 2013, page 506. The last else clause of the pseudocode has a division by Length(ci.N). The division should be by Length(Cross(ci.EA,ci.EB)). This follows because of the definition of N(t) and L(t) in the paragraph after Equation (6.100).

24 Jun 2012, page 490. The second displayed equation array has "(0,-lambda)+(-4*lambda/5,lambda/5)" that should be "(0,-lambda)+(-4*lambda/5,2*lambda/5)"; however, the last equation of the array is correct. The third displayed equation array has "(lambda/10,-4*lambda/5)" that should be "(lambda/10,-3*lambda/10)"; however, this is still consistent with the postcollision motion to the right and downward.

19 Feb 2012, page 747. The second line from the top of the page mentions the initial condition "dot(theta)". This should be "dot(theta) = 0".

19 Jun 2011, page 496. The discussion at the end of the page shows how to formulate the velocity update as a convex quadratic programming problem to minimize the squared length of (Af+b). This may be equivalently handled by trying to solve for (Af+b = 0) on the convex polytope domain. You may use Gauss-Seidel iteration with projection (iterative method) rather than LCP (global method). A new exercise: Show that in Example 6.6 (rectangle contacting two immovable lines), the squared length minimum is zero, occurs on the boundary of the convex polygon domain, and the postimpulse velocity is computed from the preimpulse velocity by negating the preimpulse speeds in the normal directions at the contact points.

19 Jun 2011, pages 492-493. There are several notational errors due to using calligraphy font for points and bold font for vectos. The first line of page 492 has dot(PB) = O, where O is the origin. However, the derivative of the (point) position is a vector, so it should be dot(PB) = O, where the right-hand side denotes the zero vector. In the first displayed equation on page 492, the subtraction of the origin is incorrect, because the derivatives of the (point) positions are vectors. The equation should be
    dot(P)+A = dot(P)-A + f(...)
The two lines after this displayed equation also need the origin symbols removed
    dot(d)- = N0 • dot(P)-A and dot(d)+ = N0 • dot(P)+A
Page 493 has the same issue with the first displayed equation and two dot products in the text below the displayed equation. The origin symbols should be removed.

04 Jun 2011, page 86. The sentence "In the case of dynamics, we are specifying the acceleration and must integrate to obtain the velocity and acceleration" should end with "to obtain the velocity and position".

16 Apr 2011, page 179. A sentence below Figure 4.9 says "Control points 2 and 6 move...". This should be "Control points 2 and 10 move...".

16 Apr 2011, page 518. In the paragraph after the first displayed equation, the constraint force hat(F) is said to be a 3-by-1 vector of 3-tuples; however, it is an n-by-1 vector of 3-tuples.

16 Apr 2011, page 521. In the paragraph after the first displayed equation there is a second-order partial derivative "d^2C/dxq". This should be "d^2C/dxdq".

16 Apr 2011, page 521. A displayed equation has "Q_{ij} = sigma_{ijk} q_{k}". In the paragraph after this equation there is "The tensor S_{ijk} has...". This should be "The tensor sigma_{ijk} has...". The tensor sigma_{ijk} has indices i and k that use 0-based indexing; however, the index j uses 1-based indexing because angular velocity was defined as w = (w1,w2,w3). This means the lists of sigma values that are +1 or -1 need their middle index increased by 1.

16 Apr 2011, page 521. The construction for w^T*A*w/4 can be simplified by observing that sigma_{ijk} w_{j} Q_{kl} w_{l} can be written as a product of a 4-by-4 skew-symmetric matrix and a 4-by-1 vector,
sigma_{ijk} w_{j} =
{
{ 0, -w1, -w2, -w3},
{w1,   0, -w3,  w2},
{w2,  w3,   0, -w1},
{w3, -w2,  w1,   0}
}
Q_{kl} w_{l} =
{
-w1*q1 - w2*q2 - w3*q3,
w1*q0 + w2*q3 - w3*q2,
-w1*q3 + w2*q0 + w3*q1,
w1*q2 - w2*q1 + w3*q0
}
sigma_{ijk} w_{j} Q_{kl} w_{l} = -(w1^2 + w2^2 + w3^2)*q = -|w|^2*q

16 Apr 2011, page 522. The lower-right entry of the H matrix in Equation (6.127) has a term "qI". The quaternion should be written as a 4-tuple in bold, "qI".

16 Apr 2011, page 524. The next-to-last-line has "-Ji wi x wi". To be clear, this is computed as "-Ji(wi x wi)" (which then happens to be the zero vector).

16 Apr 2011, page 530. On this page are occurrences of w. These should all be w1. The term "R(t)b1" on the page should be "R1(t)b1". The phase "The constraint force, which is parallel to N1, must push..." should be "The "dC/dx2" component of the constraint force GT is N1 and must push..."

15 Oct 2010; pages 360, 362, 364, 370, 371, 375. Two matrices are ordered incorrectly. Equation (6.10) on page 360 should be
K2 = sqrt(D0)*transpose(R0)*(K1 - K0)
Items 2 and 3 on page 362 should be
2. Compute K2 = sqrt(D0)*transpose(R0)*(K1 - K0)
3. Compute M2 = invsqrt(D0)*transpose(R0)*R1*D1*transpose(R1)*R0*invsqrt(D0)
Equation (6.28) on page 364 should be
C(t) = transpose(R)*sqrt(D0)*transpose(R0)*(K1 - K0 + t*V) = K + t*W
The pseudocode for K2 on pages 370 and 375 should be
K2 = D0Half*((K1 - K0)*R0);
The pseudocode for M2 on pages 370 and 375 should be
R1TR0D0NegHalf = R1.TranposeTimes(R0*D0NegHalf);
M2 = R1TR0D0NegHalf.TransposeTimes(D1)*R1TR0D0NegHalf;
The pseudocode for W on pages 371 and 375 should be
W = (D0Half*((velocity1 - velocity0)*R0))*R

Book Corrections Organized by Page Number

Section 3.1, page 86. The sentence "In the case of dynamics, we are specifying the acceleration and must integrate to obtain the velocity and acceleration" should end with "to obtain the velocity and position".

Section 4.3.2, page 179. A sentence below Figure 4.9 says "Control points 2 and 6 move...". This should be "Control points 2 and 10 move...".

Section 5.2.1, page 232. Equation (5.55) is not correct as stated. The displacement x is rotated to a displacement y = RTx, but the velocity vector must be rotated similarly, say, s = RTv, and the error vector must be rotated, say, φ = RTε. Equation (5.54) is v(p+x) = v(p) + α × x + Ex + ε which is multiplied first by RT followed by the algebraic manipulations indicated on page 232: s(p+Ry) = s(p) + β×y + E'y + φ The enumerated list of 3 items is about quantities relative to the displacement y and should say (1) s(p) represents a linear translation in p, (2) β × y is a velocity that corresponds to rotation about a line with direction β and containing p, and (3) E'y = e0y0 + e1 y1 + e2 y2 is a velocity that represents stretching the volume at p and is called pure strain.

Section 6.3; pages 360, 362, 364, 370, 371, 375. Two matrices are ordered incorrectly. Equation (6.10) on page 360 should be
K2 = sqrt(D0)*transpose(R0)*(K1 - K0)
Items 2 and 3 on page 362 should be
2. Compute K2 = sqrt(D0)*transpose(R0)*(K1 - K0)
3. Compute M2 = invsqrt(D0)*transpose(R0)*R1*D1*transpose(R1)*R0*invsqrt(D0)
Equation (6.28) on page 364 should be
C(t) = transpose(R)*sqrt(D0)*transpose(R0)*(K1 - K0 + t*V) = K + t*W
The pseudocode for K2 on pages 370 and 375 should be
K2 = D0Half*((K1 - K0)*R0);
The pseudocode for M2 on pages 370 and 375 should be
R1TR0D0NegHalf = R1.TranposeTimes(R0*D0NegHalf);
M2 = R1TR0D0NegHalf.TransposeTimes(D1)*R1TR0D0NegHalf;
The pseudocode for W on pages 371 and 375 should be
W = (D0Half*((velocity1 - velocity0)*R0))*R

Section 6.6.2, page 490. The second displayed equation array has "(0,-lambda)+(-4*lambda/5,lambda/5)" that should be "(0,-lambda)+(-4*lambda/5,2*lambda/5)"; however, the last equation of the array is correct. The third displayed equation array has "(lambda/10,-4*lambda/5)" that should be "(lambda/10,-3*lambda/10)"; however, this is still consistent with the postcollision motion to the right and downward.

Section 6.6.2, pages 492-493. There are several notational errors due to using calligraphy font for points and bold font for vectos. The first line of page 492 has dot(PB) = O, where O is the origin. However, the derivative of the (point) position is a vector, so it should be dot(PB) = O, where the right-hand side denotes the zero vector. In the first displayed equation on page 492, the subtraction of the origin is incorrect, because the derivatives of the (point) positions are vectors. The equation should be
    dot(P)+A = dot(P)-A + f(...)
The two lines after this displayed equation also need the origin symbols removed
    dot(d)- = N0 • dot(P)-A and dot(d)+ = N0 • dot(P)+A
Page 493 has the same issue with the first displayed equation and two dot products in the text below the displayed equation. The origin symbols should be removed.

Section 6.6.2, page 496. The discussion at the end of the page shows how to formulate the velocity update as a convex quadratic programming problem to minimize the squared length of (Af+b). This may be equivalently handled by trying to solve for (Af+b = 0) on the convex polytope domain. You may use Gauss-Seidel iteration with projection (iterative method) rather than LCP (global method). A new exercise: Show that in Example 6.6 (rectangle contacting two immovable lines), the squared length minimum is zero, occurs on the boundary of the convex polygon domain, and the postimpulse velocity is computed from the preimpulse velocity by negating the preimpulse speeds in the normal directions at the contact points.

Section 6.6.3, page 506. The last else clause of the pseudocode has a division by Length(ci.N). The division should be by Length(Cross(ci.EA,ci.EB)). This follows because of the definition of N(t) and L(t) in the paragraph after Equation (6.100).

Section 6.7.2, page 518. In the paragraph after the first displayed equation, the constraint force hat(F) is said to be a 3-by-1 vector of 3-tuples; however, it is an n-by-1 vector of 3-tuples.

Section 6.7.3, page 521. In the paragraph after the first displayed equation there is a second-order partial derivative "d^2C/dxq". This should be "d^2C/dxdq".

Section 6.7.3, page 521. A displayed equation has "Q_{ij} = sigma_{ijk} q_{k}". In the paragraph after this equation there is "The tensor S_{ijk} has...". This should be "The tensor sigma_{ijk} has...". The tensor sigma_{ijk} has indices i and k that use 0-based indexing; however, the index j uses 1-based indexing because angular velocity was defined as w = (w1,w2,w3). This means the lists of sigma values that are +1 or -1 need their middle index increased by 1.

Setion 6.7.3, page 521. The construction for w^T*A*w/4 can be simplified by observing that sigma_{ijk} w_{j} Q_{kl} w_{l} can be written as a product of a 4-by-4 skew-symmetric matrix and a 4-by-1 vector,
sigma_{ijk} w_{j} =
{
{ 0, -w1, -w2, -w3},
{w1,   0, -w3,  w2},
{w2,  w3,   0, -w1},
{w3, -w2,  w1,   0}
}
Q_{kl} w_{l} =
{
-w1*q1 - w2*q2 - w3*q3,
w1*q0 + w2*q3 - w3*q2,
-w1*q3 + w2*q0 + w3*q1,
w1*q2 - w2*q1 + w3*q0
}
sigma_{ijk} w_{j} Q_{kl} w_{l} = -(w1^2 + w2^2 + w3^2)*q = -|w|^2*q

Section 6.7.3, page 522. The lower-right entry of the H matrix in Equation (6.127) has a term "qI". The quaternion should be written as a 4-tuple in bold, "qI".

Section 6.7.4, page 524. The next-to-last-line has "-Ji wi x wi". To be clear, this is computed as "-Ji(wi x wi)" (which then happens to be the zero vector).

Section 6.7.5, page 530. On this page are occurrences of w. These should all be w1. The term "R(t)b1" on the page should be "R1(t)b1". The phase "The constraint force, which is parallel to N1, must push..." should be "The "dC/dx2" component of the constraint force GT is N1 and must push..."

Section 14.2.1, page 832. Example 14.3 claims that there is a cycle in the LCP iterations. This is incorrect. It is true that one of the variables enters the dictionary a second time, but this can happen--it is not the definition of a cycle. The correct definition of a cycle is that the tableau formed by q and M repeats, which is not the case for this example. Several more iterations in the example finally leads to a terminal dictionary. The LCP solution is w = (0,0,0,3/4,0) and z = (1/4,9/4,1/2,0,1/2). Apparently cycling is a rare event; I have been unable to create an example where this happens when using the min-ratio algorithm for selecting variables that leave the dictionary.

Section 14.2.3, page 837. The Section 14.2.3 title should say "The Complementary Variable Cannot Enter the Dictionary".