title: Porting from OpenGL to MetalKit - Projection Matrix (?) Problems
body: <h3>Question</h3>
  
  <p>I'm working on porting from OpenGL (OGL) to MetalKit (MTK) on iOS. I'm failing to get identical display in the MetalKit version of the app. I modified the projection matrix to account for differences in Normalized Device Coordinates between the two frameworks, but don't know what else to change to get identical display. Any ideas what else needs to be changed to port from OpenGL to MetalKit?</p>
  
  <h3>Projection Matrix Changes so far...</h3>
  
  <p>I understand that the Normalized Device Coordinates (NDC) are different in OGL vs MTK:</p>
  
  <ul>
  <li>OGL NDC: <code>-1 &lt; z &lt; 1</code></li>
  <li>MTK NDC: <code>0 &lt; z &lt; 1</code></li>
  </ul>
  
  <p>I modified the projection matrix to address the NDC difference, as indicated <a href="https://metashapes.com/blog/opengl-metal-projection-matrix-problem/" rel="nofollow noreferrer">here</a>. Unfortunately, this modification to the projection matrix doesn't result in identical display to the old OGL code.</p>
  
  <p>I'm struggling to even know what else to try.</p>
  
  <h3>Background</h3>
  
  <p>For reference, here's some misc background information:</p>
  
  <ul>
  <li>The view matrix is very simple (identity matrix); i.e. camera is at <code>(0, 0, 0)</code> and looking toward <code>(0, 0, -1)</code></li>
  <li>In the legacy OpenGL code, I used <code>GLKMatrix4MakeFrustum</code> to produce the projection matrix, using the screen bounds for <code>left</code>, <code>right</code>, <code>top</code>, <code>bottom</code>, and <code>near=1</code>, <code>far=1000</code></li>
  </ul>
  
  <p>I stripped the scene down to bare bones while debugging and below are 2 images, the first from legacy OGL code and the second from MTK, both just showing the "ground" plane with a debug texture and a black background.</p>
  
  <p>Any ideas about what else might need to change to get to identical display in MetalKit would be greatly appreciated.</p>
  
  <h3>Screenshots</h3>
  
  OpenGL (legacy)
  
  <p><a href="https://i.stack.imgur.com/mx4Ma.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/mx4Ma.jpg" alt="OpenGL Scene"></a></p>
  
  MetalKit
  
  <p><a href="https://i.stack.imgur.com/s3xfZ.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/s3xfZ.jpg" alt="MetalKit Scene"></a></p>
  
  <h3>Edit 1</h3>
  
  <p>I tried to extract code relevant to calculation and use of the projection matrix:</p>
  
  <pre><code>float aspectRatio = 1.777; // iPhone 8 device
  float top = 1;
  float bottom = -1;
  float left = -aspectRatio;
  float right = aspectRatio;
  float RmL = right - left;
  float TmB = top - bottom;
  float nearZ = 1;
  float farZ = 1000;
  
  GLKMatrix4 projMatrix = {   2 * nearZ / RmL,     0,                      0,                               0,
                              0,                   2 * nearZ / TmB,        0,                               0,
                              0,                   0,                      -farZ / (farZ - nearZ),          -1,
                              0,                   0,                      -farZ * nearZ / (farZ - nearZ),  0 };
  
  GLKMatrix4 viewMatrix = ...; // Identity matrix: camera at origin, looking at (0, 0, -1), yUp=(0, 1, 0);
  GLKMatrix4 modelMatrix = ...; // Different for various models, but even when this is the identity matrix in old/new code the visual output is different
  GLKMatrix4 mvpMatrix = GLKMatrix4Multiply(projMatrix, GLKMatrix4Multiply(viewMatrix, modelMatrix));
  
  ...
  
  GLKMatrix4 x = mvpMatrix; // rename for brevity below
  float mvpMatrixArray[16] = {x.m00, x.m01, x.m02, x.m03, x.m10, x.m11, x.m12, x.m13, x.m20, x.m21, x.m22, x.m23, x.m30, x.m31, x.m32, x.m33};
  
  // making MVP matrix available to vertex shader
  [renderCommandEncoder setVertexBytes:&amp;mvpMatrixArray
                                length:16 * sizeof(float)
                               atIndex:1]; // vertex data is at "0"
  
  [renderCommandEncoder setVertexBuffer:vertexBuffer
                                 offset:0
                                atIndex:0];
  
  ...
  
  [renderCommandEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
                           vertexStart:0
                           vertexCount:4];
  </code></pre>