[Potential Bug] ScreenCoordinates Errant Behavior away from World Origin

When moving my camera across the world scene, I have come across the following issue: when the camera is “far” away from the world origin, the object that is viewed starts “jumping” around erratically in the view port when rotating the camera.



When testing [java]cam.getScreenCoordinates(sphere.getWorldTranslation())[/java] the following is the results sequence when rotating the camera up:



[java]

06-07 07:40:24.539 I/pyramid.test.TestCase1(13496): obj: (240.0, 560.9476, 0.92592597)

06-07 07:40:24.554 I/pyramid.test.TestCase1(13496): obj: (240.0, 560.9476, 0.92592597)

06-07 07:40:24.570 I/pyramid.test.TestCase1(13496): obj: (240.0, 560.9476, 0.92592597)

06-07 07:40:24.593 I/pyramid.test.TestCase1(13496): obj: (240.0, 560.9476, 0.92592597)

06-07 07:40:24.609 I/pyramid.test.TestCase1(13496): obj: (240.0, 560.9476, 0.92592597)

06-07 07:40:24.632 I/pyramid.test.TestCase1(13496): obj: (240.0, 560.9476, 0.92592597)

06-07 07:40:24.648 I/pyramid.test.TestCase1(13496): obj: (10480.0, 552.34375, 0.9375)

06-07 07:40:24.671 I/pyramid.test.TestCase1(13496): obj: (-10000.0, 538.5417, 0.9166667)

06-07 07:40:24.695 I/pyramid.test.TestCase1(13496): obj: (240.0, 516.6667, 0.9583334)

06-07 07:40:24.710 I/pyramid.test.TestCase1(13496): obj: (-10000.0, 500.0, 0.9583334)

06-07 07:40:24.726 I/pyramid.test.TestCase1(13496): obj: (240.0, 470.83334, 0.9166667)

06-07 07:40:24.742 I/pyramid.test.TestCase1(13496): obj: (240.0, 458.33334, 0.9166667)

06-07 07:40:24.765 I/pyramid.test.TestCase1(13496): obj: (240.0, 450.0, 0.9375)

06-07 07:40:24.796 I/pyramid.test.TestCase1(13496): obj: (240.0, 412.2449, 0.9183673)

06-07 07:40:24.828 I/pyramid.test.TestCase1(13496): obj: (-10000.0, 387.5, 0.9166667)

06-07 07:40:24.835 I/pyramid.test.TestCase1(13496): obj: (240.0, 383.3333, 0.9270834)

06-07 07:40:24.859 I/pyramid.test.TestCase1(13496): obj: (240.0, 375.51022, 0.92346936)

06-07 07:40:24.875 I/pyramid.test.TestCase1(13496): obj: (240.0, 369.91846, 0.927031)

06-07 07:40:24.898 I/pyramid.test.TestCase1(13496): obj: (10271.0205, 367.34692, 0.92857146)

06-07 07:40:24.914 I/pyramid.test.TestCase1(13496): obj: (-9590.399, 376.0, 0.91999996)

06-07 07:40:24.929 I/pyramid.test.TestCase1(13496): obj: (240.0, 350.0, 0.9166667)

06-07 07:40:24.945 I/pyramid.test.TestCase1(13496): obj: (-10000.0, 333.3333, 0.9166667)

06-07 07:40:24.960 I/pyramid.test.TestCase1(13496): obj: (10480.0, 366.6667, 1.0)

06-07 07:40:24.976 I/pyramid.test.TestCase1(13496): obj: (240.0, 366.6667, 0.9166667)

06-07 07:40:24.992 I/pyramid.test.TestCase1(13496): obj: (10480.0, 366.6667, 1.0)

06-07 07:40:25.015 I/pyramid.test.TestCase1(13496): obj: (240.0, 333.3333, 0.9166667)

06-07 07:40:25.031 I/pyramid.test.TestCase1(13496): obj: (-10000.0, 333.3333, 0.9166667)

