Wierd Ray Casting behaviors with scaling

So, I have a simple program that involves a square room made up of 4 boxes of 10,4,1.
Inside this room I have a small cube that i want to translate along a simple vector, and have it turn around when it hits the wall, and repeat. I accomplish this by calculating the distance from the cube to the approaching wall using ray casting, and reverse when some close distance is reached.

My code works with my scale set to 1, but when I set it to anything higher I get strange behavior.
Jmonkey seems to think my wall geometries are much further away then they ā€œappearā€ to be. and thus will pass right through it and will start backtracking from further behind it.
Can anyone tell me why this is and possibly how to fix it so that when my rootNode is scaled to any value my cube will behave as I described?

[java]
package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResults;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
public class Main extends SimpleApplication {

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

int scale = 1;
Spatial s;
Vector3f dir;
public void simpleInitApp() {
//Create floor

    flyCam.setMoveSpeed(20);
    Box floor = new Box(10, 0.05f, 10);
    Geometry geom = new Geometry("Box", floor);
    
    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setColor("Color", ColorRGBA.Gray);
    geom.setMaterial(mat);
    geom.setLocalTranslation(10, -3.0f, 10);
    rootNode.attachChild(geom);
    Box wall;
    Spatial Wall;
    mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
    mat.setColor("Color", ColorRGBA.Brown);
    for(int i=0; i<4; i++){
    if(i==0){
    wall = new Box(10,4,1);
    Wall = new Geometry("w1", wall);
    Wall.setMaterial(mat);
    Wall.move(10,0,0);
    }
    else if(i==1){
    wall = new Box(1,4,10);
    Wall = new Geometry("w2", wall);
    Wall.setMaterial(mat);
    Wall.move(0,0,10);
    }
    else if(i==2){
    wall = new Box(10,4,1);
    Wall = new Geometry("w3", wall);
    Wall.setMaterial(mat);
    Wall.move(10,0,20);
    }
    else if(i==3){
    wall = new Box(1,4,10);
    Wall = new Geometry("w4", wall);
    Wall.setMaterial(mat);
    Wall.move(20,0,10);
    }
    else {
        Wall = new Geometry();//to avoid warnings
    }
    rootNode.attachChild(Wall);
    }
    dir = new Vector3f(1,0,0);//initial direction

    Box b = new Box(1f,1f,1f);
    s = new Geometry("oscillator", b);
    mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
    mat.setColor("Color", ColorRGBA.Red);
    s.setMaterial(mat);
   
    s.setLocalTranslation(5,-2f,5);
    rootNode.attachChild(s);
    rootNode.scale(scale);

}
@Override
public void simpleUpdate(float tpf) {

    Ray r = new Ray(s.getLocalTranslation(),dir);
    s.move(dir.mult(0.01f));//slow it down.
    CollisionResults results = new CollisionResults();
    rootNode.collideWith(r, results);
    if(results.size() > 0){
        //if distance < some threshold reverse direction vector.
        float dist = results.getClosestCollision().getDistance();
        System.out.println(dist);//for debug
        if(dist < 1){
            dir = dir.negate();
        }
        //for debug
        System.out.println(results.getClosestCollision().getGeometry());
    }

}
}
[/java]

When you run my code you will see what I mean.
If you change my global ā€˜scaleā€™ value to anything higher than 1, you can watch the console as it outputs the distance from where it thinks the far side wall is, and itā€™s clearly not where it is displayed.

Itā€™s too bad you didnā€™t provide examples of the output when itā€™s bad. Might have given us something more to go on without downloading and running the code.

When scale is 2-4 the ray cast will calculate the distance like I intuitively think it would. scale 2 = scale 1(x2,y2,z*2) etc.
However this is apparently not how the geometries are scaled because this causes them to go out of the ā€˜roomā€™ completely before reaching these values.

When scale is 5 the cube jitters in place because itā€™s raycast is picking up the moving block itself as the closest obstacle.
Higher scale values 6-20 seem to under reach the target walls, additionally their distance values suddenly display very small by comparison to the lower scale values.

I even get different behavior depending on where i initially place the moving cube.

The only theory I have is that both the unscaled and the rescaled versions of the blocks exist in the scene graph and are interacting with the rays. Even though only the rescaled is visible. I donā€™t know if this can happen, but itā€™s the only thing I can think of.

