Unity中从顶点着色器输出到片段着色器中间的顶点变换

Unity中从顶点着色器输出到片段着色器中间的顶点变换

image-20230202003630324

上图来自《shader入门精要》,是渲染流水线中顶点的完整空间变换过程。

在顶点着色器中,主要完成了前三个阶段,即顶点坐标乘以MVP矩阵,把顶点变换到了裁剪空间中,然后作为顶点着色器的输出。

在顶点着色器到片元着色器中间,也就是裁剪空间到屏幕空间,是Unity自动帮我们完成的,但是这个过程不只有一个阶段。

变换到NDC空间

首先要把顶点变换到NDC空间,裁剪空间中,各个顶点的x,y,z分量的范围是【-w,+w】,因此首先进行了透视除法,把各个顶点从裁剪空间变换到了NDC空间,这时各个分量的取值范围为【-1,1】。

视口变换

之后,需要进行视口变换,把各个分量先乘以1/2,再加上1/2,这时各个分量的取值范围就变成了【0,1】,这里就是视口空间的坐标。

屏幕空间

把各个顶点的x,y值分别乘以屏幕的宽和高,就得到了顶点最终在屏幕空间的位置。

因此整个过程就是裁剪空间坐标=>NDC空间坐标=>视口空间坐标=>屏幕空间坐标

Unity Shader中的ComputeScreenPos

Shader中这个函数的输入是裁剪空间中的某个顶点坐标,但是输出的并不是视口空间中的坐标,视口空间坐标的范围是【0,1】,但是这个函数输出的范围是【0,w】,因此,在除以w之后,把范围映射到了【0,1】才得到了视口空间的坐标。

image-20230202005628939

上图同样来自《shader入门精要》,注意除法要在片元着色器中进行。

Unity之所以不自动执行这个除法,首先是因为在顶点着色器中进行这个除法会影响插值,投影空间不是线性空间,在顶点着色器中计算x/w和y/w,顶点着色器到片元着色器中的插值就会影响这个结果,而保留x,y,w,经过插值之后再计算,结果就正确了。

另外一个原因是Unity希望你把该坐标值用作tex2Dproj指令的参数值,tex2Dproj会在对纹理采样前除以w分量。

这两种方法是等价的

tex2Dproj(_Tex, projCoord) == tex2D(_Tex, projCoord.xy / projCoord.w)

当我们需要采样某张屏幕空间的投影图时(深度图),后面是手动进行除法,效率没有前面的方法高。

posted @ 2023-02-02 01:22  罗小铸  阅读(198)  评论(0)    收藏  举报