关于gluProject与OpenGL裁剪的困惑:顶点Y坐标为何均超1080?
OpenGL固定变换管线中gluProject计算结果异常问题
问题背景
在OpenGL固定变换管线中,给定如下参数:
GL_MODELVIEW_MATRIX 0,175,303.109,0,688.503,-2741.84,1583,0,29.3148,5.52094,-3.18752,0,-87.4871,731.309,-1576.92,1 GL_PROJECTION_MATRIX 2.09928,0,0,0,0,3.73205,0,0,0,0,-1.00658,-1,0,0,-43.9314,0 GL_VIEWPORT 0,0,1920,1080
绘制单位立方体后,预期一半顶点的像素Y坐标大于1080,另一半为负值,但使用gluProject计算后,所有顶点的Y坐标均大于1080,计算结果如下:
model coordinate 0 0 0 -> screen coordinate 848.191 1474.61 0.989359 model coordinate 1 0 0 -> screen coordinate 821.586 1973.88 0.986045 model coordinate 0 1 0 -> screen coordinate -198317 667165 4.61719 model coordinate 1 1 0 -> screen coordinate -2957.48 12504.1 1.07433 model coordinate 0 0 1 -> screen coordinate 885.806 1479.77 0.989388 model coordinate 1 0 1 -> screen coordinate 868.195 1979.01 0.986088 model coordinate 0 1 1 -> screen coordinate -438501 1.39841e+06 8.60228 model coordinate 1 1 1 -> screen coordinate -3191.35 12592.4 1.07507
绘制立方体的代码:
glBegin(GL_QUADS); for(int d = 0; d < 3; ++d) for(int s = 0; s < 2; ++s) for(int v = 0; v < 4; ++v) { const int a = (v & 1) ^ (v >> 1 & 1); const int b = v >> 1 & 1; const int d0 = d; const int d1 = (d + 1) % 3; const int d2 = (d + 2) % 3; double p[3]; p[d] = s; p[d1] = a; p[d2] = b; glColor3dv(p); glVertex3dv(p); } glEnd();
原因分析
所有顶点屏幕Y坐标均大于1080的核心原因是模型视图矩阵的变换完全改变了顶点在相机空间的位置,加上透视除法的符号影响,导致最终屏幕Y坐标全部超出视口上边界,具体拆解:
模型视图变换对顶点Y分量的影响
OpenGL矩阵采用列主序,模型视图矩阵的Y平移分量为731.309,对单位立方体顶点(模型空间y∈{0,1})的变换结果:- 模型空间y=0的顶点:变换后相机空间Y分量为731.309或906.309(均为正数)
- 模型空间y=1的顶点:变换后相机空间Y分量为-2010.53或-1835.53(均为负数)
透视除法的符号反转作用
投影矩阵的最后一行决定了透视除法的w分量:w'' = -z'(z'为模型视图变换后的相机空间Z分量)。对于单位立方体顶点:- 模型空间y=0的顶点:z'为负数,w''为正数,透视除法后NDC-Y为正数,计算屏幕Y时
screen_y = 540*(ndc_y +1),ndc_y均大于1.7,最终screen_y大于1458,远超1080。 - 模型空间y=1的顶点:z'为正数,w''为负数,透视除法时负数除以负数得到正数NDC-Y,且因z'绝对值很小,NDC-Y绝对值极大,最终screen_y远大于1080。
- 模型空间y=0的顶点:z'为负数,w''为正数,透视除法后NDC-Y为正数,计算屏幕Y时
预期错误的根源
你错误地认为模型空间的y值与屏幕Y坐标的正负直接对应,但实际上模型视图矩阵的旋转、平移已经完全改变了顶点的相机空间位置,加上投影变换的非线性映射,模型空间的y值无法直接决定屏幕坐标的正负。
内容的提问来源于stack exchange,提问作者diegor
相关产品推荐
相关产品推荐

