Orientation is being rounded

part = workspace:WaitForChild('Part')
local rotation = -179.999991348578
part.CFrame = part.CFrame:ToObjectSpace(CFrame.Angles(0, math.rad(rotation), 0))
local x,y,z = part.CFrame:toEulerAnglesYXZ() 
print(math.deg(x), math.deg(y), math.deg(z))
print(part.Orientation)

will print:

-0 -179.999991348578 0
0, -180, 0

9 Likes

Is this really a problem? try with -179.51, and if it gets rounded, then thats a problem, but this just seems like a floating point error

4 Likes

I think this’s problem, because it can make huge impact if you need very precise numbers.

3 Likes

EDIT. In the light of your reply, I reconsidered and edited the post. Apologies for the inconvenience. The rest of the post is now just some observations. What you mentioned definitely deserves to be looked over.


  1. Bloxxy213_DVL is right in a sense that floating point error, related to number storing limitations is the root of small discrepancies in calculations and the reason why angles in lua can never be completely precise. Some angles are also numbers whose decimal expansion doesn’t terminate (infinite patterns). Meaning rounding is mandatory at some point, but that’s not really related to the matter.

  2. Orientation is relatively accurate representation of the three orientational vectors in degrees. In properties window it is truncated to 3 digits (for reasons explained in the quote).

  1. In code, indexing BasePart.Orientation returns a number rounded to 2 digits. Not too sure why, but it would probably make sense to return the same value Orientation among the properties shows.

  2. Orientation is a hidden property and there’s no such thing as CFrame.Orientation (there is CFrame.Rotation though. I’d say it was not intended to be used for working with CFrames in scripts (and it’s a read-only property).

I thought that Orientation is a truncated version and ToOrientation(), ToEulerAnglesXYZ() and ToEulerAnglesYXZ() are counterparts that calculate to more decimals, but are not necessary much more precise, because they return approximate angles “that could be used to generate the CFrame…” (CFrame | Documentation - Roblox Creator Hub).

So I wagered it was highly unlikely the engineers were not aware of this.

If you ever used ToOrientation() in a camera script, you probably also had to use a function to find the corrected angle according to previous one because it’s rather unfeasible to find completely accurate angles.

-179.994 --> -179.99 (plus the floating point error)
-179.995 --> -180

On the other hand,

if we were to compare angles, we can’t ever compare without rounding. Floating point imprecision is going to appear even when using integers, so any representation in degrees is very close to what CFrame.Rotation is at best.

image

So the workaround is having a separate variable “for counting”, or tolerating some absolute error of maybe +-0.1 or so.

Additionally,

it’s not uncommon to experience subtle (to an eye invisible) CFrame differences between server and client, caused by CFrame compression before it’s sent over the network in order to save some bandwidth.

EDIT 2.

Here’s an example where ToOrientation() isn’t completely equal to the original value.

local part = workspace.Part
part.CFrame = CFrame.new(0,5.123456789,0) * CFrame.Angles(0,math.rad(175.987654321),0)

local z,y,x = part.CFrame:ToOrientation()

print(part.Position) --> equal to the below print
print(part.CFrame.Position)
print(part.Orientation.Y) --> 175.99000549316406
print(math.deg(y)) --> 175.98765136216736
4 Likes

You cannot justify the unjustifiable.
The fact is simple: Orientation and CFrame must be exactly the same.
In the example I put, telling that it is a floating point error does not fit, because I already do conversions with CFrame:ToObjectSpace and CFrame:toEulerAnglesYXZ and even so the original number (-179.999991348578) is perfectly preserved between conversions, the which does not occur with Orientation.

2 Likes

Have you ever noticed even position is rounded up on the 5th decimal place? Same thing goes with orientation. A part does not have that precision ever after you set it. It’s not necessary and hurts performance.

EDIT: Sorry, should have read more, didn’t realize lol

2 Likes

The problem being highlighted is that there’s a difference between printing the degree-representation of a CFrame’s rotational component differs from printing its Orientation (a Vector3). The former retains the imprecision while the latter is rounded, making them not-equal.

I wager this might be a difference in representation (Orientation is not Euler angles) but I don’t know enough about this topic to make a definitive answer. That being said, “It’s not necessary and hurts performance” is irrelevant because this has no implications on either, and speculation doesn’t really point towards if this is intentional or not. Would love to see sources and/or research if you know otherwise that this is intended behaviour that isn’t just eyeballing properties.

3 Likes

This is not a bug.

This arises from the fact that the angle you’re using is a Lua number, which is represented with a 64-bit double, while Vector3s / CFrames used by the engine have components which are 32-bit floats.

Also, they’ll never be exactly equal because doing the ToObjectSpace transform will introduce some amount of floating point error.

8 Likes

Makes sense. If I may, I’d just like to ask something regarding a subtle observation from my reply above.

Orientation in the properties is truncated to three digits (e.g. 50.958) while indexing in a script returns the same but truncated to two (such as 50.96 in this case). This is something very minor and insignificant, but it may be the reason why some would think of this as a bug and not the same info. Is there any particular reason for indexing to not yield the same number? On the contrary, BasePart.Position and CFrame.Position match.

1 Like

How are you even still seeing the Orientation property? The only thing visible now is the orientation part of the CFrame (part.CFrame:ToOrientation()), the orientation property is really just a leftover from before the properties pane could display CFrames.

1 Like

Sorry, I meant Orientation as part of the CFrame property (not a standalone Orientation from old studio versions).

image

I know it’s a read-only property and normally we don’t even use it in the code, but running the OP’s code, that orientation property above showed slightly different results than indexing part.Orientation, such as (on y-axis) -180 vs -179.966 when using angle 179.996, for example. In some other cases before it appeared like part.Orientation is additionally truncated version of what Orientation as part of CFrame property displayed, but not I’m realizing they are probably unrelated and affected by floating point imprecision too. Sorry if I wasted your time.

1 Like

No, it’s a fair point.

I’m making an API change proposal anyways to have it not never show -180 for orientations orientations (it should show +180 instead), I might as well throw in it rounding to three digits instead of two for consistency.

4 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.