Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Support for Matrix Inverse Function #4115

Open
scratchapixel opened this issue May 15, 2023 · 9 comments
Open

Feature Request: Support for Matrix Inverse Function #4115

scratchapixel opened this issue May 15, 2023 · 9 comments
Labels
feature request A request for a new GPU feature exposed in the API wgsl WebGPU Shading Language Issues
Milestone

Comments

@scratchapixel
Copy link

It would be great to consider having a builtin inverse() function for matrices in WGLS.

As pointed out in this comment, it is supported by other APIs.

While it has been argued that this function is potentially expensive and that they are other ways by which a user of the API could pass on the inverse of a given matrix to a shader (including writing your own function in a shader itself), it seems like having a built-in function could be super convenient at times:

  • for API users who feel uncomfortable writing a bug-free, robust inverse matrix function. To democratize the use of WebGPU/WGSL, it might be good to offer such people a ready-to-use method.
  • For a quick prototype. For more experienced users, you sometimes just want to test something quickly, and having this method in the library can be handy.

Note that while these are very different functions, WGSL already supports transpose(). Many users will thus expect to also see inverse() supported.

@scratchapixel scratchapixel added the wgsl WebGPU Shading Language Issues label May 15, 2023
@kainino0x kainino0x added the feature request A request for a new GPU feature exposed in the API label May 15, 2023
@kainino0x kainino0x added this to the post-V1 milestone May 15, 2023
@litherum
Copy link
Contributor

What should non-invertible matrices return? Presumably, this would use some kind of yet-to-be-standardized optional<> feature?

@magcius
Copy link

magcius commented May 23, 2023

transpose is extremely cheap (less than cheap, it"s often free!) while inverse is extremely expensive. The table linked is incorrect; it is supported by GLSL, and by extension, SPIR-V (OpMatrixInverse). It is not supported by HLSL or MSL due to its large cost.

@ezorzin
Copy link

ezorzin commented Jun 27, 2023

What should non-invertible matrices return? Presumably, this would use some kind of yet-to-be-standardized optional<> feature?

I suggest the return for that case might be a matrix having all entries set to zero, let"s call it "null matrix". All invertible matrices have a non-zero determinant: a null matrix has the determinant = 0, so it is fundamentally different from all invertible matrices and it is easy to detect.
The rationale is: imagine you have a non-null vector u and you want to calculate something like:
v = inverse(M)*u
having M a non invertible matrix.

In this case, with the proposed definition, the result would be v = (0, 0, 0): this will not make explode the calculations and it is easy to detect that something went wrong (-->M was not invertible) because normally you don"t expect to have a null vector out of a matrix to vector multiplication without having deliberately used a null-matrix in that multiplication.

By the way, with the same rationale I also suggest the normalize function applied to any type should return a null type (null vector, or null matrix) when its argument is a null type (null vector or null matrix).

@litherum
Copy link
Contributor

litherum commented Aug 7, 2023

I suggest the return for that case might be a matrix having all entries set to zero

Is there prior art for this?

@litherum
Copy link
Contributor

For comparison: the docs for CGAffineTransformInvert() say:

If the affine transform passed in parameter t cannot be inverted, the affine transform is returned unchanged.

@litherum
Copy link
Contributor

rdar://113945650 is a feature request for an inverse function in MSL

@ezorzin
Copy link

ezorzin commented Aug 16, 2023

I suggest the return for that case might be a matrix having all entries set to zero

Is there prior art for this?

I don"t know. GLSL leaves it "undefined" (https://docs.gl/sl4/inverse), which is not very satisfactory.

@trbabb
Copy link

trbabb commented Jul 31, 2024

Casting my vote for this to be implemented. Sure, users could paste code that does it, but writing a correct, efficient, ~numerically stable inverse function is nontrivial. It would be good to have a "correct" implementation as part of the library.

I"m not much moved by the objection that "it"s expensive". It"s the programmer"s job to decide whether calling the function is worth it in their application. I"d resent a language design for denying me an essential primitive because it thinks I can"t be trusted to optimize my own code.

@greggman
Copy link
Contributor

greggman commented Aug 2, 2024

regardless of whether or not it gets added, if it was added it would likely not happen for quite a while. Browsers are still trying to ship version 1.0.

In the meantime, feel free to post snippets here for solutions today. Here"s one (no idea what issues it has).

  fn inverse(m: mat4x4f) -> mat4x4f {
    let a00 = m[0][0]; let a01 = m[0][1]; let a02 = m[0][2]; let a03 = m[0][3];
    let a10 = m[1][0]; let a11 = m[1][1]; let a12 = m[1][2]; let a13 = m[1][3];
    let a20 = m[2][0]; let a21 = m[2][1]; let a22 = m[2][2]; let a23 = m[2][3];
    let a30 = m[3][0]; let a31 = m[3][1]; let a32 = m[3][2]; let a33 = m[3][3];

    let b00 = a00 * a11 - a01 * a10;
    let b01 = a00 * a12 - a02 * a10;
    let b02 = a00 * a13 - a03 * a10;
    let b03 = a01 * a12 - a02 * a11;
    let b04 = a01 * a13 - a03 * a11;
    let b05 = a02 * a13 - a03 * a12;
    let b06 = a20 * a31 - a21 * a30;
    let b07 = a20 * a32 - a22 * a30;
    let b08 = a20 * a33 - a23 * a30;
    let b09 = a21 * a32 - a22 * a31;
    let b10 = a21 * a33 - a23 * a31;
    let b11 = a22 * a33 - a23 * a32;

    let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;

    return mat4x4f(
        a11 * b11 - a12 * b10 + a13 * b09,
        a02 * b10 - a01 * b11 - a03 * b09,
        a31 * b05 - a32 * b04 + a33 * b03,
        a22 * b04 - a21 * b05 - a23 * b03,
        a12 * b08 - a10 * b11 - a13 * b07,
        a00 * b11 - a02 * b08 + a03 * b07,
        a32 * b02 - a30 * b05 - a33 * b01,
        a20 * b05 - a22 * b02 + a23 * b01,
        a10 * b10 - a11 * b08 + a13 * b06,
        a01 * b08 - a00 * b10 - a03 * b06,
        a30 * b04 - a31 * b02 + a33 * b00,
        a21 * b02 - a20 * b04 - a23 * b00,
        a11 * b07 - a10 * b09 - a12 * b06,
        a00 * b09 - a01 * b07 + a02 * b06,
        a31 * b01 - a30 * b03 - a32 * b00,
        a20 * b03 - a21 * b01 + a22 * b00) * (1 / det);
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request A request for a new GPU feature exposed in the API wgsl WebGPU Shading Language Issues
Projects
None yet
Development

No branches or pull requests

7 participants