WAYNETS.ORG

Game and Program

着色

作者:

发表于

Context Polling System Post-Processing Renderer

可见性(Visibility) / 遮挡(Occlusion)

为什么需要可见性判断?

在场景中可能有多个三角形投影到相同像素位置。因此,我们必须决定:这个像素真正看到的是哪个三角形?

方法1:画家算法

核心思想:先画远处图元,再画近处图元,后画的像素覆盖前画的。

然而,由于在实际工作中,它存在局限性

  • 遮挡环(Cyclic Occlusion):无法线性决定绘制顺序。
  • 三角形之间的深度关系可能不是全局一致的。

方法2:Z-Buffer(深度缓存)算法

深度缓存算法是现代光栅化管线中最常用的可见性处理方式。

核心思想:

  • 每个像素记录一个当前最小深度值(默认是“无穷远”)。
  • 对场景中的所有三角形进行光栅化时,逐像素判断当前片元的深度是否小于已有深度值。如果小于已有深度值,则更新颜色和深度;否则忽略该片元。

即:每一个像素可以记录先后顺序(最浅的深度信息),也可以说深度缓存是发生在像素内的。

深度缓存算法流程:P9~P11

  • 初始化帧缓冲区和Z-Buffer:所有像素深度设为∞。
  • 遍历所有三角形:对每个三角形进行光栅化,找到所有覆盖的像素。
  • 对每个像素进行深度比较:把最浅的颜色放到深度缓冲区
  • 最终图像 = 深度最浅的像素颜色。

深度缓存算法特点:

  • 时间复杂度为 O(n),其中 n 是像素数量 × 三角形数量(近似估算)。
  • 实时渲染中普遍使用。

着色:漫反射

什么是着色?

着色是根据物体表面属性、光源信息以及观察方向等因素计算最终像素颜色的过程。

定义:对不同物体应用不同材质

高光 / 漫反射 / 环境(间接)光照

P22观测方向,表面法线,光照方向,物体表面属性参数

漫反射光照模型(Diffuse Reflection)

  • 当光线打在粗糙表面时,光会被均匀地向各个方向反射
  • 人眼所见亮度与观察方向无关,只与光照角度有关。

漫反射建模 —— Lambert’s Cosine Law(P25)

物体表面接收到的光强与光线方向和法线方向夹角的余弦成正比。

漫反射光照模型公式

Ld = kd(I / r2) ⋅ max(0, n ⋅ L)

符号含义
Ld表面点最终漫反射光强(颜色)
kd材质的漫反射系数(也就是表面颜色)
I光源强度
r点光源与着色点之间的距离
I / r2实际有多少光强到达光照点,因存在衰减
n表面法线向量(单位向量)
L从着色点指向光源的单位向量
n ⋅ L入射夹角的余弦值,表示表面接收的能量
max⁡(0, ⋅)防止光线从背面照射时贡献负值

Light Falloff 光的衰减(P26)

  • 点光源发出的光会均匀扩散到所有方向,因此距离每增长一倍,单位面积上接收到的光强下降为 I / r2
  • 这被称为 光照衰减律(Light Attenuation)

着色:高光反射(Specular Reflection)

什么是高光?

表面光滑时,光线会沿特定方向反射。当观察方向反射方向相近时,会看到高亮点,这就是高光。而根据计算,当法线方向和半程向量h非常接近时,会出现高光。

什么是半程向量?P8

半程向量比反射向量更好算

Blinn-Phong 高光模型(P8)

反射模型公式(改进版):

Ls = ks (I/r2) ⋅ max(0, cos ) p= ks (I/r2) ⋅ max(0, n · h) p

符号意义
Ls高光分量
ks材质的高光系数(越大越亮)
I光源强度
r光源与着色点距离
n法线向量
h半程向量(Half Vector)
p高光“锐度”指数(越大越尖锐)

为什么要加指数p?(P9)

  • 如果只使用n · h,会造成高光区域过大,缺乏真实感。
  • 指数p控制高光“锐利程度”:
    • 小 → 高光柔和扩散(如塑料)
    • 大 → 高光集中尖锐(如金属)

环境光照

对于模型的有些地方,根本不可能被光线打到,但它却有一点光照。这是因为光线会被不断反射,直到打到这个位置。

因此,环境光照为:模拟由于多次间接反射而照亮物体暗部的光。

模型公式:La = ka * Ia

符号含义
ka材质的环境光反射系数
Ia环境光强度(通常设为常量)

环境光与光源/方向无关,通常是常数近似。

综合光照模型 —— Blinn-Phong模型P12

将三种光照合成一个表达式:L = La ​+ Ld​ + Ls

La​:环境光

Ld​:漫反射(Lambert)

Ls​:高光反射(Blinn-Phong)

三种着色方式(Shading Modes)

