Thread overview
Problem with gfm.math.matrix (some gamedevs out there ?)
Sep 03, 2020
Thomas
Sep 03, 2020
drug
Sep 03, 2020
Mike Parker
Sep 03, 2020
Thomas
Sep 04, 2020
Guillaume Piolat
September 03, 2020
Hi!

I am following some examples in C++ about how OpenGL is working. There are great tutorials out there and most of it works also with D.
For my code I am using gfm.math.matrix (Version 8.0.3) to be able to calculate the mouse position in a 3d world.
Now I have some problems with the projection matrix by inverting it.

My example code:
---------------------
import std.stdio;

int main()
{

    import gfm.math.matrix;

    const int width = 800;
    const int height = 600;

    auto projectionMatrix = mat4!(float).identity();
    auto ratio = cast(float)width / cast(float)height;

    projectionMatrix = mat4!(float).perspective( 45.0f, ratio, 0.0f, 100.0f );

    writeln("projectionMatrix: ", projectionMatrix );

    auto inversedMatrix = mat4!(float).identity();
    inversedMatrix = projectionMatrix.inverse();  // <-- why this does not work ?
    writeln("inversedMatrix: ", inversedMatrix );

    return 0;
}

The projection matrix will be calculated correctly with
[1.34444, 0, 0, 0, 0, 1.79259, 0, 0, 0, 0, -1, -0, 0, 0, -1, 0] assuming that the screen size is 800x600.

But using the .inverse() function in gfm returns only a matrix with following values:
[-nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, inf, -inf]

I don't know what I am doing wrong here:
  - do I call the function wrong way ? (but there is no other way)
  - is there a bug in the function ? (I do not believe that because the library is battle proved)

So I looked a couple of hours for an answer, but did not find anything useful.

Is somebody out there who could help me out ? Maybe one developer of the d gfm library ?

Thank you for you time!

Thomas
September 03, 2020
On 9/3/20 3:36 PM, Thomas wrote:
> Hi!
> 
> I am following some examples in C++ about how OpenGL is working. There are great tutorials out there and most of it works also with D.
> For my code I am using gfm.math.matrix (Version 8.0.3) to be able to calculate the mouse position in a 3d world.
> Now I have some problems with the projection matrix by inverting it.
> 
> My example code:
> ---------------------
> import std.stdio;
> 
> int main()
> {
> 
>      import gfm.math.matrix;
> 
>      const int width = 800;
>      const int height = 600;
> 
>      auto projectionMatrix = mat4!(float).identity();
>      auto ratio = cast(float)width / cast(float)height;
> 
>      projectionMatrix = mat4!(float).perspective( 45.0f, ratio, 0.0f, 100.0f );
> 
>      writeln("projectionMatrix: ", projectionMatrix );
> 
>      auto inversedMatrix = mat4!(float).identity();
>      inversedMatrix = projectionMatrix.inverse();  // <-- why this does not work ?
>      writeln("inversedMatrix: ", inversedMatrix );
> 
>      return 0;
> }
> 
> The projection matrix will be calculated correctly with
> [1.34444, 0, 0, 0, 0, 1.79259, 0, 0, 0, 0, -1, -0, 0, 0, -1, 0] assuming that the screen size is 800x600.
> 
> But using the .inverse() function in gfm returns only a matrix with following values:
> [-nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, inf, -inf]
> 
> I don't know what I am doing wrong here:
>    - do I call the function wrong way ? (but there is no other way)
>    - is there a bug in the function ? (I do not believe that because the library is battle proved)
> 
> So I looked a couple of hours for an answer, but did not find anything useful.
> 
> Is somebody out there who could help me out ? Maybe one developer of the d gfm library ?
> 
> Thank you for you time!
> 
> Thomas

1. zNear should not be equal to zero, this makes your matrix singular and inversion of singular matix is impossible so you get nans and infs. Make zNear a little bit more than zero and your code will work

2. FOV in perspective should be expressed in radians, not degrees

so this fixes your problem:
```
projectionMatrix = mat4!(float).perspective( 45.0f * 3.14 / 180., ratio, 0.01f, 100.0f );
```
September 03, 2020
On Thursday, 3 September 2020 at 12:36:35 UTC, Thomas wrote:

>
> My example code:
> ---------------------
> import std.stdio;
>
> int main()
> {
>
>     import gfm.math.matrix;
>
>     const int width = 800;
>     const int height = 600;
>
>     auto projectionMatrix = mat4!(float).identity();
>     auto ratio = cast(float)width / cast(float)height;
>
>     projectionMatrix = mat4!(float).perspective( 45.0f, ratio, 0.0f, 100.0f );
>
>     writeln("projectionMatrix: ", projectionMatrix );
>
>     auto inversedMatrix = mat4!(float).identity();
>     inversedMatrix = projectionMatrix.inverse();  // <-- why this does not work ?
>     writeln("inversedMatrix: ", inversedMatrix );
>
>     return 0;
> }

