我正在将iOS上的OpenGL(OGL)移植到MetalKit(MTK)。我在应用的MetalKit版本中无法获得相同的显示。我修改了投影矩阵,以解决两个框架之间在“标准化设备坐标”中的差异,但是不知道要更改其他内容以获得相同的显示。有什么想法需要更改,以便从OpenGL移植到MetalKit?
我了解OGL与MTK的标准化设备坐标(NDC)不同:
-1 < z < 1
0 < z < 1
我修改了投影矩阵以解决NDC差异,如here所示。不幸的是,对投影矩阵的这种修改不会导致显示结果与旧的OGL代码相同。
我还在努力尝试其他尝试。
供参考,这里是一些其他背景信息:
(0, 0, 0)
处并朝(0, 0, -1)
方向看GLKMatrix4MakeFrustum
生成投影矩阵,并使用left
,right
,top
,bottom
和near=1
,far=1000
的屏幕边界[调试时我将场景剥离了下来,下面是两张图像,第一张来自旧版OGL代码,第二张来自MTK,都只显示了带有调试纹理和黑色背景的“地面”平面。
关于在MetalKit中获得相同显示所需的任何其他更改的想法,将不胜感激。
我试图提取与投影矩阵的计算和使用有关的代码:
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和MaxZ表示场景将进入的深度范围渲染,不用于剪辑。大多数应用都会将这些成员设置为0.0和1.0,以使系统能够渲染到深度缓冲区中深度值的整个范围。在某些情况下,您通过使用其他深度范围可以达到特殊效果。例如,要在游戏中渲染平视显示,您可以将两个值都设置为0.0强制系统渲染前景场景中的对象,或者您可以将它们都设置为1.0来渲染应该始终在后台。
应用程序通常将MinZ和MaxZ分别设置为0.0和1.0使系统渲染到整个深度范围。但是你可以使用其他值来实现某些效果。例如你可能会将两个值都设置为0.0,以强制所有对象进入前景,或将两者都设置为1.0,以将所有对象渲染到背景中。
不幸的是,此问题最终归因于顶点着色器中的一个错误,该错误将Z轴上的所有几何+1推入了视线。
对于任何将来的OpenGL到金属搬运工:上面的投影矩阵更改(考虑到归一化设备坐标的差异,就足够了。