Why there is Slight Discrepancy Between mesh.position and mesh.getAbsolutePosition()?

Hello Babylon.js community,

I’m encountering a slight difference between the values returned by mesh.position and mesh.getAbsolutePosition(). In my case, mesh.position shows {x: 0.01, y: 0.01, z: 100.01}, but mesh.getAbsolutePosition() returns {x: 0.009999999776482582, y: 0.009999999776482582, z: 100.01000213623047}.

I understand that getAbsolutePosition() should account for transformations in the parent hierarchy, but in this scenario, the mesh isn’t part of any parent structure that would explain such discrepancies. Is this just a result of floating-point precision errors, or could there be other factors in Babylon.js affecting these values?

My main concern is to ensure that these values are synced perfectly. Could anyone suggest how to align mesh.position & mesh.getAbsolutePosition() & mesh.setAbsolutePosition() so they match exactly, or any workarounds to mitigate this issue?

Any insights into what could cause this discrepancy and how to sync the values would be greatly appreciated!

Thank you!

This is all due to maths precision in js I guess.

wondering what values would be in the parent transforms and such

Can you share in a playground ?

here we go : https://playground.babylonjs.com/#7KCWJ1#2
just 4 lines
var mesh = BABYLON.MeshBuilder.CreateBox(“mesh”,{size:10, updatable:true}, scene, );
var vec = new BABYLON.Vector3(0.00101, 0.002, 0.003)
mesh.setAbsolutePosition(vec);
mesh.computeWorldMatrix(true)

More concise: https://playground.babylonjs.com/#7KCWJ1#3

As far as I can see “absolutePosition” is auto assigned by computeWorldMatrix. This is a huge function though doing a lot of matrix stuff… :flushed:

Anyway, this should not be expected behaviour. Without having touched scaling or rotation or the the mesh not being in a parent-child relationship, it should be position === absolutePosition.

1 Like

It is a floating point thing: https://playground.babylonjs.com/#7KCWJ1#4

Question is: if the floating point error is expected in Javascript, should Babylon “fix” it (thereby changing the expectation imposed by Javascript)?


Audit trail:

Thank you Joe, It makes sense

This is expected in most languages when dealing with floating point arithmetic, try 0.2 + 0.1 in javascript

“fixing it”, while technically possible, would put performance into the toilet.
It’s better to recognize that it exists and code around it, (use epsilon’s, lesser/greater than, etc)

1 Like

This is not the use case here. My local position is 0.2. I merely assign and can assert it is 0.2. Yet absolutePosition is not (given the context outlined above).

I mean like

if(mesh.parent === null) {
   this._absolutePosition.copyFrom(mesh.position);
}

Well, or as you said, be be pragmatic :smiley:

My $.02 would be to not fix it in core (more than the parent check) and instead make sure that the utilities are available. E.g. a utility method is_equal_within_epsilon would be useful. You also may want to add either an extension or an example of a class that extends Mesh to produce fixed results.

Then people who need performance and can accept quirks can use the core class. People who need predictability and consistency more can used the fixed class instead.

From a user standpoint, an extension would be better. Then you can include it in your unit tests and maintain it going forward. From a maintenance standpoint, obviously an example would be easier. You could probably better estimate how much easier than I could.

1 Like

.55*100 = 55.00000000000001

this tickled me recently

Ask and you shall recieve (knowledge) :smile:

BABYLON.Scalar.WithinEpsilon(numberA, numberB, epsilon)
vector2.equalsWithEpsilon(otherVector2, epsilon)
vector3.equalsWithEpsilon(otherVector3, epsilon)

There’s no real reason to change how babylon acts right now, it is IMO the correct method.

Say you want to display a number that can be a float, to the end user of your application, and it should look clean, the solution is to just round it to a certain decimal point.

function sanitizeNb(nb, precision = 100){
    return Math.round(nb*precision)/precision;
}

console.log( sanitizeNb(0.1 + 0.2) ) // 0.3
console.log( sanitizeNb(0.55*100) ) // 55
console.log( sanitizeNb(0.123456789) ) // 0.12
2 Likes