-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
com.jme3.math breaks in many places if scale factors are allowed to be negative. For instance, Matrix4f.toScaleVector(Vector3f) assigns a (positive) square root to each component:
jmonkeyengine/jme3-core/src/main/java/com/jme3/math/Matrix4f.java
Lines 1861 to 1873 in a94c37a
| /** | |
| * Determines the scale component of the coordinate transform. | |
| * | |
| * @param store storage for the result (not null, modified) | |
| * @return the scale factors (in {@code store}) for chaining | |
| */ | |
| public Vector3f toScaleVector(Vector3f store) { | |
| float scaleX = (float) Math.sqrt(m00 * m00 + m10 * m10 + m20 * m20); | |
| float scaleY = (float) Math.sqrt(m01 * m01 + m11 * m11 + m21 * m21); | |
| float scaleZ = (float) Math.sqrt(m02 * m02 + m12 * m12 + m22 * m22); | |
| store.set(scaleX, scaleY, scaleZ); | |
| return store; | |
| } |
As a consequence of this bug (or undocumented assumption) the zero-argument Matrix4f.oScaleVector() method is also broken, as is Transform.fromTransformMatrix(Matrix4f).
Here is a code fragment that demonstrates those breakages:
Vector3f transA = new Vector3f(1f, 2f, 3f);
Quaternion rotA = new Quaternion(0.8f, 0.4f, 0.2f, 0.4f);
Vector3f scaleA = new Vector3f(4f, -5f, -6f);
Transform a = new Transform(transA, rotA, scaleA);
Matrix4f matA = a.toTransformMatrix();
Transform b = new Transform();
b.fromTransformMatrix(matA);
System.out.println("a: " + a);
System.out.println("b: " + b);
System.out.println();
Vector3f scaleB = matA.toScaleVector();
System.out.println("scaleA: " + scaleA);
System.out.println("scaleB: " + scaleB);
System.out.println();If this issue were solved, the transforms a and b would be approximately equal, as would the vectors scaleA and scaleB. Instead, we get:
a: Transform[ 1.0, 2.0, 3.0]
[ 0.8, 0.4, 0.2, 0.4]
[ 4.0 , -5.0, -6.0]
b: Transform[ 1.0, 2.0, 3.0]
[ -0.40000004, -0.20000003, 0.40000004, 0.8]
[ 4.0 , 5.0, 5.9999995]
scaleA: (4.0, -5.0, -6.0)
scaleB: (4.0, 5.0, 5.9999995)There's a similar assumption of positive scale factors in Quaternion.fromRotationMatrix(), which rejects scaling but only if all the scale factors are positive.
Directly or indirectly, JMonkeyEngine uses these methods in many places, notably Transform.invert(), which is similarly broken, as demonstrated by the following code fragment:
Vector3f transA = new Vector3f(1f, 2f, 3f);
Quaternion rotA = new Quaternion(0.8f, 0.4f, 0.2f, 0.4f);
Vector3f scaleA = new Vector3f(4f, -5f, -6f);
Transform a = new Transform(transA, rotA, scaleA);
Transform aInverse = a.invert();
Transform c = aInverse.invert();
System.out.println("a: " + a);
System.out.println("c: " + c);
System.out.println();If this issue were solved, the transforms a and c would be approximately equal. Instead, we get:
a: Transform[ 1.0, 2.0, 3.0]
[ 0.8, 0.4, 0.2, 0.4]
[ 4.0 , -5.0, -6.0]
c: Transform[ 1.74527, 2.0037012, 2.7823966]
[ -0.3705214, -0.15285265, 0.4035354, 0.8135669]
[ 4.5550847 , 5.043545, 4.949222]If a matrix contains an odd number of negative scale factors, the fact can be detected using determinants. However, I don't know an easy way to detect an even number of negative scale factors.