如何在现代 OpenGL 中使用片段着色器中的 gl_FragCoord.z 线性渲染深度?
我阅读了很多有关使用片段着色器获得深度的信息。
例如
http://www.opengl.org/discussion_boards/ubbthreads .php?ubb=showflat&Number=234519
但我仍然不知道是否gl_FragCoord.z
是线性的。
GLSL 规范表示其范围是屏幕空间中的 [0,1],但没有提及它是否是线性的。
我认为线性度至关重要,因为我将使用渲染模型来匹配 Kinect 的深度图。
那么如果它不是线性的,如何在世界空间中线性化它呢?
I read lots of information about getting depth with fragment shader.
such as
http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=234519
but I still don't know whether or not the gl_FragCoord.z
is linear.
GLSL specification said its range is [0,1] in screen sapce without mentioning it's linear or not.
I think linearity it is vital since I will use the rendered model to match depth map from Kinect.
Then if it is not linear, how to linearlize it in the world space?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
gl_FragCoord.z 是否是线性的取决于投影矩阵。
对于正交投影,
gl_FragCoord.z
是线性的,而对于透视投影,它不是线性的。一般来说,深度(
gl_FragCoord.z
和gl_FragDepth
)计算如下(参见GLSL gl_FragCoord.z计算和设置gl_FragDepth):投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射。它从眼睛空间变换到剪辑空间,并且通过除以剪辑坐标的 w 分量,将剪辑空间中的坐标变换为标准化设备坐标 (NDC
)
。眼睛空间中的坐标线性映射到标准化设备坐标。
正交投影矩阵:
在正交投影中,Z 分量由线性函数计算:
透视投影
透视投影中的投影矩阵描述了 3D 的映射从针孔相机看到的世界上的点到视口的 2D 点。
相机视锥体(截棱锥体)中的眼睛空间坐标被映射到立方体(标准化设备坐标)。
透视投影矩阵:
在透视投影中,Z 分量由有理函数计算:
深度缓冲区
由于标准化设备坐标在范围 (-1 ,-1,-1) 到 (1,1,1) 的 Z 坐标必须映射到深度缓冲区范围 [0,1]:
要将深度缓冲区的深度转换为原始 Z 坐标,必须知道投影(正交或透视)以及近平面和远平面。
正交投影
透视投影
如果透视投影矩阵已知,可以按如下方式完成:
的答案
另请参阅如何给定视图空间深度值和 ndc xy 恢复视图空间位置
Whether
gl_FragCoord.z
is linear or not depends on, the projection matrix.While for Orthographic Projection
gl_FragCoord.z
is linear, for Perspective Projection it is not linear.In general, the depth (
gl_FragCoord.z
andgl_FragDepth
) is calculated as follows (see GLSL gl_FragCoord.z Calculation and Setting gl_FragDepth):The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport. It transforms from eye space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) by dividing with the w component of the clip coordinates
Orthographic Projection
At Orthographic Projection the coordinates in the eye space are linearly mapped to normalized device coordinates.
Orthographic Projection Matrix:
At Orthographic Projection, the Z component is calculated by the linear function:
Perspective Projection
At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).
Perspective Projection Matrix:
At Perspective Projection, the Z component is calculated by the rational function:
Depth buffer
Since the normalized device coordinates are in range (-1,-1,-1) to (1,1,1) the Z-coordinate has to be mapped to the depth buffer range [0,1]:
To convert form the depth of the depth buffer to the original Z-coordinate, the projection (Orthographic or Perspective), and the near plane and far plane has to be known.
Orthographic Projection
Perspective Projection
If the perspective projection matrix is known this can be done as follows:
See also the answer to
How to recover view space position given view space depth value and ndc xy
假设通常的透视投影矩阵,一旦执行透视除法(通过gl_Position.w)步骤,深度就会失去线性,因此gl_FragCoord.z不是线性的。如需更详细的解释,请阅读@Dreamer 的回答。
要恢复为线性,您应该执行 2 个步骤:
1) 将变量
gl_FragCoord.z
转换为 [-1, 1] 范围内的标准化设备坐标2) 应用投影矩阵的逆矩阵 (IP )。 (您可以对 x 和 y 使用任意值),并对最后一个分量进行标准化。
您将获得视图空间(或相机空间,您可以命名的)中的一个点,其线性 z 介于 znear 和 zfar 之间。
Assuming a usual perspective projection matrix, once the perspective division (by
gl_Position.w
) step is performed the depth loses its linearity, sogl_FragCoord.z
is not linear. For a more detailed explanation read @Dreamer's answer.To revert back to linear you should perform 2 steps:
1) Transform the variable
gl_FragCoord.z
to normalized devices coordinates in the range [-1, 1]2) Apply the inverse of the projection matrix (IP). (You can use arbitrary values for x and y), and normalize for the last component.
you will obtain a point in view space (or camera space, you name it) that has a linear z between znear and zfar.
gl_FragCoord.z
是否是线性的取决于您的变换矩阵。gl_FragCoord.z
是通过计算三角形所有顶点的gl_Position.z / gl_Position.w
确定的,然后将结果插值到该三角形的所有片段上。因此,当变换矩阵为
gl_Position.w
分配常量值时,gl_FragCoord.z
是线性的(这通常发生在正交投影矩阵中)并且是当gl_Position.w
取决于输入向量的x
、y
或z
坐标时,非线性(这发生在透视投影矩阵)。Whether
gl_FragCoord.z
is linear or not depends on your transformation matrix.gl_FragCoord.z
is determined by computinggl_Position.z / gl_Position.w
for all vertices of your triangle and then interpolating the result over all fragments of that triangle.So
gl_FragCoord.z
is linear when your transformation matrix assigns a constant value togl_Position.w
(which usually happens with ortho projection matrices) and is non-linear whengl_Position.w
depends on thex
,y
, orz
coordinate of your input vector (which happens with perspective projection matrices).由您决定是否需要线性 Z,一切都取决于您的投影矩阵。您可以阅读以下内容:
http://www.songho.ca/opengl/gl_projectionmatrix.html
这很好地解释了投影矩阵的工作原理。最好使用非线性 Z,以便在前景中获得更好的精度,在背景中获得更少的精度,当距离很远时,深度伪像不太明显......
Its up to you to decide if you want linear Z or not, everythings relies on your projection matrix. You may read this:
http://www.songho.ca/opengl/gl_projectionmatrix.html
Which explains very well how projection matrices works. It may be better to have non-linear Z in order to have better precision in the foreground and less in the backgrounds, depth artifacts are less visible when far away...