I was playing with directional lights and shadow casting, and wanted to do something really simple for my test - that being an arrow showing the direction of the light, as I kept losing it
So I added an arrow primitive for the job.
What I cant work out is how to rotate the arrow to align it with the light direction.
The directionlight has a vector showing the lights direction, but I can't work out how to convert from that vector to anything you can use to set the local rotation for the arrow object. The closest I got was using look at, but that didnt give me the right results.
It feels like it should be soooo simple, but I just aint getting it…
It seems the arrow it rotated funnily by default.
If you rotate the arrow first, so it correctly points into the Z direction, you can later use quaternion.lookAt() to look at a diven direction.
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.shape.Arrow;
public class SimpleDirection extends SimpleGame {
@Override
protected void simpleInitGame() {
Arrow arrow = new Arrow("hiya", 5, 0.7f);
arrow.setModelBound(new BoundingBox());
arrow.updateModelBound();
// fix the arrow rotation
Quaternion correctXRotation = new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD*-90, Vector3f.UNIT_X.clone());
Quaternion correctZRotation = new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD*180, Vector3f.UNIT_Z.clone());
arrow.setLocalRotation(correctXRotation.mult(correctZRotation));
// attach the fixed arrow to a node
Node arrowNode = new Node("arrow node");
arrowNode.attachChild(arrow);
// now rotate the node into the desired direction
// -1, 1, 0 to the left and up
// 1, 0, 1 to the backwards and to the right
Vector3f direction = new Vector3f(1, 0, 1);
arrowNode.getLocalRotation().lookAt(direction, Vector3f.UNIT_Y);
rootNode.attachChild(arrowNode);
}
public static void main(String[] args) {
new SimpleDirection().start();
}
}
Excellent, that works just perfectly for what I wanted, I did notice the in the code comments for lookat that it transforms the z axis, but hadnt quite understood what that meant - but the answer does raise some more beginner mistakes I was making, so now I have a couple more questions (isnt that always the way).
One (well the biggest it seems) mistake I was making was that I was affecting the Arrow object directly rather than attaching it to a node and affecting that. Why is this step so necessary when translating the arrow seems fine, but rotating it isnt, or is this just for lookat ?
When you apply the final rotation, you use node.getLocalRotation().lookAt(…) rather than just node.lookAt(…). In a quick test this didnt seem to make a difference. The code does one extra step for node.lookat but im not really sure what that does (subtracts the position from the world position before passing it to the getLocalRotation.lookat??), so im guessing because It made no difference because I have a very simple scene centered around the origin?
JOC said:
Why is this step so necessary when translating the arrow seems fine, but rotating it isnt.
The Arrow mesh is not Z-Axis aligned, so first we rotate the Arrow mesh to point correctly into the z-direction and attach it to a new node.
Now the arrow's new rotation is kinda saved.
JOC said:
im guessing because It made no difference because I have a very simple scene centered around the origin?
Exactly, node.lookAt() looks at a world position where as Quaternion.lookAt() takes a direction as parameter.
If you move the node 5 units to the left and try again it will make a difference.
Thanks again for you time and help (would have replied earlier but got dragged off shopping - damn this nice weather).
On my first question, I don't think I explained myself well…
I now understand the rotating of the arrow to Z align it first, what I didn't get is why the arrow (which extends Node) needs to be attached to another Node, and when you use lookat on the parent node it works, but if you do it directly on the Arrow node it doesn't when in my 2 tests (in test 1 the arrow without a parentnode, and test 2 tha arrow with a parent node), both nodes are attached directly to the rootnode?
On the second question - that kinda makes sense. Have been a little confused by the whole world and local thing, but think Im getting closer - if im right in assuming that world means a fixed coordinate system (meaning the world's orientation can't be changed, and that rotation/translation in world coordinates will always be around/relative to the origin?) and that local means local in relation to its parent node?
JOC said:
I now understand the rotating of the arrow to Z align it first, what I didn't get is why the arrow (which extends Node) needs to be attached to another Node,
If we don't attach the arrow to a new node, and call arrow.lookAt() then the previous rotation would be overwritten and our previously correct arrow rotation would be lost.
But if we attach the arrow to a new node after we set its correct rotation, the arrow will always keep this new initial rotation.
JOC said:
and that rotation/translation in world coordinates will always be around/relative to the origin?) and that local means local in relation to its parent node?
absolutely :)
It takes a bit time to understand those basic scenegraph concepts, but once you got used to it, its pretty easy and logical.
A good exercise would be to create a planetary system with a sun earth and moon, each rotating correctly around each other.
There is absolutely no math needed to acheive this.
Core-Dump said:
If we don't attach the arrow to a new node, and call arrow.lookAt() then the previous rotation would be overwritten and our previously correct arrow rotation would be lost.
But if we attach the arrow to a new node after we set its correct rotation, the arrow will always keep this new initial rotation.
Ahhh of course... doh, feel pretty stupid now, but yes, that makes perfect sense.
I am struggling a bit with the strict hierarchical nature of the scenegraph. I did have another question here recently about organisation of a scene when I was playing with Q3 maps (started there as I am familiar with BSP trees from work long ago), but I guess it was tooo big a question. Maybe I'll work up to that one again - think I've spent tooo long writing boring business software :D
Thanks again for your help, its very much appreciated.