我使用默认的OpenGL值,如glDepthRangef(0.0,1.0);, gldepthfunc(GL_LESS);和glClearDepthf(1.f);因为我的投影矩阵会将右手坐标更改为左手坐标。我的意思是,我的近平面和远平面z值在NDC中应该是[-1,1]。
问题是当我在包含相同RBO的一个FBO上绘制两个对象时,例如,如下面的代码,
glEnable(GL_DEPTH_TEST);
glClearDepthf(1.f);
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
drawObj1(); // this uses 1) the orthogonal projection below
drawObj2(); // this uses 2) the perspective projection below
glDisable(GL_DEPTH_TEST);
总是,object1位于object2之上。
然而,当他们使用相同的投影时,它工作正常。
你认为我应该过哪一部分?
- 更新 -
将眼睛坐标转换为NDC到屏幕坐标,究竟发生了什么?
我的理解是因为在两个投影之后,其NDC形状与下面的图像相同,其乘以2)透视矩阵后的z值不必失真。然而,根据德巴斯的好答案,如果视图坐标中的z值乘以透视矩阵,则z值将在NDC中双曲线扭曲。
如果是这样,例如,如果一个顶点位置在[w:480.0,h:320.0]的眼睛(视图)坐标中是[-240.0,0.0,-100.0],我用[-0.01]剪切它,-100],在NDC中会是[-1,0,-1]还是[something> = - 1,0,-1]?它的z值仍然与-1相同,不是吗?当它的z值失真时?
答案 0 :(得分:3)
您不能期望顶点的z值投影到相同的窗口空间z值,因为您对透视和正交投影矩阵使用相同的近和远值。
在预先设定的情况下,眼睛空间z值将双曲线地扭曲为NDC z值。在正交情况下,它只是过度缩放和移位。
如果你的" Obj2"只是在一个平面z_eye = const中,你可以预先计算它在透视情况下应该具有的扭曲深度。但如果它具有非零深度,则无效。我可以想出处理这种情况的不同方法:
"修正"通过根据z缓冲区预期的双曲线失真调整gl_FragDepth
,片段着色器中对象2的深度。
使用线性z缓冲区,也就是说。一个w buffer。
这些方法在概念上是彼此相反的。在这两种情况下,您都可以使用gl_FragDepth
,以便它与其他渲染过程的约定相匹配。
<强>更新强>
我的理解是因为在两个投影之后,它的NDC形状 与下面的图像相同,它是在乘以2)透视后的z值 矩阵不必扭曲。
嗯,这些图像显示了从剪辑空间到NDC的转换。而这种透明化就是透视划分所遵循的投影矩阵。当它处于标准化的设备坐标中时,不会发生进一步的失真。它只是根据glDepthRange()
设置线性转换为窗口空间z。
然而,根据 如果视图坐标中的z值相乘,那么德巴斯的答案很好 通过透视矩阵,z值将是双曲线的 在NDC中扭曲。
透视矩阵应用于完整的4D同质眼空间矢量,因此它应用于z_eye
以及x_eye
,y_eye
和w_eye
(通常只有1,但不必)。
因此,透视情况的最终NDC坐标是hyberbolically扭曲到
f + n 2 * f * n B
z_ndc = ------- + ----------------- = A + -------
n - f (n - f) * z_eye z_eye
而在正交情况下,它们只是线性转换为
- 2 f + n
z_ndc = ------- z_eye - --------- = C * z_eye + D
f - n (f - n)
对于n=1
和f=10
,它看起来像这样(请注意,我将范围部分绘制在平截头体之外。当然,剪切将阻止GL中出现这些值)。
如果是这样,例如,如果一个顶点位置为[-240.0,0.0,-100.0] 在眼睛(视图)坐标与[w:480.0,h:320.0],我剪了它 使用[-0.01,-100],它会是[-1,0,-1]还是[something&gt; = - 1,0,-1] in NDC?它的z值仍然与-1相同,不是吗?当它的z值 被扭曲了吗?
远处平面上的点始终转换为z_ndc=1
,并指向近似平面z_ndc=-1
。这就是投影矩阵的构造方式,这正是上图中两个图相交的位置。因此,对于这些微不足道的案例,不同的映射根本不重要。但对于所有其他距离,他们会。