lookAt() is imprecise. How to fix?

When I do the following:

obj.lookAt(new THREE.Vector3(0,1,0));

I get:
Vector3 {x: 0, y: 0.999999995, z: 0.00009999999949994454}

As you can see, it is inaccurate.
I need to get the precise direction: (0,1,0)

How would I achieve that??
I even tried to round the rotation x,y,z to the nearest degree, however, the direction is still inaccurate.

This is precise from 3D point of view, since floating point arithmetics have a limited precision overall. .5 rounds previous digit up, so each of the .9 in 0.999999995 will round up, converging to a 1.0.

Similarly with 0.0000999..., becomes 0.0001, that last .1 rounds down, so the entire value converges to 0.0.

To use these values in operations - you can leave them as-is. If you’d like to display them in UI in a cleaner way, you can use Number.toFixed to limit the precision and apply rounding to that limited representation. Or if you want straight up integers, just Math.round - but that’ll work quite bad in 3D, as many values will just appear as 0.0, which won’t be true.

1 Like

The problem is that I am raycasting against the object, and these imprecise rotations will cause the raycast to get imprecise results.
I need to be able to set the object orientation precisely so that it doesn’t have these errors.

The problem is that your object has up vector (0,1,0). You cannot look at the up vector, because this will destroy a matrix. So, Three.js tries to get almost (0,1,0), but still to protect from matrix disaster.

If you really need (0,1,0), change the up vector to something else. Then you can lookAt precisely:

object.up.set(1,0,0); // change up vector
object.lookAt(new THREE.Vector3(0,1,0));
console.log(vector); // should be (0,1,0)
1 Like

What about when I look at -1,0,0
I get:
Vector3 {x: -1, y: 0, z: 2.220446049250313e-16}

So the up vector isn’t the issue in that case.

That’s another issue – this is an inherent floating point imprecision. It is not related to Three.js, but with the FPU. Whenever you have a lot of calculations, it is unavoidable to get such minor turbulence in the least significant digits of numbers.

To demonstrate:

  • the value 0.0001 is manually set by Three.js (see the image)
  • this value you see as 0.0000999… because 0.0001 cannot be represented exactly in binary form with any fixed number of bits


1 Like

I see. Well I guess I’ll need to approach all this differently if the numbers can’t be relied on and I can’t raycast against the object anymore since the intersection will be increasingly inaccurate the further away from the center of the object it is. I’m not sure how to solve it though, but I’ll keep thinking.

Do not worry. You cannot get further enough from the object. The GPU has brutally lower floating point precision than JS. If you try to step back 107 units, the GPU will collapse. And 107 is 1 000 000 000 times smaller than 1016.

1 Like