Lookat problems with nodes

Hi, I am having several problems with lookat when using nodes, I was trying to build a test case, and I was not able even to do it :

The problem is simple, I have a sphere, and a camera looking to it at 0,0,0.
If I remove the code on simpleupdate it shows the sphere, if not, it shows nothing, and the code on simpleupdate suppose not to do anything at all, at least at starting.

My felling is that its a serious bug out there , follow the test case:

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Matrix3f;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.control.CameraControl;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Texture;

public class rotTestCase extends SimpleApplication implements ActionListener, AnalogListener {
Material matRock;
Geometry sphere , oPlayer;
Vector3f lookAt = new Vector3f(0,0,1);
Vector3f up = new Vector3f(0,1,0);
boolean pressed = false;

Node playerNode = new Node();

CameraNode chaseCam;
Node centralCamNode = new Node();

float valuex,valuey;

public static void main(String[] args) { new rotTestCase().start(); }

@Override public void simpleInitApp() {
    setupInput();
    createMaterial();

    Sphere mesh = new Sphere(16, 16, 1);
    sphere = new Geometry("sphere", mesh);
    sphere.setMaterial(matRock);
    rootNode.attachChild(sphere);

    Box pmesh = new Box(0.1f, 0.1f, 0.1f);
    Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    oPlayer = new Geometry("player", pmesh);
    playerNode.attachChild(oPlayer);
    oPlayer.setLocalTranslation(0, 1.2f, 0);
    m.setColor("Color", ColorRGBA.Blue); oPlayer.setMaterial(m);
    rootNode.attachChild(playerNode);

    chaseCam = new CameraNode("Camera Node", cam);
    centralCamNode.attachChild(chaseCam);
    chaseCam.setControlDir(CameraControl.ControlDirection.SpatialToCamera);
    chaseCam.setLocalTranslation(0, 4f, 0);
    chaseCam.lookAt(sphere.getLocalTranslation(), Vector3f.UNIT_Y);
    rootNode.attachChild(centralCamNode);

    valuex=0; valuey=0;

    // for some reason I need to do this, maybe a bug ??
    centralCamNode.setLocalRotation(  playerNode.getLocalRotation()  );

    rootNode.addLight(new DirectionalLight());
    flyCam.setEnabled(false);
}

private void setupInput() {
    inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_LEFT));     inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_A ));
    inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_RIGHT));   inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_D));
    inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_UP));         inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_W));
    inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_DOWN));     inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_S));
    inputManager.addListener(this, "left","right","up","down","space");
}

private void createMaterial() {
    matRock = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    TextureKey key2 = new TextureKey("Textures/Rock/Rock.PNG");
    key2.setGenerateMips(true);
    Texture tex2 = assetManager.loadTexture(key2);
    matRock.setTexture("ColorMap", tex2);
}

@Override public void simpleUpdate(float tpf) {
    Node temp = new Node();
    temp.lookAt( sphere.getLocalTranslation() , Vector3f.UNIT_Y );
centralCamNode.setLocalRotation(temp.getLocalRotation());
}

public void onAction(String name, boolean isPressed, float tpf) {
    //if (binding.equals("Button")) { pressed = value; System.out.println("button: " + value); }
}

public void onAnalog(String name, float value, float tpf) {
    //System.out.println("name "+name+" ispressed="+isPressed);

    valuey=1f*tpf;
    valuex=-1f*tpf;

    if (name.equals("left")) {
            Quaternion add = new Quaternion().fromAngleAxis(+FastMath.QUARTER_PI * valuey * 4, Vector3f.UNIT_Y);
            //add.multLocal(lookAt);
            //add.multLocal(up);

            playerNode.rotate(add);

    } else if (name.equals("right")) {
            Quaternion add = new Quaternion().fromAngleAxis(-FastMath.QUARTER_PI * valuey * 4, Vector3f.UNIT_Y);
            //add.multLocal(lookAt);
            //add.multLocal(up);

            playerNode.rotate(add);

    } else if (name.equals("up")) {
            Quaternion add = new Quaternion().fromAngleAxis(-FastMath.QUARTER_PI * valuex * 4, Vector3f.UNIT_X);
            //add.multLocal(lookAt);
            //add.multLocal(up);
            playerNode.rotate(add);


    } else if (name.equals("down")) {
            Quaternion add = new Quaternion().fromAngleAxis(+FastMath.QUARTER_PI * valuex * 4, Vector3f.UNIT_X);
            //add.multLocal(lookAt);
            //add.multLocal(up);
            playerNode.rotate(add);

    }


    /*if (binding.equals("MouseLeft")) {
        if (pressed) {
            Quaternion add = new Quaternion().fromAngleAxis(-FastMath.QUARTER_PI * value * 10, Vector3f.UNIT_Y);
            add.multLocal(lookAt);
            add.multLocal(up);
        }
    } else if (binding.equals("MouseRight")) {
        if (pressed) {
            Quaternion add = new Quaternion().fromAngleAxis(FastMath.QUARTER_PI * value * 10, Vector3f.UNIT_Y);
            add.multLocal(lookAt);
            add.multLocal(up);
        }
    } else if (binding.equals("MouseUp")) {
        if (pressed) {
            Quaternion add = new Quaternion().fromAngleAxis(FastMath.QUARTER_PI * value * 10, Vector3f.UNIT_X);
            add.multLocal(lookAt);
            add.multLocal(up);
        }
    } else if (binding.equals("MouseDown")) {
        if (pressed) {
            Quaternion add = new Quaternion().fromAngleAxis(-FastMath.QUARTER_PI * value * 10, Vector3f.UNIT_X);
            add.multLocal(lookAt);
            add.multLocal(up);
        }
    }*/
}