I scale things in the scene all the time and donā€™t have problems picking them.

I donā€™t have time to run the code you posted but maybe if you posted the actual strange values you get then it would help when browsing it to see what the issue is. It could be one of perception or something else. When the whole scene is scaled it can be a little tricky to get the mental gymnastics right to keep track, I guess.

It is always uniform scaling, right? Not different x,y, or z?

The only time it is scaled is when everything is in place.
ā€œrootNode.scale(scale);ā€

So yeah, uniform.


scale set to 2.
This picture shows the cube right before it reverses direction after hitting what it thinks is the wall.
As you can see in the display, the output for the closest wall is w4, which is the wall directly behind it. So it really does think the wall is out there for some reason.


scale set to 3. Similar behavior to 2, but it goes out even further before reversing.


Scale set to 6.
Taken right before the cube reverses as it hits where it thinks the left wall is, which is much closer to the right wall this time than is displayed.

I should note that I get different behavior if i initially translate the cube to a different position than ā€œs.setLocalTranslation(5,-2f,5);ā€

Why this is I have no idea.

Just one noteā€¦ I noticed you are moving without factoring in tpf at all. Your speed and time steps will vary greatly because of this. I know it probably has nothing to do with your issue but it will cause you pretty serious problems down the line.

Instead of this:
Ray r = new Ray(s.getLocalTranslation(),dir);

Try:
Ray r = new Ray(s.getWorldTranslation(),dir);

1 Like

Thanks for the advice, that seems to have fixed it. Although I donā€™t really understand why.

Could you possibly explain why it was behaving that way when using the local translation?

I guess I donā€™t understand the difference between setlocaltranslation() setworldtranslation() and move().

The tutorials say the local translation is from the origin, but then what is world translation? why would it be different?

@UMS-kid said: Thanks for the advice, that seems to have fixed it. Although I don't really understand why.

Could you possibly explain why it was behaving that way when using the local translation?

I guess I donā€™t understand the difference between setlocaltranslation() setworldtranslation() and move().

The tutorials say the local translation is from the origin, but then what is world translation? why would it be different?

World translation takes into account any parent transforms, etc.

So, if you move a node via move to a local translation of 1,1,1
and then move itā€™s parent node to a local translation of 1,1,1
the child nodeā€™s world translation will reflect both. as itā€™s origin is now 1,1,1 and then it has been moved from this origin by 1,1,1

1 Like
@UMS-kid said: Thanks for the advice, that seems to have fixed it. Although I don't really understand why.

Could you possibly explain why it was behaving that way when using the local translation?

I guess I donā€™t understand the difference between setlocaltranslation() setworldtranslation() and move().

The tutorials say the local translation is from the origin, but then what is world translation? why would it be different?

As sort of stated by tonegod, because youā€™ve scaled the root node, any local translation under that is unscaled. 10 units scaled by 4 will look like 40 units but the local translation is still 10.

But if you try to collideWith(10) on the root node, will itā€™s going to ā€˜unscaleā€™ that for you and make it 2.5 instead.

Does that make sense? You needed to get the coordinates in something that made sense outside of rootNode. Youā€™d have to do the same with direction if you were basing it on the rotation of some node, for example.

1 Like
@pspeed said: As sort of stated by tonegod, because you've scaled the root node, any local translation under that is unscaled. 10 units scaled by 4 will look like 40 units but the local translation is still 10.

But if you try to collideWith(10) on the root node, will itā€™s going to ā€˜unscaleā€™ that for you and make it 2.5 instead.

Does that make sense? You needed to get the coordinates in something that made sense outside of rootNode. Youā€™d have to do the same with direction if you were basing it on the rotation of some node, for example.

May not be appropriate to ask this here but is completely related to the OPā€¦ I noticed this issue with the gui node and scaling. Any words of wisdom about how to deal with this scaling issue?

Thanks guys. I think Iā€™ve got it now.
I really appreciate the prompt, informative help.

@t0neg0d said: May not be appropriate to ask this here but is completely related to the OP... I noticed this issue with the gui node and scaling. Any words of wisdom about how to deal with this scaling issue?

Whatā€™s the issue?