Deprecating precision-losing GfMatrix4d methods in 24.08

tl;dr: We plan to deprecate functions that are known potential sources of precision loss in the 24.08 release and then remove these methods in 24.11. We welcome your feedback in this thread!

The type GfMatrix4d is commonly used in the Pixar pipeline to represent local-to-world transformations. When local space points are represented using the type GfVec3f, calls to functions such as GfMatrix4d::Transform can lose precision due to overloads that take and return values of type GfVec3f. Production experience has shown us this precision loss can be critical, e.g., due to large translations in local-to-world matrices that require points in world space to be represented with higher precision than is necessary in local space (which is presumably chosen so that the points are sufficiently close to the local origin).

In order to avoid this loss of precision, it is currently necessary to explicitly cast a GfVec3f argument to GfVec3d in order to select the overload that computes and returns a double-precision result; it is easy to call a lossy overload by accident. And when lost precision causes observable problems downstream, it can be very difficult and time-consuming to track down the source of the problem.

Therefore, we plan to deprecate functions that are known potential sources of precision loss (marking them as deprecated in the documentation and annotating the functions using the [[deprecated]] attribute) in the 24.08 release, and then to remove these methods in 24.11. Note that the above geometric interpretation doesn’t apply to all of the operations we are planning to deprecate, but for consistency, we plan to remove all methods and free functions that produce a float-valued vector from an operation on a float-valued vector and a double-valued matrix.

After the functions are removed (in 24.11), each client code site that was calling the old API will end up invoking a function that takes and returns a GfVec3d (or GfVec2d or GfVec4d), which in many cases will many that the client code will have to explicitly cast the result to the corresponding single-precision type. One benefit is that the loss of precision (which may or may not be significant to the client) will be explicit in the calling code.

The full list of functions to be deprecated is:

    GfVec3f GfMatrix4d::Transform(const GfVec3f &)
    GfVec3f GfMatrix4d::TransformAffine(const GfVec3f &)
    GfVec3f GfMatrix4d::TransformDir(const GfVec3f &)
    GfVec3f GfRotation::TransformDir(const GfVec3f &)
    GfVec2f operator*(const GfMatrix2d &, const GfVec2f &)
    GfVec2f operator*(const GfVec2f &, const GfMatrix2d &)
    GfVec3f operator*(const GfMatrix3d &, const GfVec3f &)
    GfVec3f operator*(const GfVec3f &, const GfMatrix3d &)
    GfVec4f operator*(const GfMatrix4d &, const GfVec4f &)
    GfVec4f operator*(const GfVec4f &, const GfMatrix4d &)

Let’s continue the discussion here with any questions or concerns you have!

I’m so sorry to say it’s a bad news to me.

We are using USD on mobile device, a memory limited enviroment, and we also need to load some large scale models, as large as possible. Our data model stores matricis as single precision, and it can save hundreds of megabytes of memory if we also use GfMatrix4f in our code.

Is it possible to warn users of the risks in some way? It would even be acceptable to require some sort of complexity or difficulty for users to continue using GfMatrix4f.

If I understood @arwoodbury’s post correctly, OpenUSD’s not deprecating anything related to GfMatrix4f, just the single precision methods and operators on GfMatrix4d.

1 Like

That’s correct, @nvmkuruc. This will only affect uses of GfMatrix4d (and GfMatrix3d and GfMatrix2d).

@wingfire, let me know if you still have concerns about how this may affect you!

Thanks for the explanation, @nvmkuruc, I should have read the original post more carefully. And also thank @arwoodbury to confirm it.

I have understood the purpose now, and the chage is totally fine to me.

@wingfire, sounds good! And no worries!

A brief update:

tl;dr: We have marked these functions as \deprecated in the documentation, but we no longer plan to annotate them with the [[deprecated]] attribute.

In order to avoid annoying error output for anyone who tried to take advantage of the deprecation, we wanted to remove all uses of the deprecated functions. But in this case, because these are deprecated overloads, avoiding invoking the deprecated functions involved some messy argument conversions. This got even messier in functions that were templated on the matrix type, requiring extra indirection to correctly handle all cases.

Rather than add messy temporary code, we now think it will be simpler to wait for the 24.11 release, when the deprecated functions will be removed. At that time, the compiler will select the remaining overload automatically. And in cases where the result needs to be converted to GfVec3f, the compiler will indicate the code sites that require fixing up.

Please continue to bring up and remaining questions or concerns here!