public static Vector3f getForward(Node node) {
    Vector3f forward = new Vector3f(0,0,1);
    node.localToWorld(forward,forward);
    return forward;
}

public static Vector3f getUpVector(Node node) {
    Vector3f forward = new Vector3f(0,1,0);
    node.localToWorld(forward,forward);
    return forward;
}

}

Please note that centralCamNode and sphere have 0 rotation.
It seens I am having the same problem from the old post :

This is only one problem I have , but there is more all related.

Do anyone knows why it happens ? If its a bug and or a way to make it work ?

Another very weird behavior, if I change the line 100 to :

temp.lookAt( getUpVector(playerNode) , Vector3f.UNIT_Y );

The camera “moves” to the box translation ! How come ???

I know I will regret wading into this thread… but what do you use new Node() here?

The issue is that temp will be located at 0,0,0 when you create it so lookAt() is meaningless because you are looking at the location you already are.

But the funny thing is that you already have a centralCamNode to call lookAt() on.

1 Like

Well, yes, all nodes in this code are in 0,0,0.
The point is, this code suppose not to do anything, but it is doing a lot.
I was trying to build an test case for another problem, this temp node will be used for other stuff in there, but since it gets broken at it, I just decide to post in here.
What I mean is that the code is not complete because I stop coding after I saw this problem.
I hope you understand, I am trying my best to make it clear, you need to use the “good faith” sometimes.

Translation:
“I wrote code that creates a bad transformation because it is attempting to make an object sitting at 0,0,0 look at 0,0,0 which is impossible so creates a bad rotation that makes my scene invisible. I know it’s wrong but why is it wrong?”

I knew I would regret wading into this.

Show real code or don’t bother posting really. I’m getting tired of responding to “Yes, I know my code is bad” posts.

1 Like

So what you are saying is that if you do lookat at an object at 0,0,0 into another object at 0,0,0 it will not rotate to this object ?
If so than that is the problem, but I got the impression that it works that way…

You dont need to be rude by the way.

What direction should an object sitting at 0,0,0 rotate to look at an object at 0,0,0? There is no answer because an object at 0,0,0 CANNOT look at an object at 0,0,0. This creates an invalid transformation. Basically your eyes roll back into your head and you can’t see anything anymore. (Trying to put it into terms you will understand.)

It creates an invalid transformation. Invalid means it won’t work. As in, you won’t see anything. Like, won’t see anything at all because the transform is invalid. And by “won’t see anything” I don’t mean “looking in some strange direction”. I mean YOU WON’T SEE ANYTHING. 0 objects. Well, you are seeing them but they are all of 0 size in an infinite distance in an imaginary direction.

1 Like

Yeah, I’m just going to stop replying to your posts. Sorry.

I get very frustrated when I reply “well your code is wrong because of this” and get a response “Yes, I know my code is wrong because of that. What’s the issue?”

I have very little time these days and so have zero patience for this kind of time wasting. I will no longer reply to these posts in the future. Others will have more patience and can help you.

Sorry again.

I understand what you are saying, but I have an intire code working doing exactly this, and as I said its working, the node1 when look at node2 at the same position just rotate into it.
I was doing this to make an slerp camera, if this is the wrong way to do it, nice, thank you, you just solve the issue.

You guys are beeing very rude, I guess people stops to come into this site because of this. That is bad for the engine, I dont get why you came here and try to help people if you do this at all…
I have a valid post here, I got an impression that the lookat works in a way you are saying its not that way, its an valid post, will help peaple to understand how this works.
I saw lookats in another engines and they rotate objects in the same position, so I thought it works that way here, please be more polide.

Please explain how an object at world position 0,0,0 can rotate to look at an object at 0,0,0.

How can your eyes look at your own eyes?

In other engines, the lookat checks the position, if its in the same position it just rotate into it.
Think asking a object head and eyes to look into a direction the other head is looking at.
And as I said, if you try to do some tests, if you rotate they a bit they will work, but if you are saying this is invalid in this engine, I believe you, no more discussions, after all, you are core developer…

I saw the problem in your code and I pointed it out only to have you tell me that you already know that’s a problem. This is the same as wasting everyone’s time. Some people are more ok with that than I am. Given how this same thing has happened in your other threads, I should have known better. The mistake is mine as I should have let more patient people answer.

If you want one object to look in the same direction as another object then set the rotation the same.

What I don’t understand is why you are even trying to do that. Aren’t you actually trying to have the camera look at the planet? These two things will never be at the same location.

You might also benefit from this article:
http://mywiki.wooledge.org/XyProblem

1 Like

Well, I really do need to use lookat because it will not look at the planet but to the cube in slerp, and it will not be at the same position after the player moves it.
It was much more easy to do it using lookat on the nodes, but I didnt notice that it could not be valid in jmonkey, thank you for clarifying it.

And I am really sorry for any problem or frustration you had with me in another thread, I really make a mistake in there and I am trying to make the communication works from now on.

Just to add, I really didnt even consider it to be invalid, as I am use to do this in other engines, so this is really valid for others in the same condition. Thanks again.

Well, it’s possible the code could be more graceful or throw an error if you ask for the impossible… but the fact that other engines do something arbitrary in this case is not necessarily comforting either. I would think the best option would be to do nothing at all else you end up with very strange visuals potentially.

JME tends to opt on the side of performance in these cases and so trusts the user to pass in sensible parameters. Else it has to check every time for whether they are sensible or not which slightly slows down the 99.9% of cases where good values were passed in to catch the one crazy time. Generally not a good trade.

You could always do this check yourself.
float length = obj1.getWorldTranslation().distanceSquared(obj2.getWorldTranslation));
if( length < minDistance ) {
// Do arbitrary direction setting (my vote would be for ‘don’t change the direction at all’)
} else {
// do the lookAt
}