google / mathfu

C++ math library developed primarily for games focused on simplicity and efficiency.
http://google.github.io/mathfu
Apache License 2.0
1.4k stars 188 forks source link

Ortho/Perspective matrices are different than from DirectX 9 Math library. #22

Open FrankStain opened 7 years ago

FrankStain commented 7 years ago

Hi there. Currently i have working on some test and found some unclear moments between Mathfu and DirectX Math. I know how the canonical perspective and orthographic matrices looks like. What i wondering is why DirectX Math uses different calculations for perspective and orthographic matrices? I work with DirectX Math almost 10 years and never had a problems with projection matrices.

For example i had run tests from 'matrix_test.cpp' for DirectX 9 Math and get next results.

Right-handed perspective
   ( atan( 1.0 ) * 2.0, 1.0, -2.0, 2.0 )
        Mathfu              DirectX9
| 1.0  0.0  0.0  0.0 | 1.0  0.0  0.0  0.0 |
| 0.0  1.0  0.0  0.0 | 0.0  1.0  0.0  0.0 |
| 0.0  0.0 -0.5 -1.0 | 0.0  0.0 -0.5 -1.0 |
| 0.0  0.0  2.0  0.0 | 0.0  0.0  1.0  0.0 |

Left-handed perspective
   ( atan( 1.0 ) * 2.0, 1.0, -2.0, 2.0 )
        Mathfu              DirectX9
| 1.0  0.0  0.0  0.0 | 1.0  0.0  0.0  0.0 |
| 0.0  1.0  0.0  0.0 | 0.0  1.0  0.0  0.0 |
| 0.0  0.0  0.5  1.0 | 0.0  0.0  0.5  1.0 |
| 0.0  0.0  2.0  0.0 | 0.0  0.0  1.0  0.0 |

Right-handed orthographic
      ( 1.0, 3.0, 1.0, 3.0, 1.0, 3.0 )
        Mathfu              DirectX9
| 1.0  0.0  0.0  0.0 | 1.0  0.0  0.0  0.0 |
| 0.0  1.0  0.0  0.0 | 0.0  1.0  0.0  0.0 |
| 0.0  0.0 -1.0  0.0 | 0.0  0.0 -0.5  0.0 |
|-2.0 -2.0 -2.0  1.0 |-2.0 -2.0 -0.5  1.0 |

Left-handed orthographic
      ( 1.0, 3.0, 1.0, 3.0, 1.0, 3.0 )
        Mathfu              DirectX9
| 1.0  0.0  0.0  0.0 | 1.0  0.0  0.0  0.0 |
| 0.0  1.0  0.0  0.0 | 0.0  1.0  0.0  0.0 |
| 0.0  0.0  1.0  0.0 | 0.0  0.0  0.5  0.0 |
|-2.0 -2.0 -2.0  1.0 |-2.0 -2.0 -0.5  1.0 |

This moment is crucial in cross-platform development perspective. In fact, the DirectX math library is good enough for using it on Windows desktop systems. But for portability purposes we need another math library. And Mathfu looks good enough to use it on other systems.

But that difference mixes the cards. Does the different calculations makes the real difference in results?

jsanmiya commented 7 years ago

Hey Franken, thanks for the question.

I looked into this too, a while back, when we added right/left-handed support. It's caused by a difference between DirectX and OpenGL.

MathFu creates OpenGL matrices, so they're slightly different than the DirectX matrices. If you compare MathFu to glm, however, you should notice that they're the same.

I agree it would be useful for cross-platform development to have support for DirectX, too. If you'd like to create a pull request with that support, I'd be very happy to take a look!

On Wed, May 3, 2017 at 3:35 AM, Franken notifications@github.com wrote:

Hi there. Currently i have working on some test and found some unclear moments between Mathfu and DirectX Math. I know how the canonical perspective and orthographic matrices looks like. What i wondering is why DirectX Math uses different calculations for perspective and orthographic matrices? I work with DirectX Math almost 10 years and never had a problems with projection matrices.

For example i had run tests from 'matrix_test.cpp' for DirectX 9 Math and get next results.

