So I've just noticed that when rotating a mesh that the scale sneaks up slowly over time:

extends MeshInstance3D

func _ready():
	print(scale.x) #Outputs: 1.0

func _process(delta: float) -> void:
	rotate_y(delta)
	print(scale.x) #Outputs: 1.00000011920929 and climbing with every frame,
                       #1.00003898143768 after only a about a minute!

I assume this is floating point imprecision causing the issue, but why does the rotation affect the scale at all, and why is the position totally unaffected?

Any insight would be great!

  • xyz replied to this.

    schme16 but why does the rotation affect the scale at all

    They're both represented by the 3 basis vectors in node's transformation matrix.

    Normalize the basis if the error becomes too large, or after every rotation:
    basis = basis.orthonormalized()

      xyz
      I figured it must have been something like that, but had assumed the position would get affected too, haha.
      I'm actually writing a geckos.io (nodejs webrtc server) compatible webrtc multiplayer library, and until I learn enough to use the built in webrtc multiplayer peer I'm just going to roll my own sync, and part of the most basic optimisations is, of course, only sending data when it's changed, but because scale is jittering/increasing it ends up being sent every tick regardless, so I end up doing a trim op on the values.
      Is the basis correction func above particularly heavy to run, as in, if dozens of objects did this every physics frame how much would you expect it to hurt performance?
      Or is there another way I should be testing for changes in pos/rot/scale?

      • xyz replied to this.

        schme16 Is the basis correction func above particularly heavy to run, as in, if dozens of objects did this every physics frame how much would you expect it to hurt performance?

        Shouldn't be heavy at all. Run the profiler with your typical use case and check.

        If you don't want to do it every frame, store the wanted scaling in a custom property and then check the difference between that and actual scaling. If it goes beyond some tolerance value, normalize and then assign that custom scale property to the actual one.

        Alternatively you can just normalize every N frames, with a frame offset for different objects so it doesn't all happen on the same frame.

        Bruteforce normalizing each frame should be fine though for a reasonably small (in ballpark of 100s) number of objects. There's no much calculation behind orhonormalize(). It's just a couple of dot and cross products.

          schme16 And yeah, position won't be affected by this due to how transforms are stored in the standard 4x4 matrix. Rotation and scaling are "encoded" together into 9 elements (aka the basis), while position uses 3 different elements. So rotation and scaling precision errors will always affect each other but neither will affect translation.

            xyz Good to know!

            xyz Fantastic to know that the baseline load should be fairly low even in a, as you say, bruteforce attempt!
            I'll definitely take the advice of setting up a dummy exemplar scene and profile it's performance cost!

            I really appreciate the time you've taken to walk through all of this with me!