我正在使用以下代码创建正交矩阵:
Matrix4D Matrix4D::fromOrtho(double left, double right, double bottom, double top, double nearZ, double farZ)
{
double ral = right + left;
double rsl = right - left;
double tab = top + bottom;
double tsb = top - bottom;
double fan = farZ + nearZ;
double fsn = farZ - nearZ;
return Matrix4D ( 2.0f / rsl, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f / tsb, 0.0f, 0.0f,
0.0f, 0.0f, -2.0f / fsn, 0.0f,
-ral / rsl, -tab / tsb, -fan / fsn, 1.0f);
}
并使用以下参数:
double widthToHeightRatio = screenWidth / screenHeight;
Matrix4D::fromOrtho(-10, 10, -7, 7 ,0.1, 5000);
左侧、右侧、底部和顶部参数实际上是作为相机眼睛和中心坐标的函数计算的,但这是结果参数的一个示例。
同样的矩阵可以很好地与OpenGL配合使用,但不能与Metal配合使用。当矩阵是透视矩阵时,在Metal中一切都很好。
可能是什么问题?
GL的透视矩阵和正交投影矩阵在Metal中都无效,因为z范围不同。有些矩阵可能仍然有效,因为OpenGL中的z剪辑范围太深,所以它恰好足够深,可以让碎片在Metal中通过,但这是一件不好的事情。
来自《金属编程指南》,第51页"使用视口和像素空间坐标":
Metal将其标准化设备坐标(NDC)系统定义为2x2x1立方体,其中心位于(0,0,0.5)。x的左侧和底部NDC系统的x和y分别被指定为-1。权利NDC系统的x和y的顶部分别指定为+1.
这与OpenGL不同,OpenGL在2x2x2立方体中的z从-1到1。
有关更多详细信息,请参阅此博客文章:http://blog.athenstean.com/post/135771439196/from-opengl-to-metal-the-projection-matrix
更新--用户da1发现了另一篇博客文章,上面的内容当前已关闭:http://metashapes.com/blog/opengl-metal-projection-matrix-problem
来自AAPLTransfer。mm这对我有效(金属样品项目)
simd::float4x4 AAPL::ortho2d(const float& left,
const float& right,
const float& bottom,
const float& top,
const float& near,
const float& far)
{
float sLength = 1.0f / (right - left);
float sHeight = 1.0f / (top - bottom);
float sDepth = 1.0f / (far - near);
simd::float4 P;
simd::float4 Q;
simd::float4 R;
simd::float4 S;
P.x = 2.0f * sLength;
P.y = 0.0f;
P.z = 0.0f;
P.w = 0.0f;
Q.x = 0.0f;
Q.y = 2.0f * sHeight;
Q.z = 0.0f;
Q.w = 0.0f;
R.x = 0.0f;
R.y = 0.0f;
R.z = sDepth;
R.w = 0.0f;
S.x = 0.0f;
S.y = 0.0f;
S.z = -near * sDepth;
S.w = 1.0f;
return simd::float4x4(P, Q, R, S);
} // ortho2d
并通过传递到中的着色器来实现
constant_buffer[i].modelview_ortho_matrix = ortho2d(-2.0f, 2.0f, -2.0f, 2.0f, 0, 2); //_projectionMatrix * modelViewMatrix;
然后可能在你的顶点着色器中
float4 in_position = float4(float3(vertex_array[vid].position), 1.0);
out.position = constants.modelview_ortho_matrix * in_position;