山东大学计算机图形学期末复习完结篇上——24历年题
24历年题
由于csdn的md编辑器渲染问题,一些公式未能正常显示。
一、简答题
1. 图形绘制流水线的组成和作用
组成(基于图形管道架构):
- 顶点处理(Vertex Processing)
- 坐标变换(对象坐标 → 相机坐标 → 屏幕坐标)
- 顶点着色(计算颜色、光照)
- 投影变换(Projection)
- 将3D转换为2D(透视或平行)
- 图元组装(Primitive Assembly)
- 顶点组合为几何图元(三角形、多边形)
- 裁剪(Clipping)
- 移除视见体外的图元
- 光栅化(Rasterization)
- 图元 → 像素片段
- 片段处理(Fragment Processing)
- 纹理映射、光照计算、隐藏面消除
作用:提高图形渲染效率,实现从几何数据到图像的完整处理。
2. 双缓冲机制
定义:使用前台缓冲区和后台缓冲区避免图像撕裂。
原理:
- 绘图时写入后台缓冲区;
- 显示时从前台缓冲读取;
- 帧绘制完成后交换两个缓冲区。
作用:避免闪烁,提高动画的平滑度。
3. Delaunay三角化的四条性质
- 最大最小角性质:最大化三角形最小角度,避免瘦长三角形。
- 外接圆性质:任一三角形外接圆中不含其他顶点。
- 唯一性:若无四点共圆,则Delaunay三角化唯一。
- Voronoi对偶性:Delaunay三角形的外接圆心构成Voronoi图。
二、在三维空间中,如果要求沿方向v(a,b,c)产 生放大S倍的图形,试推导出变换矩阵。其 中v(a,b,c)为单位向量,a,b,c分别为向 量v与坐标轴之间夹角余弦值。(课上习题)
在三维空间中,沿任意方向向量 v = ( a , b , c ) \mathbf{v} = (a, b, c) v=(a,b,c) 缩放 S S S 倍,需要构造一个变换矩阵 M \mathbf{M} M,它具有如下性质:
- 在方向 v \mathbf{v} v 上放大 S S S 倍;
- 在垂直于 v \mathbf{v} v 的方向上保持不变(缩放比例为 1);
- v \mathbf{v} v 是单位向量,即 a 2 + b 2 + c 2 = 1 a^2 + b^2 + c^2 = 1 a2+b2+c2=1。
思路:向量分解 + 投影矩阵构造
对于任意一个点 p \mathbf{p} p,我们可以将其分解为两部分:
- 沿 v \mathbf{v} v 的分量: p ∥ = ( p ⋅ v ) v \mathbf{p}_\parallel = (\mathbf{p} \cdot \mathbf{v}) \mathbf{v} p∥=(p⋅v)v
- 垂直于 v \mathbf{v} v 的分量: p ∗ ⊥ = p − p ∗ ∥ \mathbf{p}*\perp = \mathbf{p} - \mathbf{p}*\parallel p∗⊥=p−p∗∥
那么,沿 v \mathbf{v} v 方向放大 S S S 倍的结果为:
p ′ = S ⋅ p ∥ + p ⊥ = S ( p ⋅ v ) v + ( p − ( p ⋅ v ) v ) = p + ( S − 1 ) ( p ⋅ v ) v \mathbf{p}' = S \cdot \mathbf{p}_\parallel + \mathbf{p}_\perp = S (\mathbf{p} \cdot \mathbf{v}) \mathbf{v} + \left(\mathbf{p} - (\mathbf{p} \cdot \mathbf{v}) \mathbf{v} \right) = \mathbf{p} + (S - 1) (\mathbf{p} \cdot \mathbf{v}) \mathbf{v} p′=S⋅p∥+p⊥=S(p⋅v)v+(p−(p⋅v)v)=p+(S−1)(p⋅v)v
所以可以推出变换公式:
p ′ = p + ( S − 1 ) ( v ⋅ p ) v \boxed{ \mathbf{p}' = \mathbf{p} + (S - 1)(\mathbf{v} \cdot \mathbf{p}) \mathbf{v} } p′=p+(S−1)(v⋅p)v
推导变换矩阵 M \mathbf{M} M
设单位向量 v = ( a , b , c ) \mathbf{v} = (a, b, c) v=(a,b,c),我们来构造 3×3 线性变换矩阵,使得:
p ′ = M ⋅ p \mathbf{p}' = \mathbf{M} \cdot \mathbf{p} p′=M⋅p
从上面的表达式可以得到(怎么得到??):
对于向量 p \mathbf{p} p 和单位向量 v \mathbf{v} v ,它们的点积可以表示为矩阵乘法:
p ⋅ v = v T p \mathbf{p} \cdot \mathbf{v}=\mathbf{v}^T \mathbf{p} p⋅v=vTp
这是因为:
- v T \mathbf{v}^T vT 是 v \mathbf{v} v 的转置(行向量)。
- 矩阵乘法 v T p \mathbf{v}^T \mathbf{p} vTp 展开后即为 v 1 p 1 + v 2 p 2 + v 3 p 3 v_1 p_1+v_2 p_2+v_3 p_3 v1p1+v2p2+v3p3 ,与点积定义一致。
示例:
设 v = [ a b c ] , p = [ x y z ] \mathbf{v}=\left[\begin{array}{l}a \\ b \\ c\end{array}\right], \mathbf{p}=\left[\begin{array}{l}x \\ y \\ z\end{array}\right] v= abc ,p= xyz ,则:v T p = [ a b c ] [ x y z ] = a x + b y + c z = p ⋅ v \mathbf{v}^T \mathbf{p}=\left[\begin{array}{lll} a & b & c \end{array}\right]\left[\begin{array}{l} x \\ y \\ z \end{array}\right]=a x+b y+c z=\mathbf{p} \cdot \mathbf{v} vTp=[abc] xyz =ax+by+cz=p⋅v
将点积结果 ( p ⋅ v ) (\mathbf{p} \cdot \mathbf{v}) (p⋅v) 与向量 v \mathbf{v} v 相乘时,可以改写为矩阵乘法:( p ⋅ v ) v = v ( v T p ) = ( v v T ) p (\mathbf{p} \cdot \mathbf{v}) \mathbf{v}=\mathbf{v}\left(\mathbf{v}^T \mathbf{p}\right)=\left(\mathbf{v} \mathbf{v}^T\right) \mathbf{p} (p⋅v)v=v(vTp)=(vvT)p
这里的关键是结合律和矩阵乘法的性质:
1.标量乘法交换:
( v T p ) \left(\mathbf{v}^T \mathbf{p}\right) (vTp) 是一个标量,因此 v ( v T p ) = ( v T p ) v \mathbf{v}\left(\mathbf{v}^T \mathbf{p}\right)=\left(\mathbf{v}^T \mathbf{p}\right) \mathbf{v} v(vTp)=(vTp)v 。
2.矩阵乘法结合律:
将 v ( v T p ) \mathbf{v}\left(\mathbf{v}^T \mathbf{p}\right) v(vTp) 看作矩阵乘法时,可以重新分组为 ( v v T ) p \left(\mathbf{v} \mathbf{v}^T\right) \mathbf{p} (vvT)p ,因为矩阵乘法满足结合律。
M = I + ( S − 1 ) ⋅ v v ⊤ \mathbf{M} = \mathbf{I} + (S - 1) \cdot \mathbf{v} \mathbf{v}^\top M=I+(S−1)⋅vv⊤
即:
$$
\mathbf{M} =
\begin{bmatrix}
1 & 0 & 0 \
0 & 1 & 0 \
0 & 0 & 1
\end{bmatrix}
- (S - 1)
\begin{bmatrix}
a^2 & ab & ac \
ab & b^2 & bc \
ac & bc & c^2
\end{bmatrix}
最终结果为: 最终结果为: 最终结果为:
\boxed{
\mathbf{M} =
\begin{bmatrix}
1 + (S-1)a^2 & (S-1)ab & (S-1)ac \
(S-1)ab & 1 + (S-1)b^2 & (S-1)bc \
(S-1)ac & (S-1)bc & 1 + (S-1)c^2
\end{bmatrix}
}
$$
三、Bresenham 算法及其改进
算法作用:高效绘制线段,避免浮点运算。
基本思想:
- 选择像素点使直线与理想线段最接近;
- 通过误差项决定下一步向 x 还是向 x+y。
改进措施:
- 处理不同斜率(包括负斜率与大于 1 的情况);
- 推广到圆(Bresenham 圆算法);
- 使用整数代替浮点提高效率;
- 改为对称算法减小运算量。
四、
1. 视见体标准化的作用
- 简化裁剪过程;
- 所有视见体转为单位立方体( [ − 1 , 1 ] 3 [-1,1]^3 [−1,1]3);
- 统一处理不同投影模式。
2. 正交投影归一化变换矩阵推导
设视见体范围:
- x ∈ [ l , r ] x \in [l, r] x∈[l,r]
- y ∈ [ b , t ] y \in [b, t] y∈[b,t]
- z ∈ [ n , f ] z \in [n, f] z∈[n,f]
正交投影矩阵为:
[ 2 r − l 0 0 − r + l r − l 0 2 t − b 0 − t + b t − b 0 0 − 2 f − n − f + n f − n 0 0 0 1 ] \begin{bmatrix} \frac{2}{r - l} & 0 & 0 & -\frac{r + l}{r - l} \\ 0 & \frac{2}{t - b} & 0 & -\frac{t + b}{t - b} \\ 0 & 0 & \frac{-2}{f - n} & -\frac{f + n}{f - n} \\ 0 & 0 & 0 & 1 \end{bmatrix} r−l20000t−b20000f−n−20−r−lr+l−t−bt+b−f−nf+n1
作用:将任意长方体视见体转换为标准立方体。
复杂场景下的消隐算法
常见算法包括:
1. Z-buffer(深度缓存法):
- 每个像素记录当前最近的深度值;
- 新片段深度小于当前值则更新。
2. BSP 树(Binary Space Partitioning):
- 将场景划分为多个部分;
- 用树结构排序可见性。
3. 后-前法(Painter’s Algorithm):
- 按照深度从远到近绘制;
- 存在重叠错误问题。
加速三角形填充的两种方法
方法一:扫描线算法(Scanline)
- 遍历每一行像素;
- 计算当前扫描线与三角形边的交点;
- 填充交点之间的像素;
- 适合光栅化的加速处理。
方法二:Barycentric坐标法
- 对于每个像素 ( x , y ) (x, y) (x,y),计算其在三角形中的重心坐标 ( α , β , γ ) (\alpha, \beta, \gamma) (α,β,γ);
- 如果 α , β , γ ∈ [ 0 , 1 ] \alpha, \beta, \gamma \in [0,1] α,β,γ∈[0,1],则该点在三角形内;
- 可直接插值颜色、纹理坐标等属性;
- GPU中广泛使用。
Phong模型
1. 组成及 Blinn 改进模型
Phong 模型组成:
- 环境光: I a m b i e n t = k a ⋅ I a I_{ambient} = k_a \cdot I_a Iambient=ka⋅Ia
- 漫反射: I d i f f u s e = k d ⋅ I ⋅ ( N ⋅ L ) I_{diffuse} = k_d \cdot I \cdot (N \cdot L) Idiffuse=kd⋅I⋅(N⋅L)
- 镜面反射: I s p e c u l a r = k s ⋅ I ⋅ ( R ⋅ V ) n I_{specular} = k_s \cdot I \cdot (R \cdot V)^n Ispecular=ks⋅I⋅(R⋅V)n
Blinn 模型改进:
- 使用半角向量 H = L + V ∣ L + V ∣ H = \frac{L + V}{|L + V|} H=∣L+V∣L+V 替代反射向量 R R R;
- 公式: I s p e c u l a r = k s ⋅ ( N ⋅ H ) n I_{specular} = k_s \cdot (N \cdot H)^n Ispecular=ks⋅(N⋅H)n;
- 计算更稳定,效率更高。
2. Phong着色优点与绘图质量提升
- 每像素插值计算法向量后再光照计算;
- 相较 Gouraud 每顶点光照插值,能展现更平滑高光;
- 提高真实感和光照精细度。
判断顶点是否在图形内(如多边形)
常见算法:射线法(Ray-Casting)
- 从点向任意方向引一条射线;
- 统计其与图形边界的交点数;
- 若为奇数次 → 点在图形内;
- 若为偶数次 → 点在图形外。
判断顶点是否在图形内(如多边形)
常见算法:射线法(Ray-Casting)
- 从点向任意方向引一条射线;
- 统计其与图形边界的交点数;
- 若为奇数次 → 点在图形内;
- 若为偶数次 → 点在图形外。
Mipmap原理
1. 原理:
- 多分辨率纹理金字塔;
- 减少远处图像失真与锯齿;
- 提高渲染效率。
2. 存储量:
总存储量约为原图像的 4 3 \frac{4}{3} 34 倍:
总大小 = ∑ i = 0 ∞ 1 4 i = 1 1 − 1 4 = 4 3 \text{总大小} = \sum_{i=0}^{\infty} \frac{1}{4^i} = \frac{1}{1 - \frac{1}{4}} = \frac{4}{3} 总大小=i=0∑∞4i1=1−411=34
3. 分级实现:
- 原图缩小为 1 / 2 i 1/2^i 1/2i 尺寸,每级为前一级平均采样生成;
- 可使用 OpenGL 自动生成
glGenerateMipmap
。
算法题
1. Cyrus-Beck 算法步骤(线段裁剪)
适用于凸多边形窗口裁剪:
- 计算边法向量与线段方向的点积;
- 求入/出交点参数 t t t;
- 确定线段在窗口内的部分: t i n ≤ t ≤ t o u t t_{in} \le t \le t_{out} tin≤t≤tout;
- 线段与裁剪窗口交于两个 t t t 值所确定的点。
2. Liang-Barsky 算法思想
比Cohen-Sutherland更高效(少算交点)
- 基于参数方程 P ( t ) = P 0 + t ( P 1 − P 0 ) P(t) = P_0 + t(P_1 - P_0) P(t)=P0+t(P1−P0), t ∈ [ 0 , 1 ] t \in [0,1] t∈[0,1];
- 对于每条边,求出 t t t 的范围;
- 若所有方向上的 t i n ≤ t o u t t_{in} \le t_{out} tin≤tout,则线段可见;
- 减少不必要的剪裁操作。
物体绕任意向量 ( a , b , c ) (a, b, c) (a,b,c) 旋转的变换矩阵推导(Rodrigues公式)
:
- 原始点为 p ⃗ ∈ R 3 \vec{p} \in \mathbb{R}^3 p∈R3
- 旋转轴单位向量为 v ⃗ = ( a , b , c ) T \vec{v} = (a, b, c)^T v=(a,b,c)T,其中 ∣ v ⃗ ∣ = 1 |\vec{v}| = 1 ∣v∣=1
- 旋转角度为 θ \theta θ
目标是找出将任意点 p ⃗ \vec{p} p 绕向量 v ⃗ \vec{v} v 旋转 θ \theta θ 后的新坐标 p ⃗ ′ \vec{p}' p′。
Step 1:拆分分量
将点 p ⃗ \vec{p} p 拆成两部分:
-
平行于轴 v ⃗ \vec{v} v 的分量:
p ⃗ ∥ = ( v ⃗ ⋅ p ⃗ ) v ⃗ \vec{p}_{\parallel} = (\vec{v} \cdot \vec{p})\vec{v} p∥=(v⋅p)v -
垂直于轴的分量(记为 p ⃗ ⊥ \vec{p}_\perp p⊥):
p ⃗ ⊥ = p ⃗ − p ⃗ ∥ \vec{p}_\perp = \vec{p} - \vec{p}_\parallel p⊥=p−p∥
Step 2:绕轴旋转的几何表达
旋转后的结果为:
p ⃗ ′ = p ⃗ ∥ + p ⃗ ⊥ cos θ + ( v ⃗ × p ⃗ ) sin θ \vec{p}' = \vec{p}_{\parallel} + \vec{p}_\perp \cos\theta + (\vec{v} \times \vec{p}) \sin\theta p′=p∥+p⊥cosθ+(v×p)sinθ
解释:
-
p ⃗ ∥ \vec{p}_{\parallel} p∥:保持不变;
-
p ⃗ ⊥ \vec{p}_\perp p⊥:在垂直平面内旋转 θ \theta θ;
-
v ⃗ × p ⃗ \vec{v} \times \vec{p} v×p:与 v ⃗ \vec{v} v 和 p ⃗ ⊥ \vec{p}_\perp p⊥ 构成右手坐标系,作为旋转方向。为什么要加这一项?这是把垂直分量的旋转给分解了(参考图片中二维旋转的分解方式)。由于V是单位向量,所以 v ⃗ × p ⃗ \vec{v} \times \vec{p} v×p的模长等于P。
-
要想绕轴旋转角度 θ \theta θ,实际上是在垂直平面中进行二维旋转。二维旋转公式为:
p ⃗ ⊥ ′ = p ⃗ ⊥ cos θ + ( 垂直于 p ⃗ ⊥ ) ⋅ sin θ \vec{p}_\perp' = \vec{p}_\perp \cos\theta + (\text{垂直于 } \vec{p}_\perp)\cdot \sin\theta p⊥′=p⊥cosθ+(垂直于 p⊥)⋅sinθ
而在三维中,“垂直于 p ⃗ ⊥ \vec{p}_\perp p⊥”的方向由 v ⃗ × p ⃗ \vec{v} \times \vec{p} v×p 给出。因此,完整的旋转效果必须包括这两部分:
- p ⃗ ⊥ cos θ \vec{p}_\perp \cos\theta p⊥cosθ:旋转后的在原方向上的投影;
- ( v ⃗ × p ⃗ ) sin θ (\vec{v} \times \vec{p}) \sin\theta (v×p)sinθ:旋转后的“垂直于原向量”的分量。
Step 3:整理为矩阵形式
我们的目标是把下面这个向量公式:
p ⃗ ′ = p ⃗ cos θ + ( 1 − cos θ ) ( v ⃗ ⋅ p ⃗ ) v ⃗ + ( v ⃗ × p ⃗ ) sin θ \vec{p}' = \vec{p} \cos\theta + (1 - \cos\theta)(\vec{v} \cdot \vec{p}) \vec{v} + (\vec{v} \times \vec{p}) \sin\theta p′=pcosθ+(1−cosθ)(v⋅p)v+(v×p)sinθ
变成这种矩阵乘法形式:
p ⃗ ′ = R ⋅ p ⃗ 其中 R = I cos θ + ( 1 − cos θ ) v ⃗ v ⃗ T + [ v ⃗ ] × sin θ \vec{p}' = R \cdot \vec{p} \quad \text{其中 } R = I \cos\theta + (1 - \cos\theta)\vec{v}\vec{v}^T + [\vec{v}]_\times \sin\theta p′=R⋅p其中 R=Icosθ+(1−cosθ)vvT+[v]×sinθ
第一步:分析每一项的形式
我们设:
- v ⃗ = ( a , b , c ) T \vec{v} = (a, b, c)^T v=(a,b,c)T:单位旋转轴
- p ⃗ = ( x , y , z ) T \vec{p} = (x, y, z)^T p=(x,y,z)T:任意三维向量
原始公式中每一项的含义:
- p ⃗ cos θ \vec{p} \cos\theta pcosθ
这就是:
cos θ ⋅ I ⋅ p ⃗ ⇒ 矩阵形式为 I cos θ \cos\theta \cdot I \cdot \vec{p} \Rightarrow \text{矩阵形式为 } I \cos\theta cosθ⋅I⋅p⇒矩阵形式为 Icosθ
- ( v ⃗ ⋅ p ⃗ ) v ⃗ (\vec{v} \cdot \vec{p}) \vec{v} (v⋅p)v
这是一个向量-向量乘积形式:
( v ⃗ ⋅ p ⃗ ) v ⃗ = ( v ⃗ v ⃗ T ) p ⃗ (\vec{v} \cdot \vec{p}) \vec{v} = (\vec{v} \vec{v}^T)\vec{p} (v⋅p)v=(vvT)p
因为 v ⃗ v ⃗ T \vec{v} \vec{v}^T vvT 是一个 3 × 3 3 \times 3 3×3 矩阵,它作用在任意 p ⃗ \vec{p} p 上会得到 ( v ⃗ ⋅ p ⃗ ) v ⃗ (\vec{v} \cdot \vec{p}) \vec{v} (v⋅p)v。
例如:
v ⃗ = [ a b c ] ⇒ v ⃗ v ⃗ T = [ a 2 a b a c a b b 2 b c a c b c c 2 ] \vec{v} = \begin{bmatrix} a \\ b \\ c \end{bmatrix} \Rightarrow \vec{v} \vec{v}^T = \begin{bmatrix} a^2 & ab & ac \\ ab & b^2 & bc \\ ac & bc & c^2 \end{bmatrix} v= abc ⇒vvT= a2abacabb2bcacbcc2
所以:
( 1 − cos θ ) ( v ⃗ ⋅ p ⃗ ) v ⃗ = ( 1 − cos θ ) ( v ⃗ v ⃗ T ) p ⃗ (1 - \cos\theta)(\vec{v} \cdot \vec{p}) \vec{v} = (1 - \cos\theta)(\vec{v} \vec{v}^T)\vec{p} (1−cosθ)(v⋅p)v=(1−cosθ)(vvT)p
- ( v ⃗ × p ⃗ ) sin θ (\vec{v} \times \vec{p}) \sin\theta (v×p)sinθ
我们把叉乘写成矩阵乘法:
v ⃗ × p ⃗ = [ v ⃗ ] × ⋅ p ⃗ \vec{v} \times \vec{p} = [\vec{v}]_\times \cdot \vec{p} v×p=[v]×⋅p
其中, [ v ⃗ ] × [\vec{v}]_\times [v]× 是叉乘矩阵(反对称矩阵):
[ v ⃗ ] × = [ 0 − c b c 0 − a − b a 0 ] [\vec{v}]_\times = \begin{bmatrix} 0 & -c & b \\ c & 0 & -a \\ -b & a & 0 \end{bmatrix} [v]×= 0c−b−c0ab−a0
所以:
( v ⃗ × p ⃗ ) sin θ = sin θ ⋅ [ v ⃗ ] × ⋅ p ⃗ (\vec{v} \times \vec{p}) \sin\theta = \sin\theta \cdot [\vec{v}]_\times \cdot \vec{p} (v×p)sinθ=sinθ⋅[v]×⋅p
第四步:组合为矩阵运算
把三项加起来:
$$
\vec{p}’ = \cos\theta \cdot I \cdot \vec{p}
- (1 - \cos\theta) \cdot \vec{v} \vec{v}^T \cdot \vec{p}
- \sin\theta \cdot [\vec{v}]\times \cdot \vec{p}
KaTeX parse error: Can't use function '$' in math mode at position 5: 提取 $̲\vec{p}$,得到整体旋转…
\vec{p}’ = \left( \cos\theta I + (1 - \cos\theta)\vec{v} \vec{v}^T + \sin\theta [\vec{v}]\times \right)\vec{p}
$$
所以最后 Rodrigues 旋转矩阵就是:
R = cos θ I + ( 1 − cos θ ) v ⃗ v ⃗ T + sin θ [ v ⃗ ] × R = \cos\theta I + (1 - \cos\theta)\vec{v} \vec{v}^T + \sin\theta [\vec{v}]_\times R=cosθI+(1−cosθ)vvT+sinθ[v]×
这就是从向量形式 → 矩阵形式的全过程推导。
Step 4:展开成显式矩阵
设 v ⃗ = ( a , b , c ) T \vec{v} = (a, b, c)^T v=(a,b,c)T,则有:
R = [ a 2 ( 1 − cos θ ) + cos θ a b ( 1 − cos θ ) − c sin θ a c ( 1 − cos θ ) + b sin θ a b ( 1 − cos θ ) + c sin θ b 2 ( 1 − cos θ ) + cos θ b c ( 1 − cos θ ) − a sin θ a c ( 1 − cos θ ) − b sin θ b c ( 1 − cos θ ) + a sin θ c 2 ( 1 − cos θ ) + cos θ ] R = \begin{bmatrix} a^2(1 - \cos\theta) + \cos\theta & ab(1 - \cos\theta) - c\sin\theta & ac(1 - \cos\theta) + b\sin\theta \\ ab(1 - \cos\theta) + c\sin\theta & b^2(1 - \cos\theta) + \cos\theta & bc(1 - \cos\theta) - a\sin\theta \\ ac(1 - \cos\theta) - b\sin\theta & bc(1 - \cos\theta) + a\sin\theta & c^2(1 - \cos\theta) + \cos\theta \end{bmatrix} R= a2(1−cosθ)+cosθab(1−cosθ)+csinθac(1−cosθ)−bsinθab(1−cosθ)−csinθb2(1−cosθ)+cosθbc(1−cosθ)+asinθac(1−cosθ)+bsinθbc(1−cosθ)−asinθc2(1−cosθ)+cosθ
这个 3 × 3 3\times3 3×3 矩阵就是绕任意单位向量 ( a , b , c ) (a,b,c) (a,b,c) 旋转角度 θ \theta θ 的旋转矩阵。
- 分别带入单位基向量同样也可以求出变换矩阵:三维空间绕任意轴旋转矩阵的推导 - 知乎 (zhihu.com)
复杂无透明图像场景的消隐算法
1. Z-Buffer法(推荐)
- 为每个像素存一个深度值;
- 每绘制一个片段时:
- 比较当前深度与缓冲区深度;
- 更近的片段覆盖远处的;
- 优点:简单、适用性广、硬件支持。
- 缺点:不能处理半透明物体,需高精度缓冲防止z-fighting。
加速三角形填充的两种方法
方法一:扫描线算法(Scanline)
- 遍历每一行像素;
- 计算当前扫描线与三角形边的交点;
- 填充交点之间的像素;
- 适合光栅化的加速处理。
方法二:Barycentric坐标法
- 对于每个像素 ( x , y ) (x, y) (x,y),计算其在三角形中的重心坐标 ( α , β , γ ) (\alpha, \beta, \gamma) (α,β,γ);
- 如果 α , β , γ ∈ [ 0 , 1 ] \alpha, \beta, \gamma \in [0,1] α,β,γ∈[0,1],则该点在三角形内;
- 可直接插值颜色、纹理坐标等属性;
- GPU中广泛使用。
判断顶点是否在图形内(如多边形)
常见算法:射线法(Ray-Casting)
- 从点向任意方向引一条射线;
- 统计其与图形边界的交点数;
- 若为奇数次 → 点在图形内;
- 若为偶数次 → 点在图形外。
几何显示表示方式
几何图形通常表示为:
- 顶点(Vertices)+ 边(Edges)+ 面(Faces):
- 点: ( x , y , z ) (x,y,z) (x,y,z);
- 线:两个顶点;
- 面:三角形或多边形;
文件格式(如 .obj, .ply)中常见方式是使用三角网(Triangular Mesh)表示模型。
局部光照模型
局部光照模型(如Phong)只考虑相机-表面-光源三者之间的直接光照,不考虑环境间接光照(如全局光照或间接反射)。
包括:
- 环境光(Ambient)
- 漫反射光(Diffuse)
- 镜面反射光(Specular)
三种 Shading 的特点与区别
模型 | 特点 | 光照计算位置 | 效果 |
---|---|---|---|
Flat Shading | 每面一个颜色 | 多边形面中心 | 快速但不平滑 |
Gouraud Shading | 每顶点光照,插值颜色 | 顶点 | 平滑但高光可能错失 |
Phong Shading | 每像素插值法线,再光照 | 像素级 | 精细高光,耗时大 |
反射变换转化为旋转
反射矩阵的推导 - 知乎 (zhihu.com)
原理:二维中,对单位向量 n ⃗ \vec{n} n 的反射变换矩阵为:
R = I − 2 n ⃗ n ⃗ T R = I - 2 \vec{n}\vec{n}^T R=I−2nnT
这个操作等价于围绕垂直于 n ⃗ \vec{n} n 的方向旋转 180°。
在三维中,反射可以视作绕某平面法向的旋转(180°),例如绕对称轴或面进行旋转,即:
反射 = 旋转 + 坐标翻转 \text{反射} = \text{旋转} + \text{坐标翻转} 反射=旋转+坐标翻转
设点 A A A 到平面的投影是 B B B,那么:
O B → = ( I − n ⃗ n ⃗ T ) O A → \overrightarrow{OB} = (I - \vec{n}\vec{n}^T)\overrightarrow{OA} OB=(I−nnT)OA
这个等式表示:用 ( I − n ⃗ n ⃗ T ) (I - \vec{n}\vec{n}^T) (I−nnT) 这个投影矩阵将点 A A A 投影到平面上得到点 B B B。
所以:
O B → − O A → = [ ( I − n ⃗ n ⃗ T ) O A → ] − O A → \overrightarrow{OB} - \overrightarrow{OA} = \left[(I - \vec{n}\vec{n}^T)\overrightarrow{OA}\right] - \overrightarrow{OA} OB−OA=[(I−nnT)OA]−OA
O C → = O A → + 2 A B → = O A → + 2 ( O B → − O A → ) = O A → + 2 [ ( I − n ⃗ n ⃗ T ) O A → − O A → ] = O A → + 2 [ ( − n ⃗ n ⃗ T ) O A → ] = ( I − 2 n ⃗ n ⃗ T ) O A → \begin{aligned} \overrightarrow{O C} & =\overrightarrow{O A}+2 \overrightarrow{A B} \\ & =\overrightarrow{O A}+2(\overrightarrow{O B}-\overrightarrow{O A}) \\ & =\overrightarrow{O A}+2\left[\left(I-\vec{n} \vec{n}^T\right) \overrightarrow{O A}-\overrightarrow{O A}\right] \\ & =\overrightarrow{O A}+2\left[\left(-\vec{n} \vec{n}^T\right) \overrightarrow{O A}\right] \\ & =\left(I-2 \vec{n} \vec{n}^T\right) \overrightarrow{O A} \end{aligned} OC=OA+2AB=OA+2(OB−OA)=OA+2[(I−nnT)OA−OA]=OA+2[(−nnT)OA]=(I−2nnT)OA
代入原式就得到了:
O A → + 2 ( O B → − O A → ) = O A → + 2 [ ( I − n ⃗ n ⃗ T ) O A → − O A → ] \overrightarrow{OA} + 2(\overrightarrow{OB} - \overrightarrow{OA}) = \overrightarrow{OA} + 2\left[(I - \vec{n}\vec{n}^T)\overrightarrow{OA} - \overrightarrow{OA}\right] OA+2(OB−OA)=OA+2[(I−nnT)OA−OA]
所以,反射矩阵 M p = ( I − 2 n ⃗ n ⃗ T ) M_p=\left(I-2 \vec{n} \vec{n}^T\right) Mp=(I−2nnT)