屏幕空间

作者:追风剑情 发布于:2017-1-3 20:56 分类:Shader

      经过投影矩阵的变换后,我们可以进行裁剪操作。当完成了所有的裁剪工作后,就需要进行真正的投影了,也就是说,我们需要把视锥体投影到屏幕空间(screen space)中。经过这一步变换,我们会得到真正的像素位置,而不是虚拟的三维坐标。

      屏幕空间是一个二维空间,因此,我们必须把顶点从裁剪空间投影到屏幕空间中,来生成对应的2D坐标。这个过程可以理解成有两个步骤。

      首先,我们需要进行标准齐次除法(homogeneous division),也被称为透视除法(perspective division)。虽然这个步骤听起来很陌生,但是实际上非常简单,就是用齐次坐标系的w分量去除以x、y、z分量。在OpenGL中,我们把这一步得到的坐标叫做归一化的设备坐标(Normalized Device Coordinates,NDC)。经过这一步,我们可以把坐标从齐次裁剪坐标空间转换到NDC中。经过透视投影变换后的裁剪空间,经过齐次除法后会变换到一个立方体内。按照OpenGL的传统,这个立方体的x、y、z分量的范围都是[-1,1]。但在DirectX这样的API中,z分量的范围会是[0,1]。而Unity选择了OpenGL这样的齐次裁剪空间。如图所示:

     而对于正交投影来说,它的裁剪空间实际已经是一个立方体了,而且由于经过正交投影矩阵变换后的顶点的w分量是1,因此齐次除法并不会对顶点的x、y、z坐标产生影响。经过齐次除法后,透视投影的裁剪空间会变换到一个立方体
2222.png 111111.png

     经过齐次除法后,透视投影和正交投影的视锥体都变换到一个相同的立方体内。现在,我们可以根据变换后的x和y坐标来映射输出窗口的对应像素坐标。

     在Unity中,屏幕空间左下角的像素坐标是(0, 0),右上有的像素坐标是(pixelWidth,pixelHeight)。由于当前x和y坐标都是[-1, 1]。因此这个映射的过程就是一个缩放的过程。

齐次除法和屏幕映射的过程可以使用下面的公式来总结:

11111.png

上面的式子对x和y分量都进行了处理,那么z分量呢?通常z分量会被用于深度缓冲,一个传统的方式是把clipz/clipw的值直接存进深度缓冲中,但这并不是必须的。通常驱动生产商会根据硬件来选择最好的存储格式。此时clipw也并不会被抛弃,虽然它已经完成了它的主要工作——在齐次除法中作为分母来得到NDC,但它仍然会在后续的一些工作中起到重要的作用,例如进行透视校正插值。

      在Unity中,从裁剪空间到屏幕空间的转换是由底层帮我们完成的。我们的顶点着色器只需要把顶点转换到裁剪空间即可。

总结

111111.png222222.png

需要注意的是,这里仅仅给出的是一些最重要的坐标空间。还有一些空间在实际开发中也会遇到,例如切线空间(tangent space)。切线空间通常用于法线映射。

标签: Shader

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号