Right-handed perspective ( atan( 1.0 ) * 2.0, 1.0, -2.0, 2.0 ) Mathfu DirectX9 | 1.0 0.0 0.0 0.0 | 1.0 0.0 0.0 0.0 | | 0.0 1.0 0.0 0.0 | 0.0 1.0 0.0 0.0 | | 0.0 0.0 -0.5 -1.0 | 0.0 0.0 -0.5 -1.0 | | 0.0 0.0 2.0 0.0 | 0.0 0.0 1.0 0.0 |

Left-handed perspective ( atan( 1.0 ) * 2.0, 1.0, -2.0, 2.0 ) Mathfu DirectX9 | 1.0 0.0 0.0 0.0 | 1.0 0.0 0.0 0.0 | | 0.0 1.0 0.0 0.0 | 0.0 1.0 0.0 0.0 | | 0.0 0.0 0.5 1.0 | 0.0 0.0 0.5 1.0 | | 0.0 0.0 2.0 0.0 | 0.0 0.0 1.0 0.0 |

Right-handed orthographic ( 1.0, 3.0, 1.0, 3.0, 1.0, 3.0 ) Mathfu DirectX9 | 1.0 0.0 0.0 0.0 | 1.0 0.0 0.0 0.0 | | 0.0 1.0 0.0 0.0 | 0.0 1.0 0.0 0.0 | | 0.0 0.0 -1.0 0.0 | 0.0 0.0 -0.5 0.0 | |-2.0 -2.0 -2.0 1.0 |-2.0 -2.0 -0.5 1.0 |

Left-handed orthographic ( 1.0, 3.0, 1.0, 3.0, 1.0, 3.0 ) Mathfu DirectX9 | 1.0 0.0 0.0 0.0 | 1.0 0.0 0.0 0.0 | | 0.0 1.0 0.0 0.0 | 0.0 1.0 0.0 0.0 | | 0.0 0.0 1.0 0.0 | 0.0 0.0 0.5 0.0 | |-2.0 -2.0 -2.0 1.0 |-2.0 -2.0 -0.5 1.0 |

This moment is crucial in cross-platform development perspective. In fact, the DirectX math library is good enough for using it on Windows desktop systems. But for portability purposes we need another math library. And Mathfu looks good enough to use it on other systems.

But that difference mixes the cards. Does the different calculations makes the real difference in results?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/google/mathfu/issues/22, or mute the thread https://github.com/notifications/unsubscribe-auth/AF3McHouCtWsvBq8L7EFd8IzWRSrKzbmks5r2FhqgaJpZM4NPN9K .

FrankStain commented 7 years ago

@jsanmiya , thanks for response.

  • In DirectX, the z-near plane maps to -1. That is, DirectX depth clipping happens on z values in the [-1, 1] range.
  • In OpenGL, the z-near plane maps to 0. That is, OpenGL depth clipping happens on z values in the [0, 1] range.

I didn't thought about it. Can you help me providing some links to DirectX and OpenGL documentation about z plane mapping? Seems this information has eluded me.

What about PR for DirectX support, firstly i need to deeply understand the reasons of that difference. :) Potential visual difference must be avoided, as for me.

FrankStain commented 7 years ago

So, i had found the documents about transformation pipeline of Direct3D and OpenGL.

Direct3D Transformation pipeline OpenGL Transformation pipeline (another link)

I had found two interesting notes in Direct3D Transformation pipeline: First one:

Clipping volume for all points Xp = (Xp, Yp, Zp, Wp) in the projection space is defined as:

-Wp < Xp <= Wp
-Wp < Yp <= Wp
0 < Zp <= Wp

Second:

This transformation can provide increased precision and is equivalent to scaling and shifting the clipping volume.

The corresponding Mclip matrix is: Projection matrix

At one side we have z-plane mapping in (0, 1]. Is it that what @jsanmiya talking about? At another side we have note that such projection matrix is equal to regular one and can provide increased precision. Or am i wrong in my conclusions?

OpenGL transformation pipeline gives me only one interesting note:

The range of values is now normalized from -1 to 1 in all 3 axes. OGL NDC

And here is the difference between DirectX and OpenGL - the range of normalized Z coordinate.

It could be important if viewport specifications for both api had lack of z-near and z-far fields. But since we can change this range by viewport specification in both OpenGL and DirectX, i still can't figure out, how the difference in projection matrix can affect the picture.

Only note about additional precision still looks important enough to keep such difference. Seems, i need to make visual and mathematical tests on both api with both types of projection matrices. It could take long time...