[SOLVED] Transform.fromTransformMatrix does not work correctly

Hello. I’m having the following problem:
When I execute the following code…

var mat = new Matrix4f(
	0, 1, 0, 0,
	1, 0, 0, 0,
	0, 0, 1, 0,
	0, 0, 0, 1
);
System.out.println(mat);
var t = new Transform();
t.fromTransformMatrix(mat);
System.out.println(t.toTransformMatrix());

…I get the following output:

Matrix4f
[
 0.0  1.0  0.0  0.0 
 1.0  0.0  0.0  0.0 
 0.0  0.0  1.0  0.0 
 0.0  0.0  0.0  1.0 
]
Matrix4f
[
 1.0  0.0  0.0  0.0 
 0.0  1.0  0.0  0.0 
 0.0  0.0  1.0  0.0 
 0.0  0.0  0.0  1.0 
]

So all I wanted to do was just swap the x- and y-axis, but Transform won’t allow me to.
The real use-case is much more complex than that of cause. I’ve just broken it down to the essential parts here.

1 Like

Transform does not support the swapping of axes because it’s internally using a quaternion for rotation. Simplifying rotations with a quaternion necessarily means that assumptions need to be made about axes orientations and handedness. Simplifying rotations with a quaternion comes with a ton of other benefits for a game engine… which is why JME uses that instead of hauling around matrix multiplication everywhere.

Edit: but if you explain what you are actually trying to do then maybe we can provide some alternative approaches.

1 Like

Thank you for the really fast answer.
It would be helpful if the code would throw me an exception then.
What I’m trying to do is the following:
My graphics card does not support glLineWidth(). glGetFloatv(GL13.GL_LINE_WIDTH_RANGE) gives me float[1.0,1.0].
So I came up with the idea to just draw a small Box around all the lines.
Lines are given by a start and end Vector3f and lineWidth is given as a float.
I successfully computed a transformation matrix that does exactly that. But then I ran into the problem above.

The math probably still worked, it just didn’t produce the results you wanted. Adding specific checks for every odd thing that a caller might send in can really bog down the code after a while.

Are the lines in 2D space or 3D space?

Either way, I feel like you can still do what you want to do without messing with coordinate axes… but I can’t see the code to know why you felt that was necessary in the first place. A box (3D or otherwise) can be projected along a line without swapping axes.

3D space of cause. In 2D, this problem would be way too easy to bother you (or someone else around here).
Yes, I know that that can be done. I just don’t know how.
“Messing” with coordinate axes was the easiest way, because you just have to compute two vectors “a” and “b” from the line vector “v” with a.dot(b) == a.dot(v) == 0 and then you basically have your transformation matrix.
I also tried to use Camera.lookAtDirection and then use the view matrix, but without any luck so far.
But I will try some other workarounds…

Okay, I have a solution. I’m documenting it here just in case someone else has the same problem. Thanks again @pspeed for your help.
Let var box = new Box(lineWidth/2,v.length()/2,lineWidth/2); be the according box and “v” be the line vector.
You can compute the Quaternion for the rotation by using Quaternion.fromAngleAxis() with var angle = Vector3f.UNIT_Y.angleBetween(v.normalize()); and var axis = Vector3f.UNIT_Y.cross(v);.
Of couse, you also have to translate, but that shouldn’t be a problem.

If your box is oriented with Z as the long axis then Quaternion().lookAt() will orient the box correctly if passed the normalized line.end1 - line.end2 vector.

Care needs to be taken if the line is parallel to the up vector supplied.

https://javadoc.jmonkeyengine.org/v3.4.0-stable/com/jme3/math/Quaternion.html#lookAt-com.jme3.math.Vector3f-com.jme3.math.Vector3f-

Yes, forgot that: The cross product obviously does not work if the the angle is 0 or 180 degree. I’ve added special if-conditions for that case.

But it’s less code to just use lookAt() versus what you do now.

Vector3f dir = v2.subtract(v1).normalizeLocal();
Vector3f up = Vector3f.UNIT_Y;
if( Math.abs(dir.dot(up)) > 0.99 ) {
    up = Vector3f.UNIT_X;
}
Quaternion rotation = new Quaternion().lookAt(dir, up);
1 Like