在作业3中计算插值的代码如下:
float w_reciprocal = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
z_interpolated *= w_reciprocal;
其中v是view space下的坐标,w_reciprocal是插值后的z_view
我暴力的手推了一下,发现最终的z_interpolated的确是z_ndc,正是我们所需要的。
但是这个式子,后两行的这个代码是怎么来的呢?我始终想不通如何从数学上推出这个代码。但我按这个式子列了一下,算到最后,知道他是正确的。
另外假设从view space变换到ndc,我们有
auto z_correct_ndc = (zfar+znear)/(zfar-znear) + 2*zfar*znear/ ((zfar - znear) *w_reciprocal );
auto z_correct = 1 / w_reciprocal ;
可以看到实际上影响到深度值的部分就是z_correct, 我们直接使用1 / w_reciprocal
,也就是1/z_view来做depth test就可以了,那么再把插值后的z_view变换到z_ndc是否还有必要?在多出了部分运算量后,这样做有什么好处?
以及在draw()
函数中的vert.z() = vert.z() * f1 + f2;
这个我手推出来是n+f+nf/z_view,我并不清楚这步的意义,在插值计算时我也完全没有使用传入rasterize_triangle()
函数中三角形的这个z分量,我想知道原本这个设计是用来做什么的。
最后是一个关于插值理解的问题,我发现如果要对depth或者其他的属性做插值的话,我现在是这样做的,先在屏幕空间计算出贡献分量,然后回到view space去做关于1/z_view的线性插值。有没有不使用viewspace坐标或者说不把z_ndc变换到z_view,直接使用z_ndc的插值方法?
恳请各位大佬赐教!!