0

I was trying to port some c++ code to C#, everything works except the perspective.

In c++ the code looks like this, which worked without distortion.

DirectX::XMMatrixTranspose(
                DirectX::XMMatrixRotationZ(100) *
                DirectX::XMMatrixRotationX(200) *
                DirectX::XMMatrixTranslation(0,0,4) *
                DirectX::XMMatrixPerspectiveLH(DirectX::XMConvertToRadians(180),pAdapter->aspectRatio,0.5f,10)

and the C# code like this

Matrix4x4.Transpose(
            Matrix4x4.CreateRotationZ(100) *
            Matrix4x4.CreateRotationX(200) *
            Matrix4x4.CreateTranslation(0, 0, 4) *
            Matrix4x4.CreatePerspective(1.39626f, 1.7777777777777777777777777777778f, 0.5f,10)
            );

I would assume both of these would do the exact same, but the C# code doesn't appear at all, when i remove the perspecitve it renders but everything is strecthed as expected.

I tried to remake the source of dxmath which resulted in this, it now renders as further away but its still stretched.

Matrix4x4 perspective = new Matrix4x4();
float ViewWidth = 1.39626f;
float ViewHeight = 1.7777777777777777777777777777778f;
float NearZ = 0.5f;
float FarZ = 10.0f;
float TwoNearZ = NearZ + NearZ;
float fRange = FarZ / (NearZ - FarZ);

perspective.M11 = TwoNearZ / ViewWidth;
perspective.M22 = TwoNearZ / ViewHeight;
perspective.M33 = fRange;
perspective.M43 = -fRange * NearZ;

data.matrix = perspective * data.matrix;

Im not really sure what the problem is, i read in another post that matrix4x4 is right handed so i tried the same with that one but it didn't render at all. Any help is appreciated.

  • Your perspective matrix implementation look strange to me. I suggest you try with another implementation, This one, for example: https://stackoverflow.com/questions/18404890/how-to-build-perspective-projection-matrix-no-api (notice you may have to adapt some detail since DirectX and OpenGL did not use the same coordinate system) –  May 31 '22 at 13:57
  • @Sedenion i tried to implement your suggestion but it did not render, maybe i did something wrong but i tried all the combinations. judging from this post directx doesn't use a set coordinate system anymore https://stackoverflow.com/questions/25525432/d3d11-coordinate-system and here is what i tried to implement from the dxmath source https://github.com/microsoft/DirectXMath/blob/main/Inc/DirectXMathMatrix.inl – TheMightyCat May 31 '22 at 14:16
  • since previous comment was too big already here is the code `float farDist = 10f; float nearDist = 0.5f; float frustumDepth = farDist - nearDist; float oneOverDepth = 1 / frustumDepth; perspective.M22 = (float)(1 / Math.Tan(0.5f * 180)); perspective.M11 = -1 * perspective.M22 / 1.7777777777777777777777777777778f; perspective.M33 = farDist * oneOverDepth; perspective.M43 = (-farDist * nearDist) * oneOverDepth; perspective.M34 = 1;` – TheMightyCat May 31 '22 at 14:19
  • Ok, never seen this before, but why not. One detail: You can notice that `perspective.M44` must be set to `0.0f`, unlike the default value of the identity matrix. In your code you don't explicitly set this value, Is it possible that it is left at `1.0f` ? –  May 31 '22 at 14:33
  • @Sedenion can't believe i missed that, works like a charm now, thanks!, if you want to post your comment as an answer ill mark it correct. – TheMightyCat May 31 '22 at 14:39
  • ``System.Numerics`` is based on XNA Game Studio's C# math functions, which used Right-Handed matrices. Your source DirectXMath code was explicitly using Left-Handed. – Chuck Walbourn Jun 02 '22 at 05:41

1 Answers1

0

The perspective matrix you use appear strange. I suggest you to use the more classical implementation from OpenGL documentation. Also, notice that you don't explicitly set the M44 value of your perspective matrix to 0.0f while this value is set to 1.0f for default identity matrix. This result in a wrong perspective matrix.

float frustumDepth = farDist - nearDist;  
float oneOverDepth = 1 / frustumDepth;

perspective.M22 = (float)(1.0f / Math.Tan(0.5f * fovRadians));
perspective.M11 = 1.0f * perspective.M22 / aspectRatio; 
perspective.M33 = farDist * oneOverDepth; 
perspective.M34 = 1.0f; 
perspective.M43 = (farDist * nearDist) * oneOverDepth; 
perspective.M44 = 0.0f;              //< replace 1.0f to 0.0f
  • The 0 was the solution for the code in the post you suggested, my implementation of the directx code still doesn't work, and setting it to 0 there is redundant anyway since it initializes as 0, the working code based on the post you suggested is is like this: – TheMightyCat May 31 '22 at 14:52
  • `float frustumDepth = farDist - nearDist; float oneOverDepth = 1 / frustumDepth; perspective.M22 = (float)(1 / Math.Tan(0.5f * fovRadians)); perspective.M11 = 1 * perspective.M22 / aspectRatio; perspective.M33 = farDist * oneOverDepth; perspective.M43 = (farDist * nearDist) * oneOverDepth; perspective.M34 = 1; perspective.M44 = 0;` – TheMightyCat May 31 '22 at 14:52
  • Ok ! so, I was correct when I found that perspective implementation strange... I edit my answers to prevent confusion –  May 31 '22 at 14:55
  • For an orthographic projection matrix (e.g. if using directional light shadows), then element `_44` is indeed 1.0f, and `_34` (row-major) is 0.0f. This is a way to easily identify the projection type. Also note that for right-handed perspective projections, `_34` (row-major) should be -1.0f. So that makes distinguishing projection matrix handedness (or _chirality_ as chemistry grads would say) trivial as well. – Maico De Blasio Jun 01 '22 at 03:49