从 OpenGL 移植到 MetalKit - 投影矩阵(?)问题

Porting from OpenGL to MetalKit - Projection Matrix (?) Problems

问题

我正在 iOS 上从 OpenGL (OGL) 移植到 MetalKit (MTK)。我无法在应用程序的 MetalKit 版本中获得相同的显示。我修改了投影矩阵以解决两个框架之间标准化设备坐标的差异,但不知道还需要更改什么才能获得相同的显示。有什么想法需要更改以从 OpenGL 移植到 MetalKit 吗?

到目前为止投影矩阵变化...

我了解 OGL 与 MTK 中的标准化设备坐标 (NDC) 不同:

我修改了投影矩阵以解决 NDC 差异,如 here 所示。不幸的是,这种对投影矩阵的修改不会导致与旧 OGL 代码相同的显示。

我什至不知道还能尝试什么。

背景

作为参考,这里有一些杂项背景信息:

我在调试时将场景简化为骨架,下面是两张图片,第一张来自遗留 OGL 代码,第二张来自 MTK,都只显示了带有调试纹理和黑色的 "ground" 平面背景。

任何关于在 MetalKit 中可能需要更改以实现相同显示的任何想法都将不胜感激。

截图

OpenGL(旧版)

金属套件

编辑 1

我试图提取与投影矩阵的计算和使用相关的代码:

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:&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];

如果没有看到代码,很难说出问题所在。最常见的问题之一可能是视口配置错误:

// Set the region of the drawable to draw into.
[renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, 0.0, 1.0 }];

视口的默认值为:

originX = 0.0
originY = 0.0
width = w
height = h
znear = 0.0
zfar = 1.0

*金属:znear = minZ,zfar = maxZ。

MinZ and MaxZ indicate the depth-ranges into which the scene will be rendered and are not used for clipping. Most applications will set these members to 0.0 and 1.0 to enable the system to render to the entire range of depth values in the depth buffer. In some cases, you can achieve special effects by using other depth ranges. For instance, to render a heads-up display in a game, you can set both values to 0.0 to force the system to render objects in a scene in the foreground, or you might set them both to 1.0 to render an object that should always be in the background.

Applications typically set MinZ and MaxZ to 0.0 and 1.0 respectively to cause the system to render to the entire depth range. However, you can use other values to achieve certain affects. For example, you might set both values to 0.0 to force all objects into the foreground, or set both to 1.0 to render all objects into the background.

遗憾的是,这个问题最终是由于顶点着色器中的一个错误造成的,该错误将所有几何体推到 Z 轴上 +1,导致视觉差异。

对于任何未来的 OpenGL 到 Metal 搬运工:以上投影矩阵的变化,考虑到规范化设备坐标的差异,就足够了。