2
\$\begingroup\$

I'm using Transform in a certain case where I want extracting/changing/preserving the components {position, scale, rotation} to be straightforward - I guess that is a benefit. But when it comes to multiplication, it looks like 3x4 Matrix will be more efficient (it appears to require fewer floating-point operations) and doesn't have lots of bizarre cases to worry about (see the following code from UE's FTransform::Multiply):

A->DiagnosticCheckNaN_All();
B->DiagnosticCheckNaN_All();

checkSlow(A->IsRotationNormalized());
checkSlow(B->IsRotationNormalized());

...
if (AnyHasNegativeScale(A->Scale3D, B->Scale3D))
{
    // @note, if you have 0 scale with negative, you're going to lose rotation as it can't convert back to quat
    MultiplyUsingMatrixWithScale(OutTransform, A, B);
}
else
{
    OutTransform->Rotation = B->Rotation*A->Rotation;
    OutTransform->Scale3D = A->Scale3D*B->Scale3D;
    OutTransform->Translation = B->Rotation*(B->Scale3D*A->Translation) + B->Translation;
}

Am I right about the efficiency of multiplication between the two? What are other PROs and CONs I'm missing?

I'm guessing there must be full articles on this topic already, but I failed to find any.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Have you considered keeping your components separate to gain their pros, and then building a matrix from them to use in composing transformations, so you get the pro of easy multiplication too? Every transformation library I know of does it this way — we don't have to abandon one or the other, we can get the pros of both. \$\endgroup\$
    – DMGregory
    Jul 19 at 11:29
  • \$\begingroup\$ @DMGregory That sounds nice, but costs extra memory of course. UE4 seems to be using the bare FTransform without a cached matrix, but with lots of SSE magic in which I am so inexperienced. I guess it performs just fine? \$\endgroup\$
    – Eugene
    Jul 20 at 7:59
  • 1
    \$\begingroup\$ We're talking about 48 bytes per 3x4 matrix on systems that have tens of gigabytes of RAM these days. 😉 And just because there's no matrix in an FTransform does not preclude Unreal from keeping a cached matrix in a separate structure for accelerating its scene graph transformations and rendering. I think it would need to do this, as the multiply code above does not correctly handle nested non-uniform scales and rotations (and cannot, due to the limits of TRS form discussed here). \$\endgroup\$
    – DMGregory
    Jul 20 at 11:47
2
\$\begingroup\$

I'm not sure I understand your question, but I would say that they are both the same thing.

We use 4x4 matrices to represent transformations, and due to the associative property of matrix multiplication, you can represent multiple affine transformations in a single matrix, and then apply that transformation to as many points as you want.

3x4 matrices are a special case of matrices that only allow you to represent rotations, scaling, and one translation at the end. Whether using 4x4 matrices or 3x4 matrices gives you a performance advantage is disputed, and can only be confirmed by thoroughly benchmarking your specific use case.

I'm not sure exactly which functionality this Transform you're using offers you, but in many cases it's just a class that decomposes a 4x4 (or 3x4) matrix, allows you to modify its components (translation, rotation, scaling) separately, before converting it back to a matrix. Decomposing and re-composing a matrix requires some computations, so it could be a good idea to try not to overuse it, but sometimes the benefits of added readability can be greater than the disadvantages of a small performance penalty, so I would suggest you use whatever makes the most sense to you, especially if this is a prototype, a learning project, or a personal project.

If you want to modify one of the components of the transformation, decomposing it might be the easiest way to do so. Multiplying by another matrix on the left or the right can also be used in some cases, but it may have a different meaning from what you're expecting. I would say that multiplying by a different matrix is a slightly faster operation, compared to decomposing, modifying and re-composing, especially when the different matrix is the same for many different operations.

Keep in mind that not all matrices can be decomposed into translation, rotation and scaling. There are many more types of affine transforms, and in particular, projection matrices, that are not made out of translations, rotations and scaling, so they obviously can't be decomposed into these components.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ I think OP is asking about the difference between storing two Vector3 and a Quaternion to storing a Matrix3x4 in the context of storing a game entity's transformation from origin within the scene. \$\endgroup\$
    – idbrii
    Jul 19 at 23:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.