再学计算机图形学入门

在网上查资料时,无意间发现了一门课叫《现代计算机图形学入门》。于是事隔将近3年后,我再一次尝试图形学入门。这次学习从8月20号开始,一直到10月11日,约持续了一个半月。

但是这次的学习体验和上次是完全不同的,最直接的感受有3点。

  1. 《现代计算机图形学入门》要比《3D游戏编程大师技巧》中的内容现代的多,内容和知识体系都更全面。

  2. 现代计算机的性能远超《3D游戏编程大师技巧》著作当时,因此很多为了提高性能的Trick已经没有必要使用。这会使我们花费大量精力在局部细节,而不能窥其全貌。一个最简单的例子就是,一个简单的lerp就让我花费的大量时间来调试

  3. 《现代计算机图形学入门》把主要精力都放在了如何渲染上,至于一些优化手段很少提及,比如三角形裁切,剔除等。这只是一些加速的优化手段,并不影响最终的渲染效果。这些优化在入门阶段,其实并不重要。而在《3D游戏编程大师技巧》中我们会沉浸在各种优化技巧中,而失去了渲染的全貌。

下面记录一下这次学习的新收获。


  1. 透视矫正(光栅化)

在纹理采样时,所有3维坐标都已经被投影到一个2维平面,但是纹理坐标属于3维空间。因此2维坐标下的插值系数不能用在3维坐标进行插值, 下面先来看一下为什么不能插值。

我们先定义q(x,y,z,1)为3维坐标,r(x,y,z,w)为齐次坐标,s(x,y,z, 1) 为投影坐标。

Xr = aXq + b; Yr = cYr + d; Zr = e * Zq + f; Wr = g;

q’ = lerp(q) = q1 + (q2 – q1) t;
r’ = lerp(r) = r1 + (r2 – r1)
t = q’ (a,c,e) + ((b,d,f) + ((b,d,f)’ – (b,d,f)) t)

可以看到虽然q到r的变换不是线性变换,但是有一部分变量是由q*t来贡献的,因此在齐次空间下直接对3维空间坐标进行插值,并没有太大的问题。

再来看一下齐次坐标到投影坐标的变换。

Xs = Xr / Wr; Ys = Yr / Wr; Zs = Zr / Wr;

先对齐次坐标r进行lerp,得到r’ = (lerp(Xr), lerp(Yr), lerp(Zr), lerp(Wr)).

再对r’做投影变换,得到s’ = lerp(s) = (lerp(Xr)/lerp(Wr), lerp(Yr)/lerp(Wr), lerp(Zr)/lerp(Wr), 1) = lerp(r) / lerp(Wr).

这与直接对s做插值是一样的(在投影坐标系之后,不会再次执行齐次除法)。

根据q’和r’的公式推导,可以看到lerp(r)和lerp(q)是可以共用插值系数的。

再根据s’的公式推导,可以得出lerp(s) 和 lerp(q) 的插值系数多了一个lerp(Wr).

这就是为什么,在投影坐标系对3维坐标系下的坐标做插值时,需要先做一次投影除法,将其变换到投影坐标系下,做完插值后,再除以lerp(1/w)来变回3维坐标系。

有一点需要额外提的是,有些资料提到除以lerp(1/z)也可以。但这其实不正确,因为投影变换本质上压缩了z坐标的值,相比w(实际上是3维空间下的z)来讲,会有更大误差的。

  1. 光线追踪

这次学习过程中,最大的收获就要数光线追踪了。在之前的印象中,我一直以为,渲染就是模型空间->世界空间->投影空间->屏幕空间坐标系之间的转换然后再将其光栅化成像。

这是我第一次了解到,原来另一种更好的成像方式叫光线追踪,甚至还有更真实的路径追踪。

  1. 一些零碎的额外收获

正交平移矩阵用的是坐标,所以如果相机本来就在原点那么(l+r) / 2 刚好也等于0。可能这就是为什么要选用[-1,1] 而不是[0,2] 来定义NDC的原因。

右手坐标系,脸朝向的地方为z = -1。因此在计算z深度时需要对z做反转。BUT,在计算投影矩阵时,我们一般会对进屏幕和远平面取负。因此在光栅化时就不需要再次补偿了。

使用一个矩阵M对一个三角形的三个顶点做变换后,使用M来变换法线向量有可能会使法线向量变形。由于切线向量就是三角形的一个边,因此切线不会发生形变。因此,当需要变换法线时,需要额外算出一个矩阵。具体计算公式在《Mathematics for 3D Game Programming and Computer Graphics Third Edition》中第4.5节有详细推导。

球面与射线相交处的法线,并不是从从射线原点到球心的向量。因为射线可能斜着打中球面(甚至会只擦中一点)

中位线和法线的夹角并不能代表出射光线和视线的夹角,是为了更好的光照效果,blin-phong故意引入的。其中一个副作用是,运算更快了。

在微表面模型下,不同的粗糙程度会有不同的概率密度函数,这是因为光线的分布不一样。例如在镜面反射下,大部分光线能量都会沿着某一个特定的方向射出。其他方位的光线概率密度就会特别低。

发表评论

7 × one =