'Incorrect results of simple coordinate transformation in UE4
I have a simple example:
FVector TransformTest()
{
FVector translation;
{
translation.X = 0.0f;
translation.Y = 20.0f;
translation.Z = 0.0f;
}
FRotator rotation;
{
rotation.Roll = 0.0f;
rotation.Pitch = 0.0f;
rotation.Yaw = 45.0f;
}
FVector scale;
{
scale.X = 2.0f;
scale.Y = 1.0f;
scale.Z = 1.0f;
}
FTransform test_transform = FTransform(rotation, translation, scale);
return (test_transform.Inverse() * test_transform).GetTranslation();
}
And this function will return vector:
[X = -10.0, Y = -10.0, Z = 0.0].
Expected:
[X = 0.0, Y = 0.0, Z = 0.0].
I am doing transform, for example, LocalToWorld then WorldToLocal, those i start from some space and must return back into this space (with small inaccuracies), but i finish my way in a strange space far away from the source.
I have submitted, as I think, a bug to Epic, and got a response:
Hello,
Thank you for submitting a bug report, however at this time we believe that the issue you are describing is not actually a bug with the Unreal Engine, and so we are not able to take any further action on this.
Is this behavior correct?
Is it a bug or not?
Solution 1:[1]
Actually, it looks like it impossible to solve (w/o major changes).
FTransform has decomposed transformation (translation, rotation, and scale). Applying it goes in order scale, rotation, and translation.
But inverted transformation must be applied in inverse order - reverse translation, rotation, and scale.
However, it's the same class and it doesn't have any information about application order.
It works fine with a uniform scale, but it's not correct for non-uniform. If you use non-uniform you'll have to use FMatrix.
Solution 2:[2]
A Unreal transform is basically a combination of a 3d scaling, rotation, and translation. In that order. In general, such a transformation can be inverted unless the scale is zero. That's what math is telling us. Such a 3d transformation is also a linear transformation, which can be represented by a 4x4 matrix, if the inversion exists (i.e. the determinant is not zero). However, the latter cannot be represented by a combination of scaling, rotation, and translation any longer, thus it cannot be represented by a Unreal transform. This is not a bug, this is math!
Here is why: For a uniform scale s the inversion is simple and it is obvious that it can be represented either by a 4x4 matrix or a Unreal transform, because (sRT)^-1 = T^-1 * R^-1 * 1/s = 1/s * R^-1 * (R * T^-1 * R^-1) = s' * R' * T', which is another Unreal transform.
For a non-uniform scale, which can be represented by a scaling matrix S, the inversion is of course still possible, but it cannot be represented by a Unreal transform, because (SRT)^-1 = T^-1R^-1S^-1 = R'*T'*S' != S'R'T'. It can still be represented by a 4x4 matrix, namely T^-1R^-1S^-1.
Speaking less mathematically: A Unreal Transform is a means of describing a scaling operation followed by a rigid body transformation. The inversion of a scaling followed by a rigid body transformation is the inverse of the rigid body transformation followed by a scaling. This cannot be described any longer by a scaling followed by a rigid body transformation, if the scaling is non-uniform. This would require a linear transformation, which can be represented by 4x4 matrix, but not with a Unreal transform.
So to conclude: A Unreal transform is not a 4x4 Matrix. A 4x4 Matrix is more powerful.
This appears to be a design flaw, since the problem can be easily circumvented by letting a Unreal transform be (S1RTS2), so that (S1RTS2)^-1 = S2^-1 * R^-1 * (R * T^-1 * R^-1) * S1^-1 = (S1'*R'*T'*S2'). If it is carefully implemented, it doesn't even need to impact performance, since Unreal transforms are just a way of describing scaled rigid body transformations, which have to be converted to 4x4 matrices at some point of the 3d graphics pipeline anyways.
This still does not solve the more general problem of concatenating two Unreal transforms with non-uniform scaling. But if we assume that only the left-most or right-most scaling is non-uniform, we end up with a useable solution, since the typical use case is indeed that we perform a scaling of a 3d model first and then position it in world space, followed by some additional rigid body transformations or uniform scalings. Such a transformation would be entirely invertable, if a Unreal transform would be equal to (S1RT*S2). Unfortunately it is not, so we need to use 4x4 matrices in that case.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