This is not the problem, but FYI these two lines are reduntant:

auto projectionMatrix = mat4!(float).identity();
auto inversedMatrix = mat4!(float).identity();

This is all you need:

auto projectionMatrix = mat4!(float).perspective( 45.0f, ratio, 0.0f, 100.0f );
auto inversedMatrix = projectionMatrix.inverse();

`perspective` and `inverse` return new instances that overwrite the two identity matrices you initialized, so you're doing work you don't need to do.



>
> The projection matrix will be calculated correctly with
> [1.34444, 0, 0, 0, 0, 1.79259, 0, 0, 0, 0, -1, -0, 0, 0, -1, 0] assuming that the screen size is 800x600.
>
> But using the .inverse() function in gfm returns only a matrix with following values:
> [-nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, inf, -inf]
>
> I don't know what I am doing wrong here:
>   - do I call the function wrong way ? (but there is no other way)
>   - is there a bug in the function ? (I do not believe that because the library is battle proved)
>

My guess is the problem is in the `inverse` implementation:

https://github.com/d-gamedev-team/gfm/blob/master/math/gfm/math/matrix.d#L448

T invDet = 1 / det;

It doesn't check if det is 0.

This shows 1f / 0f results in `inf`:

import std;
void main()
{
    float f = 0;
    float i = 1 / f;
    writeln(i);
}

https://run.dlang.io/is/ZyggRg

With all those zeroes in the perspective matrix and all the multiplications in the `inverse` function, I guess things are getting wonky.



September 03, 2020
On Thursday, 3 September 2020 at 13:31:01 UTC, Mike Parker wrote:
> On Thursday, 3 September 2020 at 12:36:35 UTC, Thomas wrote:
>
>>
>> My example code:
>> ---------------------
>> import std.stdio;
>>
>> int main()
>> {
>>
>>     import gfm.math.matrix;
>>
>>     const int width = 800;
>>     const int height = 600;
>>
>>     auto projectionMatrix = mat4!(float).identity();
>>     auto ratio = cast(float)width / cast(float)height;
>>
>>     projectionMatrix = mat4!(float).perspective( 45.0f, ratio, 0.0f, 100.0f );
>>
>>     writeln("projectionMatrix: ", projectionMatrix );
>>
>>     auto inversedMatrix = mat4!(float).identity();
>>     inversedMatrix = projectionMatrix.inverse();  // <-- why this does not work ?
>>     writeln("inversedMatrix: ", inversedMatrix );
>>
>>     return 0;
>> }
>
> This is not the problem, but FYI these two lines are reduntant:
>
> auto projectionMatrix = mat4!(float).identity();
> auto inversedMatrix = mat4!(float).identity();
>
> This is all you need:
>
> auto projectionMatrix = mat4!(float).perspective( 45.0f, ratio, 0.0f, 100.0f );
> auto inversedMatrix = projectionMatrix.inverse();
>
> `perspective` and `inverse` return new instances that overwrite the two identity matrices you initialized, so you're doing work you don't need to do.
>
>
>
>>
>> The projection matrix will be calculated correctly with
>> [1.34444, 0, 0, 0, 0, 1.79259, 0, 0, 0, 0, -1, -0, 0, 0, -1, 0] assuming that the screen size is 800x600.
>>
>> But using the .inverse() function in gfm returns only a matrix with following values:
>> [-nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, -nan, inf, -inf]
>>
>> I don't know what I am doing wrong here:
>>   - do I call the function wrong way ? (but there is no other way)
>>   - is there a bug in the function ? (I do not believe that because the library is battle proved)
>>
>
> My guess is the problem is in the `inverse` implementation:
>
> https://github.com/d-gamedev-team/gfm/blob/master/math/gfm/math/matrix.d#L448
>
> T invDet = 1 / det;
>
> It doesn't check if det is 0.
>
> This shows 1f / 0f results in `inf`:
>
> import std;
> void main()
> {
>     float f = 0;
>     float i = 1 / f;
>     writeln(i);
> }
>
> https://run.dlang.io/is/ZyggRg
>
> With all those zeroes in the perspective matrix and all the multiplications in the `inverse` function, I guess things are getting wonky.

Thank you very much! Both of you!
September 04, 2020
On Thursday, 3 September 2020 at 12:36:35 UTC, Thomas wrote:
> ---------------------
> import std.stdio;
>
> int main()
> {
>
>     import gfm.math.matrix;
>
>     const int width = 800;
>     const int height = 600;
>
>     auto projectionMatrix = mat4!(float).identity();

Note that instead of `mat4!(float)` you can just use `mat4f`.



>     auto ratio = cast(float)width / cast(float)height;
>
>     projectionMatrix = mat4!(float).perspective( 45.0f, ratio, 0.0f, 100.0f );

As others said, zNear is zero so your matrix is not invertible.
I guess perspective should warn about that.