Flat Shading(平面着色)—— P16

  • 每个三角形使用一个颜色(整个面法线一致)。
  • 法线由三角形的三个点叉积得出。
  • 简单快速,但边缘容易出现突变。

Gouraud Shading(Gouraud 着色)—— P17

  • 逐顶点着色 + 插值颜色
  • 每个顶点计算光照,三角形内部通过插值传播颜色。
  • 优点:效率高
  • 缺点:高光可能被“平滑”丢失

Phong Shading(逐像素着色)—— P18

  • 逐像素插值法线,然后再计算光照。
  • 比 Gouraud 更精确,能展现清晰高光。
  • 成本较高(但现代GPU可以轻松处理)。

如何定义顶点法线?(P20)

一个顶点常常被多个三角形共享。

在这种情况下,顶点法线通常取这些三角形法线的加权平均值

如何定义像素法线?(P21)

Phong Shading 中:

在三角形内部插值三个顶点法线。

得到的结果再归一化作为当前像素法线。

实时渲染管线

shader:每个像素都会执行一次

定义一个点的基本属性

任何一个三维物体表面都是二维的,找到物体表面的点和纹理表面的点一一对应的关系,就是纹理映射。

纹理上定义的坐标系:UV

================================================================

重心坐标

如何在三角形内部进行任何属性的插值?

(1) 重心坐标(Barycentric Coordinates)

在一个三角形平面中,任意点都可以表示为三个顶点的加权平均,即:

满足三个条件(P7):

  1. α+β+γ=1\alpha + \beta + \gamma = 1α+β+γ=1
  2. α,β,γ∈R\alpha, \beta, \gamma \in \mathbb{R}α,β,γ∈R
  3. 若三者都为正,则点 PPP 位于三角形内部。

(2) 重心坐标的计算:使用面积比法(Area Method)

用子三角形的面积占整个大三角形面积的比例来计算权重。

  • 设点 PPP 在三角形 ABCABCABC 内
  • 计算子三角形的面积:
  • 可用叉乘公式简化面积计算。

(3) 重心坐标的用途

  • 在三角形内部插值任意属性(颜色、法线、纹理坐标、深度等)
  • 关键用于逐像素着色(fragment shader)
  • 插值公式:属性(P)=α属性(A)+β属性(B)+γ属性(C)

(4) 重心坐标的透视矫正(Perspective Correction)

投影会破坏线性关系:

  • 屏幕空间插值的重心坐标是错误的!
  • 投影之后的图像是非线性的

纹理映射(Texture Mapping)

如何把纹理应用到渲染中?

P14纹理映射的原理:

  • 每个顶点提供纹理坐标(u,v)
  • 插值后传递到像素,再用(u,v)查找纹理颜色

问题1:如果纹理太小了怎么办?P16-P22

有一个很小的图,现在想把它放大,但是这会造成一个问题:低分辨率纹理被放大时,每个像素可能对应纹理中非整数坐标

解决方法:双线性插值(Bilinear Filtering)

让一个像素考虑最靠近的4个像素,对颜色进行加权平均,从而做到平滑过渡。

设采样位置为(u, v):

  • 找出周围的4个纹理像素(左上、右上、左下、右下)。
  • 根据u, v距离,插值合成最终颜色。

问题2:如果纹理太大了怎么办?

多个像素可能对应纹理中很大一片区域,容易导致混叠(aliasing)

解决方法:Mipmap + 过滤器

  • 为原始纹理生成一系列分辨率不断减半的图层(通常用 2 的幂次)
  • 渲染时自动选择最合适的图层采样,这样可以:
    • 降低计算压力
    • 减少混叠和闪烁

范围查询(approximate filtering):

Mipmap允许做范围查询(但只能做近似的,正方形的查询)

  • 在某个 Mipmap 级别中,按一定范围平均取样
  • 实现更平滑的缩小效果(代价是精度下降)

实际 GPU 会使用 [三线性插值(trilinear filtering)]:

在两个相邻的 mipmap 层之间插值采样,提升过渡效果

纹理的应用

在现代GPU中,可以把纹理理解为一块内存,并且可以对这块内存进行滤波。

Environment Map:可以用纹理去描述环境光,然后用该环境光去渲染其他物体。

假设:环境光来自无限远,即:只记录方向信息,没有实际的深度意义。

Spherical Map:

Cube Map:

凹凸贴图:纹理可以定义一个表面上,任意一个点的相对高度。当相对高度改变,该点的法线也会随之变化,最终导致着色的结果发生变化,于是出现了明暗对比。

法线贴图:通过法线贴图,可以得到一个复杂的纹理,但是却没有改变人物几何信息。

  • 把任何一个像素的法线做扰动(Perturb):通过定义不同位置的高度,把它临近位置的高度差来重新计算法线。P15
  • 如何计算法线的变化:

位移贴图:实际地改变三角形顶点的位置

3D纹理

Leave a comment