06-07 07:40:25.054 I/pyramid.test.TestCase1(13496): obj: (240.0, 200.0, 0.75)

[/java]



Please note the x coordinate changing erratically from 240.0 to arbitrary abs(values) ~ 10000.0.

At the same time, the camera position and rotation are remaining correct, so I can only deduct that it is somehow related to the viewPort coordinate processing. Supposedly it is not related to the float representing the world position, however conversion/casting issues might be a possible cause.



Here is my test case:



[java]

import com.jme3.app.SimpleApplication;

import com.jme3.light.DirectionalLight;

import com.jme3.material.Material;

import com.jme3.material.RenderState.BlendMode;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector3f;

import com.jme3.renderer.queue.RenderQueue.Bucket;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;

import com.jme3.scene.shape.Sphere;

import com.jme3.util.TangentBinormalGenerator;

import android.util.Log;



public class TestCase1 extends SimpleApplication {



Geometry sphere;



@Override

public void simpleInitApp() {



DirectionalLight sun = new DirectionalLight();

sun.setDirection(new Vector3f(1,0,-2).normalizeLocal());

sun.setColor(ColorRGBA.White);

rootNode.addLight(sun);



cam.setFrustumPerspective(45f,settings.getHeight()/settings.getWidth(),1f,1e2f);

cam.setLocation(new Vector3f(2e9f,0,2));



sphere = new Geometry(“sphere”, new Sphere(4,4, 2f));

Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“Color”,ColorRGBA.White);

sphere.setMaterial(mat);

sphere.setLocalTranslation(2e9f,2,-10);

rootNode.attachChild(sphere);

}



@Override

public void simpleUpdate(float tpf) {

//Log.i(this.getClass().getName(),"dir: " + cam.getDirection());

//Log.i(this.getClass().getName(),"pos: " + cam.getLocation());

Log.i(this.getClass().getName(),"obj: " + cam.getScreenCoordinates(sphere.getWorldTranslation()));

}



}

[/java]



This behavior applies to jME3 beta as well as the latest update.

How far from origin? You may be hitting floating point precision issues.

x = 2e9f, y = 0, z = 2



The erratic behavior on the x-coordinate would suggest that.

However, how would that be possible with a maximum float range of roughly 1e38f?



From Java's Primitive Data Types


4 bytes, IEEE 754. Covers a range from 1.40129846432481707e-45 to 3.40282346638528860e+38 (positive or negative).

You are mistaking range for precision. You may be able to represent a big number but you won’t be able to represent numbers to either side of it very precisely as all of the bits are used for the size of the number.



Floating point loses third or fourth decimal place precision pretty drastically above about 65,000 or so if I recall correctly.

1 Like

http://www.ibm.com/developerworks/java/library/j-math2/index.html



This explains a lot about how floating points work on computers and why you hit precision problems.



The solutions to your problem are either:

Convert JME3 to double (not as hard as it sounds although not completely trivial either). I know someone has done it but it’s not something I’ve tried myself so I don’t know how hard it was. It will make updating in future harder too but maybe you could liase with them to create a 64bit fork of JME3 that is kept up to date with new changes on a regular basis.



or

Translate the world around the camera rather than the other way around. So the camera is always at 0,0,0 and then you drop other stuff into nodes and move those nodes as the world moves. This approach is commonly used for space games which have relatively few other objects and very large distances.

@zarch said:
Convert JME3 to double (not as hard as it sounds although not completely trivial either). I know someone has done it but it's not something I've tried myself so I don't know how hard it was. It will make updating in future harder too but maybe you could liase with them to create a 64bit fork of JME3 that is kept up to date with new changes on a regular basis.


I think you are thinking of the person who converted bullet to 64 bit. Converting the physics engine to 64 bit makes a lot of sense and is relatively straight-forward. Converting JME to double is not so straight-forward since OpenGL will still be float.

1000x easier to use your second option. Just translate the root node instead of the camera. Even Mythruna does this because it makes paging easier.