(Solved) rotation of x+z of parent node = childs y position gets set to 0

I have a player node, which consists of 2 spheres (head and feet) and 1 cylinder (body). The childs are never changed after creation, but somehow this line causes the head, feet and body to have an y of 0:

physicalPlayer.setLocalRotation( camRotation.clone().set(camRotation.getX(), 0, camRotation.getZ(), 0) );



I have tested everything, checked trough all my code, and only this line causes it. When I comment this line, the player will stay normal.

Please fix this bug if u can.





My player creation code:



Sphere sphere = new Sphere( 10, 10, width0.5f );

sphere.setTextureMode( Sphere.TextureMode.Projected );

Cylinder cylinder = new Cylinder( 10, 10, width
0.5f, height+width );



physicalPlayer = new Node();

Geometry playerHead = new Geometry( “Head”, sphere );

Geometry playerFeet = new Geometry( “Feet”, sphere );

Geometry playerBody = new Geometry( “Body”, cylinder );

physicalPlayer.attachChild( playerHead );

physicalPlayer.attachChild( playerBody );

physicalPlayer.attachChild( playerFeet );

playerHead.setLocalTranslation( 0, height, 0 );

playerBody.setLocalTranslation( 0, width*0.5f, 0 );

playerFeet.setLocalTranslation( 0, -width, 0 );

playerBody.rotate( FastMath.HALF_PI, 0, 0 );



TangentBinormalGenerator.generate( physicalPlayer );

physicalPlayer.setShadowMode( ShadowMode.CastAndReceive );

physicalPlayer.setMaterial( Assets.loadPlayer() );

Please provide a complete simple test case showing the issue.

Here is my code.



Run it like this and move the mouse, you’ll see a cylinder with a ball in it.

Then comment line 74 in Player.java and run it again, you then see a cylinder with a ball underneath and above it (like it’s supposed to be).



Line 74: [java]playerModel.setLocalRotation( new Quaternion(camRotation.getX(), 0, camRotation.getZ(), 0) );[/java]



PS: if you change it to this it would fix it too: [java]playerModel.setLocalRotation( camRotation );[/java]





[snippet id=“59”]



[snippet id=“60”]

@patrickvane1993 said:
Line 74: [java]playerModel.setLocalRotation( new Quaternion(camRotation.getX(), 0, camRotation.getZ(), 0) );[/java]


Sorry I missed this the first time. Quaternions do not work like you think. You cannot just take some of the magic components and leave others behind. In the above you are creating an invalid Quaternion and setting it as the rotation. This will definitely result in strange behavior and is not a bug in JME.

Try going through this: https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:math_for_dummies

Maybe it will clear things up.

Also you can maybe explain what you think that line is supposed to do.

When I had only 1 geometry it worked like I wanted it to: I wanted to turn the player from left to right to where the camera is pointing to.

@patrickvane1993 said:
When I had only 1 geometry it worked like I wanted it to: I wanted to turn the player from left to right to where the camera is pointing to.


The four components of a quaternion represent a rotation in an imaginary 4D space. You cannot just take the x and z and hope for good results. You ended up creating some non-rotation that would flatten things, I guess. So one geometry at local 0,0,0 would probably be ok by accident.

If you want the player to rotate around the Y axis then find the camera's rotation in the Y axis and rotate it by that amount.

Hint:
http://hub.jmonkeyengine.org/javadoc/com/jme3/math/Quaternion.html#toAngles(float[])
And:
http://hub.jmonkeyengine.org/javadoc/com/jme3/math/Quaternion.html#fromAngles(float,%20float,%20float)

Though you should really go through the link I provided above, also... because playing with things by poking out them randomly will get frustrating after a while.
1 Like

Ok thanks, I’ll check it out.

Finally, I got it.



[java]

Camera cam = app.getCamera();

Vector3f camDirection = cam.getDirection();

float camDirectionAngle = FastMath.atan2( camDirection.getX(), camDirection.getZ() );



playerModel.setLocalRotation( new Quaternion().fromAngleAxis(camDirectionAngle, Vector3f.UNIT_Y) );

[/java]



So simple, yet it took me more than 4 hours to come up with.

Next time it will take me less than 10 minutes (i hope).

2 Likes

Just for when someone wants head rotations too:



[java]

float camDirectionAnglePitch = FastMath.atan2( 1, cam.getDirection().getY() );

playerModel.getChild( "Head" ).setLocalRotation( new Quaternion().fromAngleAxis(camDirectionAnglePitch, Vector3f.UNIT_X) );

[/java]



(PS: it took me less than 10 minutes, woot.)

You are still treating quaternion values like they have some logical relation to axis of rotation. They don’t. It is only by some twisted luck that your approach works.



If you want to know what the rotation of a quaternion is around a particular axis then use toAngles(). It will return the euler angles that represent the quaternion and you can extract the second angle (y axis) to use in another fromAngles() call.



[java]

float[] angles = cam.getDirection().toAngles(null);

…setLocalRotation( new Quaternion().fromAngles( 0, angles[1], 0 ) );

[/java]

But… but…

cam.getDirection() gives a Vector3f, not a Quaternion.

@patrickvane1993 said:
But.. but...
cam.getDirection() gives a Vector3f, not a Quaternion.


D'oh. Sorry... I'm an idiot today.

You still might be better off using the camera's rotation Quaternion. It would handle the case where the camera is at extreme angles better.

Ok, thanks.