I am translating a node base on the translation of a different object, but I am having trouble translating it in the right direction after I’ve rotated it.
The translation works as intended if I don’t rotate the node.
After applying local rotation, the translation will still do the same, which is predictable. But how do I take the rotation into consideration for the translation of the node?
I’ll take another stab:
To apply child translation on top of a parent rotation you multiply the child offset by the parents rotation, then add that to the parents translation, so
Vector3f localPos = new Vector3f(0,0,5);
Quaternion childRot = new Quaternion();
Vector3f parentPos = new Vector3f(0,0,10);
Quaternion parentRot = new Quaternion().fromAngles(0,90,0);
//apply the parents transform to the childs
Vector3f childWorldPos = parentPos.add(parentRot.mult(localPos));
Quaternion childWorldRot = parentRot.mult(childRot);//I think this last step is what you don't want
It is probably worth it to implement this yourself instead of relying on nodes and heirarchy if the behaviour you are after isn’t using the built in child transforms. Best practice is to have a CameraAppState that you can give a spatial target to and do whatever transforms on the camera itself, this way you can easily have smooth camera transforms or ignore the parent’s rotation (which I THINK is what you want)
Alright, I see that my explanation was crap. The “headset” in my diagram is the object that I derive my transformations from. The object is a VR headset and it gets its transformations from the user’s head movements so I can’t change the transformations through code. Since I cannot rotate the headset, it’s transformations are the same no matter what rotation my node has. How can I take the movement from the headset (let’s say it moves forward 0, 0, 1) and translate that to the correct movement for the node which is rotated (the node is rotated 90 degrees clockwise, so its forward is no longer the same as the headset’s, so it is moved to it’s local left). In the diagrams the arrow (or child), is the player and camera which is parented to the node.
get the “forward” direction for the headset by multiplying your “forward” vector by the headsets rotation (usually new Vector3f(0,0,-1)), then you need to add this to the objects position.
Quaternion headsetRot = cam.getRotation();//or however else you can get the headset's rotation if not the camera
Vector3f headsetForward = headsetRot.mult(new Vector3f(0,0,-1));//forward is usually -z axis, adjust as needed
Vector3f targetPos = target.getLocalTranslation().addheadsetForward.mult(speed*tpf));
target.setLocalTranslation(targetPos);
This is based off your diagram, assuming the node and the headset are on the same node or the root node. If you want to move the child and keep it’s parent node in place you have to move the child by the inverse of it’s parents rotation
Hopefully these diagrams better portray my problem. The black arrow represents the headset and its rotation. The red arrow represents my node and its rotation which is mirroring the black arrows translation. I want to mirror the black arrows forward movement to translate across the red arrows rotation. So if the red arrow is rotated to the right, and the black arrow up, the red arrow would move right as the black arrow moves up.
Yes, but what is the node. Is it a pumpkin floating in space? A magic wand? A tweetie bird companion?
Explain to us like we are four years old what your ACTUAL game objects are… then we can back up into what is a node, what is a parent, and what is a child.
My big fear is that we find ourselves in a “how do I inject things into my stomach” discussion… see:
Let us understand why your scene graph is the way it is… because I still don’t understand why there is any parent/child relationship at all here.
Alright, there is a spatial called observer which deals with the transformation for the player’s camera. The camera itself cannot be moved because it is directly transformed by the headset. I rotate the observer, but when I do it doesn’t rotate where I want it too. I negate that spatial with the translation of the VR headset. I use the function vrAppState.getVRHardware.getPosition(), which returns the real world translation of the headset’s movement. I offset this with another node (observerNode) using the same function. Now I have a node that allows me to rotate at the location of the headset, the current hierarchy is VRHeadset < Observer < ObserverNode. Now when I move my head everything translates as it should. However, when I rotate the observerNode, observerNode.rotate(0, 90, 0), and move my head forward, the node is moved forward, which from the view of the camera, is moved left.
and move my head forward, the node is moved forward, which from the view of the camera, is moved left.
Ok i belive your head rotations + translation move VRHeadset Spatial(or rather camera controlled by it), nothing else.
Assuming this is truth and assuming VRHeadset is child of ObserverNode:
observerNode.rotate(0, 90, 0)
after this, VRHeadset Spatial when you move your head forward, move left. And this is Correct! Because Forward for child is globally Left
What is incorrect, seems that camera rotation is incorrect(VR camera front should be now rotated as well). I dont know VRHeadset camera behaviour, but i assume camera lookAt Global position instead local based on what you say.(or maybe you provided somewhere rootNode instead of ObserverNode in VR settings as “relative node”)
You said you cant manipulate camera, right? but when you rotate character left or right, you want camera to rotate center of view as well if i good understand. In this case i would seek answer in VR settings or some VRHeadset setting that would allow change “front camera direction” where you would just copy ObserverNode “front vector” into it.
edit:
in short words, i belive Camera rotation is not trully affected by VRHeadset, but have global rotation / look at point.
The game is firstperson, and the transformations of the camera are dealt with through JME’s VRAppState class. They use the observer spatial to decide where the camera is. The observerNode is there just to offset the observer and stay centered with the camera’s location so I can rotate at its center.
I feel like I’m going around in circles at this point… so I’ll just sign out now and let others propose complicated solutions to what is likely a simple scene graph issue.
Good luck with your game. I hope the problems get worked out because VR games are cool.
I think what we’re all trying to say is that you are explaining what you’re trying to do but without the big picture.
What exactly are you trying to do. Keep a 3D HUD in view? Move an object away from the player? What? You are explaining the math you’re trying to solve but that might not be the best way. And if it is, by knowing exactly what you’re trying to do will let us understand the reason and thus logic behind the math you’re trying to explain.
I want to rotate the player’s view from the players position. Since you can move you’re headset you can move away from the center of the observer. When you rotate, often times you’ll be rotated from some position away from you. This is a little disorientating and will put you through things like walls.
If there is a better way of doing this, it would probably deal with this class, the VRViewManager.java. A method in here states:
* updatePose can be called here because appstates are always called before the main renderer. This way we get the latest pose close to when it's supposed to render
*/
public void render() {
if (environment != null) {
// grab the observer
Object obs = environment.getObserver();
Quaternion objRot;
Vector3f objPos;
if (obs instanceof Camera) {
objRot = ((Camera) obs).getRotation();
objPos = ((Camera) obs).getLocation();
} else {
objRot = ((Spatial) obs).getWorldRotation();
objPos = ((Spatial) obs).getWorldTranslation();
}
// grab the hardware handle
VRAPI dev = environment.getVRHardware();
if (dev != null) {
// update the HMD's position & orientation
dev.updatePose();
dev.getPositionAndOrientation(hmdPos, hmdRot);
if (obs != null) {
// update hmdPos based on obs rotation
finalRotation.set(objRot);
finalRotation.mult(hmdPos, hmdPos);
finalRotation.multLocal(hmdRot);
}
finalizeCamera(dev.getHMDVectorPoseLeftEye(), objPos, getLeftCamera());
finalizeCamera(dev.getHMDVectorPoseRightEye(), objPos, getRightCamera());
} else {
getLeftCamera().setFrame(objPos, objRot);
getRightCamera().setFrame(objPos, objRot);
}
}
}