我使用以下代码创建正交矩阵:
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。
可能是什么问题?
答案 0 :(得分:0)
GL的透视和正投影矩阵在Metal中都是无效的,因为z范围不同。有些矩阵可能仍然可以工作,因为你的z-clip范围在OpenGL中过于深,所以它恰好足以让碎片在Metal中通过,但是这是一件坏事。
从金属编程指南,p。 51“使用视口和像素空间坐标”:
Metal将其规范化设备坐标(NDC)系统定义为 2x2x1立方体,其中心位于(0,0,0.5)。 x的左下角 NDC系统和y分别指定为-1。正确的 NDC系统的x和y的顶部和顶部分别指定为 1。
这与OpenGL不同,OpenGL的z从-1到1,在2x2x2矩阵中。
有关详细信息,请参阅此博客文章:http://blog.athenstean.com/post/135771439196/from-opengl-to-metal-the-projection-matrix
更新 - 用户da1找到了一个替代博文,上面的内容目前已关闭:http://metashapes.com/blog/opengl-metal-projection-matrix-problem
答案 1 :(得分:0)
来自AAPLTransfomations.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;