从剪辑空间到屏幕坐标的转换何时发生?
Posted
技术标签:
【中文标题】从剪辑空间到屏幕坐标的转换何时发生?【英文标题】:When does the transition from clip space to screen coordinates happen? 【发布时间】:2014-03-17 11:42:38 【问题描述】:我正在研究渲染管道,当我进入剪辑阶段时,解释说我们必须从视图(眼睛或相机)空间传递到剪辑空间,也称为标准化设备空间(NDC),即从-1到1的立方空间。
但是,现在我不明白从这个空间到屏幕坐标空间的通道是什么时候发生的:
就在裁剪之后和光栅化之前?
在光栅化之后和剪刀和 z 测试之前?
在写入帧缓冲区之前结束?
【问题讨论】:
【参考方案1】:不,剪辑空间和 NDC 空间不是一回事。
剪辑空间其实离NDC一步之遥,所有坐标除以Clip.W
产生NDC。结果 NDC 空间中超出范围 [-1,1] 的任何内容都对应于裁剪体积之外的点。 NDC之前的坐标空间被称为剪辑空间是有原因的;)
然而,严格来说,NDC 空间不一定是立方的。 NDC 空间在 OpenGL 中确实是一个立方体,但在 Direct3D 中却不是。在 D3D 中,NDC 空间中的 Z 坐标范围从 0.0 到 1.0,而它的范围从 -1.0 到 1.0在 GL 中。 X 和 Y 在 GL 和 D3D 中的行为相同(即,它们的范围从 -1.0 到 1.0)。 NDC 是一个标准的坐标空间,但在不同的 API 中有不同的表示。
最后,NDC 空间到屏幕空间(AKA 窗口空间)发生在光栅化期间,由您的视口和深度范围定义。片段位置在任何其他坐标空间中确实没有意义,这就是光栅化产生的:片段。
更新:
在 OpenGL 4.5 中引入,扩展 GL_ARB_clip_control
允许您在 GL 中采用 D3D 的 NDC 约定。
传统的 OpenGL 行为是:
glClipControl (GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
Direct3D 行为可以通过以下方式实现:
glClipControl (GL_UPPER_LEFT, GL_ZERO_TO_ONE); // Y-axis is inverted in D3D
【讨论】:
剪辑空间和 NDC 不是一回事,否则它们不会有不同的名称。裁剪空间是空间点在投影矩阵的点变换之后但在 w 的归一化之前。 NDC空间是经过w标准化后的空间点。 scratchapixel.com/lessons/3d-basic-rendering/… 这个答案可能有点误导。剪辑空间和 NDC 在概念上是相同的东西,只是以不同的形式表示——一种以齐次坐标表示,另一种以笛卡尔坐标表示。在这种转换中唯一丢失的是表示无穷远点的能力。所以是的,虽然它们在实践中是不同的东西(也就是说,你必须做一个操作才能从一个到另一个),但它们实际上代表了相同的底层模型。 我认为它比这简单得多。它与我所说的 2d 投影空间无关。相反,它只是代表相机视野的体积。剪辑空间内的对象对相机可见。剪辑空间之外的对象不可见。与二维透视投影无关。进一步阅读后,剪辑空间似乎与 NDS 相同。在 2d 透视空间中,如果对象的 x 和 y 坐标在屏幕尺寸范围内,您可以轻松判断对象是否在视野中。所以你会使用 2d 透视空间 2 次。 这是正确的,但关于剪辑空间的问题是,它没有标准化:)w
坐标定义剪辑空间和 NDC 空间中剪辑体积的范围,但在NDC 空间,w
是 1.0 并且一切都已标准化。在剪辑空间中,每个顶点都可以以不同的w
坐标定义的比例存在;一旦转换为 NDC 空间,所有顶点都一致并且更易于使用。
@AndonM.Coleman - 感谢您的非常有用的评论!我还有一个疑问,能帮忙吗?在我在网上找到的基本上所有资源 (linking one for reference) 中,NDC 空间都显示为一个立方体。我应该如何看待 Clip 空间?它也是一个立方体,还是作为眼睛空间的透视平截头体(因为在它内部我们可以表示无限远的点)?将剪辑到 NDC 的操作视为将第一个中的光线映射到第二个中的点是否正确,或者是 1 到 1?【参考方案2】:
剪辑空间和 NDC(标准化设备坐标)不是一回事,否则它们不会有不同的名称。
剪辑空间是空间点在投影矩阵进行点变换之后,但在w
归一化之前所在的位置。
NDC 空间是经过w
标准化后的空间点。
http://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrix-GPU-rendering-pipeline-clipping
Camera space -->
x projection matrix --->
Clip space (before normalisation) --->
Clipping --->
Normalisation by w (x/w, y/w, z/w) --->
NDC space (in the range [-1, 1] in x and y)
【讨论】:
不要吹毛求疵,但有很多坐标空间有多个名称。例如,不幸的是,眼睛空间、视图空间和相机空间都是同一个东西。窗口空间和屏幕空间也是同一事物的两个词。 NDC 和剪辑空间绝对不是两个意思相同的词,这是真的。 每个分量除以w
分量的步骤不叫“归一化”,叫透视除法,目的是将顶点从齐次空间变换为笛卡尔空间空间(即投影它们)。确实,它们最终会进入规范化的设备空间,但这并不意味着顶点已“规范化”。归一化一个实际上表示为向量的顶点是非常不同的。【参考方案3】:
显然,根据 Apple 的说法,剪辑空间与 NDC 相同。
https://developer.apple.com/documentation/metal/hello_triangle
引用:
“顶点函数(也称为顶点着色器)的主要任务是处理传入的顶点数据并将每个顶点映射到视口中的一个位置。这样,管道中的后续阶段可以参考这个视口位置并将像素渲染到可绘制对象中的确切位置。顶点函数通过将任意顶点坐标转换为规范化的设备坐标(也称为剪辑空间坐标)来完成此任务。"
示例代码中来自 cmets 的另一句话:
“每个顶点着色器的输出位置都在剪辑空间(也称为标准化设备坐标空间,或NDC)中。”
也许这是因为教程是 2D 的?误导性陈述..
【讨论】:
摘自“OpenGL SuperBible 第 6 版”一书 - Pag. 64: " Clip Space : 投影到非线性齐次坐标后的顶点位置。Normalized Device Coordinate (NDC) Space : 据说顶点坐标在 NDC 之后它们的剪辑空间坐标已被它们自己的 w 分量分割。” 是的,对我来说剪辑空间是在剪辑之前,而不是在剪辑之后。但在 2D 应用程序或正交投影中,结果是相同的。 您在剪辑前后都处于剪辑空间中。剪辑坐标背后的想法是所有渐变仍然是线性的,因为还没有应用透视;这大大简化了事情。如果裁剪器的输入在裁剪空间中,那么输出也是。您正在描述一个极端情况,其中所有顶点的 w 统一为 1.0。这种情况很容易从变换矩阵和输入顶点中检测到(如果它们是 3 个或更少的分量,则微不足道)。这不会影响剪辑结果仍在剪辑坐标中的事实。好的,所以 NDC 与剪辑相同,很棒;你可以跳过一个步骤。【参考方案4】:NDC 空间是剪辑空间,NDC 空间到窗口空间是由硬件完成的,发生在 NDC 之后和光栅化之前。
有设置宽度和高度的API,默认值与窗口大小相同。
// metal
func setViewport(_ viewport: MTLViewport)
// OpenGL
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
OpenGL 的 NDC 空间,xyz 范围 [-1, 1]。对于金属,Z 是从 0 到 1
NDC 空间通常是左手系统。
【讨论】:
【参考方案5】:您可以考虑从剪辑空间(每个轴上的 -1 到 +1,对于图像中的任何内容)到屏幕坐标的过渡,也称为视口空间(X 中的 0 到 ResX,Y 中的 0 到 rexY,以及 0到 Z 中的 1,也就是深度),发生在 在光栅化之前,在顶点处理器之后。
在编写顶点着色器时,输出的是顶点在剪辑空间中的投影位置,但在片段着色器中,每个片段都有自己的屏幕坐标和深度。
关于剪辑空间 VS NDC
剪辑空间,顾名思义,是一个空间,即一个参考框架,一个坐标系,即一个特定的选择原点和您使用的一组三轴指定点和向量。
它的原点在剪辑体积的中间,它的三个轴按照 API 的指定对齐。比如这个空间的笛卡尔坐标(+1,0,0)的点出现在图像的右端,笛卡尔坐标(-1,0,0)的点出现在左边。
NDC(标准化设备坐标),顾名思义,是一组坐标:它们是剪辑空间中一个点的三个笛卡尔坐标。例如,在齐次坐标 (3,0,0,3) 的 Clip 空间中取一个点,您也可以将其表示为 (30,0,0,30),并以许多其他方式表示,它具有笛卡尔坐标 ( 1,0,0):它的 NDC 是 (1,0,0)。
【讨论】:
以上是关于从剪辑空间到屏幕坐标的转换何时发生?的主要内容,如果未能解决你的问题,请参考以下文章