山东大学计算机图形学期末复习11——CG13上
CG13上
review
Cohen-Sutherland 线段裁剪算法
- 用途:裁剪二维线段,适用于矩形窗口。
- 核心思想:使用每个端点的 区域编码(Outcode),快速判断线段:
- 完全在内(接受)
- 完全在外(拒绝)
- 部分在内(计算交点)
- 效率技巧:通过位运算判断是否需要裁剪,避免不必要的交点计算。
- 适合场景:矩形窗口裁剪。
Cyrus-Beck 线段裁剪算法
- 用途:裁剪二维线段,适用于任意凸多边形窗口。
- 核心思想:
- 使用线段的参数方程 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 i t_i ti,根据 法向量点积判断是进入还是离开边界。
- 最终保留 t ∈ [ t enter , t leave ] t \in [t_{\text{enter}}, t_{\text{leave}}] t∈[tenter,tleave] 范围的线段。
- 优势:适用于任意凸多边形,比 C-S 更通用。
- 关键工具:向量点积判断方向。
Liang-Barsky 线段裁剪算法
-
用途:裁剪线段,优化版本的 Cohen-Sutherland。
-
核心思想:
-
将线段写成参数形式,利用不等式裁剪:
x = x 0 + t Δ x , y = y 0 + t Δ y , 0 ≤ t ≤ 1 x = x_0 + t \Delta x,\quad y = y_0 + t \Delta y,\quad 0 \leq t \leq 1 x=x0+tΔx,y=y0+tΔy,0≤t≤1 -
将裁剪条件转化为关于 t t t 的不等式,然后解出 t min , t max t_{\min}, t_{\max} tmin,tmax。
-
-
优势:比 C-S 更少计算,更适合浮点窗口裁剪。
Sutherland-Hodgman 多边形裁剪算法
- 用途:裁剪任意多边形(常用于多边形对矩形窗口的裁剪)。
- 核心思想:
- 每次用一个边界裁剪多边形,将其变为新的子多边形。
- 多边形顶点逐边送入,依据“进出判断”:
- 输入点在边内 → 保留。
- 边跨界 → 计算交点。
- 一轮裁剪一条边,共进行四轮(左、右、下、上)。
- 限制:适用于凸裁剪窗口,原多边形可为任意形状。
DDA & Bresenham 线段扫描转换(光栅化)
DDA(Digital Differential Analyzer)算法
- 原理:直线方程 y = m x + b y = mx + b y=mx+b,每次 x x x 增 1, y y y 增 m m m,写入 ( x , r o u n d ( y ) ) (x, round(y)) (x,round(y))。
- 特点:使用浮点加法,适合简单实现,但效率稍低。
Bresenham 算法
- 原理:只用整数加法和比较,每步决定取哪一个像素(右 or 右上),避免浮点。
- 核心工具:构造 决策变量 d d d,用增量更新进行高效像素选择。
- 优势:运行快,精度高,广泛用于实际图形硬件和软件中。
光栅化知识体系详解:扫描转换、隐藏面、抗锯齿
1. 图形渲染目标回顾
本章核心目标:
- 光栅化:多边形扫描转换算法
- 隐藏面消除:如深度缓冲区算法
- 抗锯齿处理:解决锯齿边缘
这些任务构成图形渲染管线中光栅化阶段的主要挑战。
2. 图形管线回顾(OpenGL 管线)
OpenGL命令 → 顶点 → 逐顶点操作 → 光栅化 → 片段 → 着色 → 帧缓冲 → 显示像素
- 光栅化(Rasterization):输入为三角形等几何图元,输出为片段(fragments)
- 每个片段对应一个像素位置(x, y)和属性(颜色、深度、纹理坐标等)
3. 多边形扫描转换(Scan Conversion)
基本思想:
将多边形“转换”为填满像素格的区域
4. 多边形内部判断方法
4.1 奇偶规则(Odd-Even Rule)
- 从测试点向外画一条射线
- 统计与边的交点数,若为奇数 → 内部,否则为外部
4.2 缠绕数规则(Winding Number)
- 考虑边的方向(顺/逆时针)
- 点相对多边形的“绕圈次数”
- 非零为内部,0为外部
- 更稳定、适用于自交和多环多边形
5. OpenGL 对凹多边形的处理限制
- OpenGL 默认只支持凸多边形
- 凹多边形需先细分(Tessellation)为三角形
- 常用算法:
- 耳切割法(Ear Clipping)
- 约束 Delaunay 三角化(Constrained Delaunay)
- 常用算法:
6. 多边形填充的主要方法:扫描线填充算法(Scan-Line Fill)
核心思想:
对每一条水平扫描线,找出与多边形的交点,然后成对填充交点之间的像素
7. 扫描线填充算法详细流程
主要步骤:
- 构建边表(Edge Table, ET)
- 按y坐标排序每条边的信息:
- ymin、ymax、x在ymin处的值、斜率的倒数(1/m)
- 按y坐标排序每条边的信息:
- 初始化活动边表(AET)
- 当前扫描线交的边,从ET中提取加入AET
- 对当前扫描线:
- 计算交点:使用斜率增量法更新交点x
- 排序交点x
- 每两个交点间填充像素
- 更新AET:
- 删除无效边(当前y ≥ ymax)
- 其余边更新x值:x += 1/m
- 下移一条扫描线(y++)
- 重复直到所有边处理完毕
算法系列之十二:多边形区域填充算法--扫描线填充算法(有序边表法)-CSDN博客
8. 数据结构详解
边表(Edge Table)
ymin | ymax | x(ymin) | 1/m |
---|---|---|---|
10 | 50 | 25.0 | 0.5 |
- 每条边插入其y最小值所在的桶(按y分组)
活动边表(AET)
- 按x排序的当前活动边
- 每次扫描线更新后计算交点用于填充
9. 扫描线填充中的奇点问题(Singularities)
常见奇点:
情况 | 问题 |
---|---|
多边形顶点恰好落在扫描线上 | 可能被重复计数,影响奇偶判断 |
水平边 | 是否交点?不处理会导致多填或漏填 |
多条边交汇于一点 | 如何避免交点重复或遗漏? |
解决方案:
- 对上端点不计交点,下端点计入交点(解决顶点重数)
- 水平边不计为交点
- 交点排序后,两两配对填充,避免重叠
10. 洪泛填充(Flood Fill)
原理:
- 从一个内部“种子点”开始,递归地向相邻像素传播填色,直到遇到边界
两种连接方式:
- 4连通(上下左右)
- 8连通(加上对角线)
缺点:
- 大面积填充时会导致栈溢出
- 填充效率不如扫描线填充
11. 扫描线洪泛填充
改进:
- 用栈或队列代替递归
- 每次填充一个线段而不是一个像素
- 比普通Flood Fill更高效
12. 像素属性插值(Gouraud填充)
- 顶点颜色 → 边上插值 → 扫描线插值
- 公式:
若 C4 是 C1 和 C2 之间的点:
C 4 = ( 1 − t ) ⋅ C 1 + t ⋅ C 2 C_4 = (1 - t) \cdot C_1 + t \cdot C_2 C4=(1−t)⋅C1+t⋅C2 - 优点:
- 实现平滑颜色渐变
- 每个像素只需一次线性插值
13. 深度测试(z-buffer)
- 每个像素记录当前最小深度值
- 渲染新片段时,若新片段更近 → 更新颜色与深度
- 解决“隐藏面问题”
14. 锯齿效应(Aliasing)
原因:
- 几何图元是连续的,像素是离散的,导致边缘呈锯齿
解决方法(抗锯齿):
- 超采样(Super-sampling):每像素采多个子像素
- 多重采样(MSAA):只对边缘像素执行多重采样
- 混合边缘颜色:模糊锐利边界
图形学中的光栅化一致性与隐藏面消除完整知识体系
一、区域一致性原理(Coherence)
区域一致性(Coherence)指的是图形几何在空间和时间上具有局部规律性,可用于优化图形处理算法。
1.1 区域一致性(Region Coherence)
在扫描填充中,许多像素的可见性/颜色在空间上连续或相同通过构建梯形结构(Trapezoid)作为多边形扫描填充的最小单位,可以成组处理像素块优势:减少逐像素的判断和计算批量填充提高效率
1.2 扫描线一致性(Scan-Line Coherence)
邻近的扫描线之间的交点位置变化很小同一个多边形在相邻扫描线上的交点数量通常保持不变(或变化规律简单)用途:交点x坐标用增量更新代替每次重新计算只需在边表中维护x和斜率倒数dx(1/m)
1.3 边一致性(Edge Coherence)
多边形的边与连续扫描线的交点在x方向是连续变化的扫描线高度变化1像素,边交点x只需加上Δx=1时的斜率变化(1/m)实现方式:在活动边表中记录每条边的x值和1/m,每次扫描线更新边交点x += 1/m
二、隐藏面消除(Hidden Surface Removal)
2.1 问题定义
- 在三维场景中,多个物体可能重叠
- 观察者只能看到最前面的面
- 所以需要消除被遮挡的“隐藏面”,避免不必要的渲染
三、图像空间方法(Image-Space Approaches)
这些方法直接在像素空间判断可见性。
3.1 光线投射(Ray Casting)
- 每个像素发出一条光线,找出最先相交的物体
- 优点:直观,便于实现阴影、反射
- 缺点:每像素都要做复杂的几何求交,效率低
3.2 Z-Buffer 算法(深度缓冲)
图形硬件最常用的方法
- 每个像素记录一个“当前最近”的深度值 z
- 渲染时比较新的像素 z 值:
- 更小(更近)→ 更新颜色和 z 值
- 否则丢弃该片段
Z-Buffer 实现流程
- 初始化所有 z 值为最大值(如 ∞)
- 遍历所有图元(三角形等)
- 对每个像素:
- 计算其 z 值
- 与缓冲区 z 值比较,决定是否绘制
示例说明:
- 起始:屏幕像素为背景色,z缓冲为∞
- 逐像素更新颜色和深度,直到图像完成
优势:
- 简单、通用、适合硬件并行
- 不依赖绘制顺序(不像画家算法)
四、Z 值增量计算优化
在 扫描线填充 和 Z-buffer 隐藏面消除 中,我们需要知道每个像素的 z 值(深度),判断是否被遮挡。
但如果我们每次都用方程去重新计算 z,会涉及乘除法、耗时。
所以我们希望能:
只加一个常数
就能从左一个像素的 z 值推导出右一个像素的 z 值
这就是 z 值的增量计算(Incremental Z-Calculation)
4.1 原理
- 假设多边形在三维中是一个平面:
- 满足 a x + b y + c z + d = 0 ax + by + cz + d = 0 ax+by+cz+d=0
- 对深度 z 进行增量更新:
a Δ x + b Δ y + c Δ z = 0 ⇒ Δ z = − a c Δ x aΔx + bΔy + cΔz = 0 \Rightarrow Δz = -\frac{a}{c} Δx aΔx+bΔy+cΔz=0⇒Δz=−caΔx
- 在扫描线上:Δy = 0,因此可简化为:
Δ z = − a c Δz = -\frac{a}{c} Δz=−ca
- 即:沿扫描线水平移动一个像素,z值只需加一个常数
五、画家算法(Painter’s Algorithm)
5.1 原理:
- 将所有图形元素从远到近排序
- 后绘制的图元会覆盖前面的像素
- 类似“画家涂色”:远处先涂,近处覆盖
5.2 步骤:
- 按 z 坐标对多边形排序
- 依序绘制,每个新的图元可能覆盖旧图元
5.3 局限:
- 不能解决复杂重叠情况(如A挡B,B挡C,C挡A)
- 会出现“循环遮挡”问题
- 需要配合分割算法或使用 Z-Buffer 替代
六、深度排序(Depth Sort)
- 画家算法的前提:需要对图形按深度排序
6.1 排序算法:
- 一般复杂度 O(n log n)
- 对于互不遮挡的多边形,排序容易
- 若图形互相遮挡,需要分割处理或引入额外结构
七、隐藏面消除中的特殊情况分类
7.1 简单情况(Easy Cases)
7.2 复杂情况(Hard Cases)
- 多边形在x、y、z方向都重叠
- 存在交错遮挡、嵌套结构
- 需使用更复杂算法如:
- Z-buffer
- 图形划分(如 BSP 树)
八、背面剔除(Back-Face Culling)
8.1 原理:
- 对于封闭的、不透明模型,其背面始终不可见
- 可通过判断法向量方向快速剔除
8.2 实现:
OpenGL 控制命令:
glEnable(GL_CULL_FACE); // 开启剔除
glCullFace(GL_BACK); // 剔除背面
调试渲染模式:
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_LINE); // 背面以线框显示
- 常用于调试或部分透明渲染
九、可见性测试优化(如游戏引擎中)
9.1 目标:
- 尽早剔除不可见物体,避免浪费资源
9.2 方法:BSP 树(Binary Space Partition)
- 用平面将三维空间不断划分
- 每个多边形分配给某个区域
- 渲染时根据观察者位置按顺序访问区域
9.3 示例说明:
- 多边形 A 被用作划分平面
- 将空间划分为前区(B, C)与后区(D, E, F)
十、综合算法:扫描线 + Z-buffer + Gouraud 着色
特点:
- 扫描线水平推进,每次处理一行像素
- 对每一行的像素:
- 利用增量方式计算交点、颜色、z值
- 在多个图形重叠时,使用 Z-buffer 判定可见性