www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem with gfm.math.matrix (some gamedevs out there ?)

reply Thomas <earthwormjimmy gmx.at> writes:
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
Sep 03 2020
next sibling parent drug <drug2004 bk.ru> writes:
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 ); ```
Sep 03 2020
prev sibling next sibling parent reply Mike Parker <aldacron gmail.com> writes:
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.
Sep 03 2020
parent Thomas <earthwormjimmy gmx.at> writes:
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!
Sep 03 2020
prev sibling parent Guillaume Piolat <first.name gmail.com> writes:
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.
Sep 04 2020