当前位置: 首页 > ds >正文

山东大学计算机图形学期末复习9——CG12上

CG12上

  • 几何管线末端:顶点已组装成基本图元(Primitives,如点、线、三角形)。

    主要任务:

    • 裁剪:视锥体是一个三维空间区域(由近裁剪面、远裁剪面和侧面组成),超出该区域的图元需要被裁剪或剔除,以避免浪费计算资源。

      光栅化:将裁剪后的图元转化为屏幕上的像素(称为片段,Fragments)。这一过程也叫扫描转换(Scan Conversion),因为它涉及将连续的几何形状映射到离散的像素网格。

在这里插入图片描述

Cohen-Sutherland 2D线段裁剪算法概述

Cohen-Sutherland算法是计算机图形学中的一个经典算法,主要用于对2D图形进行裁剪。该算法通过简单的区域编码和逻辑运算高效地判断哪些线段与裁剪窗口相交,从而确定是否需要进行裁剪。通过这种方法,算法能在不计算每个交点的情况下迅速排除不需要裁剪的线段。

暴力裁剪与其问题

在暴力裁剪方法中,线段需要与裁剪窗口的四条边进行交点计算,检查每条边是否与线段相交。这意味着对于每条线段,我们需要多次计算交点,这会带来较大的计算负担,特别是在处理大量线段时。由于交点计算涉及浮点数除法,效率较低,因此我们需要一种更高效的方法。

Cohen-Sutherland算法的基本思路

Cohen-Sutherland算法通过区域编码(Outcode)来快速判断线段与裁剪窗口的关系。裁剪窗口由四条边界线定义,分别是:

  • x = x min x = x_{\text{min}} x=xmin(左边界)
  • x = x max x = x_{\text{max}} x=xmax(右边界)
  • y = y min y = y_{\text{min}} y=ymin(下边界)
  • y = y max y = y_{\text{max}} y=ymax(上边界)

算法的核心思想是利用区域编码来对每个线段的两个端点进行标记,并根据这些编码值来判断线段是否在窗口内、完全在窗口外,或者部分与窗口相交。通过这种方式,算法避免了不必要的交点计算,显著提高了效率。

区域编码(Outcode)

区域编码是一个4位二进制数,每一位表示端点相对于裁剪窗口四条边的情况:

  • 第1位:表示端点是否在 y max y_{\text{max}} ymax 以上
  • 第2位:表示端点是否在 y min y_{\text{min}} ymin 以下
  • 第3位:表示端点是否在 x max x_{\text{max}} xmax 右侧
  • 第4位:表示端点是否在 x min x_{\text{min}} xmin 左侧

在这里插入图片描述

通过这种编码,我们可以快速判定端点的位置,并根据这些信息判断线段的裁剪情况。

Cohen-Sutherland算法的步骤

  1. 计算区域编码:对线段的两个端点计算区域编码。
  2. 直接接受:如果两个端点的编码都为0000,说明线段完全在窗口内,可以直接接受,无需裁剪。
  3. 直接拒绝:如果两个端点的编码通过按位与运算(AND)得到非零值,说明线段完全在窗口外,可以直接丢弃。
  4. 需要裁剪:如果线段的两个端点一个在窗口内,另一个在窗口外,或者两个端点都在窗口外但位于不同区域,那么需要计算交点。
具体的裁剪步骤
  • 步骤1:计算两端点的区域编码。如果两端点的编码都是0000,接受线段;如果按位与(AND)后不为0,直接拒绝该线段。
  • 步骤2:如果需要裁剪,选择一个在窗口外的端点,计算它与窗口边界的交点。
  • 步骤3:将交点替代外侧端点,重新计算该端点的区域编码,并返回步骤1。如果仍需要裁剪,则继续迭代。

Cyrus-Beck算法

Cyrus-Beck算法思想-CSDN博客

Cyrus-Beck 算法是一个用于线段与凸多边形裁剪的经典算法,适用于图形学中各种裁剪问题。算法的核心思想是利用向量运算和参数化技术来判断线段与多边形边的交点,从而高效地裁剪出符合条件的线段。我们将根据以下步骤来详细讲解其原理与实现。

1. 线段与多边形的交点计算

首先,我们将线段通过参数方程表示。线段 P 0 P 1 P_0P_1 P0P1 的方程可以写成:
P ( t ) = P 0 + t ( P 1 − P 0 ) P(t) = P_0 + t (P_1 - P_0) P(t)=P0+t(P1P0)
其中, P 0 P_0 P0 P 1 P_1 P1 分别是线段的起点和终点, t t t 是参数,表示线段上的任意一点。当 t t t 从 0 变化到 1 时, P ( t ) P(t) P(t) 代表从 P 0 P_0 P0 P 1 P_1 P1 的整条线段。

对于多边形的每条边,我们也可以将其表示为参数方程。因此,求解交点,也就是求解t,需要把线段的方程带入到交点的等式当中。见下图:

在这里插入图片描述

2. 向量点积与线段与边的关系判断

Cyrus-Beck 算法利用向量点积来判断线段端点相对于多边形边的位置。对于每条多边形边,我们有一个法向量 N \mathbf{N} N,它垂直于该边。线段上的任意一点 P ( t ) P(t) P(t) 相对于该边的位置可以通过计算以下表达式来判断:
N ⋅ ( P ( t ) − A ) \mathbf{N} \cdot (P(t) - A) N(P(t)A)
其中, A A A 是多边形边上的一个点, N \mathbf{N} N 是该边的法向量, P ( t ) P(t) P(t) 是当前线段上的点。

  • 如果 N ⋅ ( P ( t ) − A ) > 0 \mathbf{N} \cdot (P(t) - A) > 0 N(P(t)A)>0,则点 P ( t ) P(t) P(t) 位于多边形边的外侧。
  • 如果 N ⋅ ( P ( t ) − A ) = 0 \mathbf{N} \cdot (P(t) - A) = 0 N(P(t)A)=0,则点 P ( t ) P(t) P(t) 在多边形边上或边的延长线上。
  • 如果 N ⋅ ( P ( t ) − A ) < 0 \mathbf{N} \cdot (P(t) - A) < 0 N(P(t)A)<0,则点 P ( t ) P(t) P(t) 位于多边形的内侧。

通过这一方法,Cyrus-Beck 算法能够快速判断一个线段是否完全在多边形内,或者是否需要进一步进行裁剪。

3. 从起点组里选择最大值,从终点组中选择最小值来作为线段和多边形实际的交点
4. 伪代码
for (k edges of clipping polygon)
{solve Ni·(p1-p0);solve Ni.(p0-Ai);if ( Ni·(p1-p0) == 0) //parallel with the edge{if ( Ni.(p0-Ai) < 0 )break; /linvisibleelsego to next edge;}else // Ni·(p1-p0) != 0{solve ti;if ( Ni (p1-p0) < 0)te = min(1, min(ti, te));elsets = max(0, max(ti, ts));}
}

解析:

目标与方法总览

我们不想用暴力法去求线段与每条边的交点,而是想用数学的方法判断线段与边界的关系

Cyrus-Beck 算法的做法是:

➤ 用 参数 t ∈ [0, 1] 来表示线段上的点:
  • 线段用参数方程表示:
    P ( t ) = P 0 + t ( P 1 − P 0 ) P(t) = P_0 + t(P_1 - P_0) P(t)=P0+t(P1P0)

    • t = 0 t = 0 t=0 时, P ( t ) = P 0 P(t) = P_0 P(t)=P0
    • t = 1 t = 1 t=1 时, P ( t ) = P 1 P(t) = P_1 P(t)=P1
    • t ∈ ( 0 , 1 ) t \in (0, 1) t(0,1) 时, P ( t ) P(t) P(t) 是在线段之间的点
➤ 遍历多边形的每一条边,根据边的法向量 N i N_i Ni,判断:
  • 线段是从边的外部进入(潜在进入点 PE)
  • 还是从内部离开(潜在离开点 PL)
关键思路:如何判断是进入还是离开?

我们有三样东西:

  • d ⃗ = P 1 − P 0 \vec{d} = P_1 - P_0 d =P1P0:线段方向向量
  • N ⃗ i \vec{N}_i N i:多边形某一条边的外法向量
  • A i A_i Ai:该边上的某个点

计算两个点积:

含义
N ⃗ i ⋅ d ⃗ \vec{N}_i \cdot \vec{d} N id 判断线段是否与边平行/进入/离开
N ⃗ i ⋅ ( P 0 − A i ) \vec{N}_i \cdot (P_0 - A_i) N i(P0Ai)判断起点是在边的哪一侧
伪代码结构分析

我们现在一步步解释这段伪代码是怎么构建的。

初始化:准备裁剪
for (k edges of clipping polygon)
  • 遍历多边形的每条边(比如 6 边形就要处理 6 次)
Step 1:计算两个点积
solve Ni·(p1 - p0);   // 线段方向与边的法向量的点积
solve Ni·(p0 - Ai);   // 起点到边上的点,与边的法向量点积
  • 第一项告诉我们线段与边是否平行或者是否穿过边界
  • 第二项判断起点在边的哪一侧
Step 2:判断平行情况
if (Ni·(p1 - p0) == 0)
{if (Ni·(p0 - Ai) < 0)break; // Line is completely outside polygonelsego to next edge;
}

如果线段与边平行:

  • 并且在外侧:直接结束,线段不可见(完全在外侧)
  • 在内侧或边上:继续检查下一条边
Step 3:计算交点参数 t i t_i ti

如果线段不平行,就有可能与该边相交:

solve ti;

我们要求解:
t i = N ⃗ i ⋅ ( A i − P 0 ) N ⃗ i ⋅ ( P 1 − P 0 ) t_i = \frac{ \vec{N}_i \cdot (A_i - P_0) }{ \vec{N}_i \cdot (P_1 - P_0) } ti=N i(P1P0)N i(AiP0)
这个公式就是将 P ( t ) P(t) P(t) 代入边的平面方程,求得交点参数 t t t

Step 4:分类交点类型(PE 或 PL)
if (Ni·(p1 - p0) < 0)te = min(1, min(ti, te)); // 潜在离开点
elsets = max(0, max(ti, ts)); // 潜在进入点
  • 如果法向量朝着线段的前进方向(dot product < 0),说明线段会离开多边形 => 更新离开点 te
  • 如果法向量背对线段的方向(dot product > 0),说明线段从这里进入多边形 => 更新进入点 ts

我们要在所有边中,找到:

  • 最大的进入点 t s t_s ts
  • 最小的离开点 t e t_e te
最后输出裁剪结
if (ts > te)return nil; // 不可见,进入在离开之后
elsereturn P(ts), P(te); // 可见线段部分

如果进入点 t s ts ts 比离开点 t e te te 晚,说明线段只在外部滑过,没有进入 => 剪裁结果为空。

否则,返回的是裁剪后保留在线段上的区间 [ t s , t e ] [ts, te] [ts,te],即:
P ( t s ) = P 0 + t s ( P 1 − P 0 ) P ( t e ) = P 0 + t e ( P 1 − P 0 ) P(t_s) = P_0 + t_s (P_1 - P_0) \\ P(t_e) = P_0 + t_e (P_1 - P_0) P(ts)=P0+ts(P1P0)P(te)=P0+te(P1P0)

Liang-Barsky Algorithm

在这里插入图片描述

一种特殊情况,即多边形为矩形。参考这篇写得极好的博客,这里不做介绍了。

[OpenGL]计算机图形学:直线裁剪算法中Cohen-Sutherland算法和Liang-Barsky算法_opengl梁友栋裁剪算法例题-CSDN博客

裁剪窗口的边界

我们考虑的窗口是矩形,由四条边组成:

  • 左边界: x = x L x = x_L x=xL
  • 右边界: x = x R x = x_R x=xR
  • 下边界: y = y B y = y_B y=yB
  • 上边界: y = y T y = y_T y=yT

线段参数表示法

我们把线段表示为参数形式:
P ( t ) = ( x ( t ) , y ( t ) ) = ( x 1 + t Δ x , y 1 + t Δ y ) , 0 ≤ t ≤ 1 P(t) = (x(t), y(t)) = (x_1 + t \Delta x, y_1 + t \Delta y), \quad 0 \le t \le 1 P(t)=(x(t),y(t))=(x1+tΔx,y1+tΔy),0t1
其中:
Δ x = x 2 − x 1 , Δ y = y 2 − y 1 \Delta x = x_2 - x_1, \quad \Delta y = y_2 - y_1 Δx=x2x1,Δy=y2y1
我们希望找到参数 t t t 的范围,使得 P ( t ) P(t) P(t) 落在矩形窗口内。


与每条边相交的条件推导

我们来看看线段与窗口的每条边相交的条件:


与左边界 x = x L x = x_L x=xL 相交

我们想找出线段进入或离开左边界的点。

设当前点为:
P ( t ) = ( x 1 + t Δ x , y 1 + t Δ y ) P(t) = (x_1 + t \Delta x, y_1 + t \Delta y) P(t)=(x1+tΔx,y1+tΔy)
条件:
x ( t ) ≥ x L ⇒ x 1 + t Δ x ≥ x L x(t) \ge x_L \quad \Rightarrow \quad x_1 + t \Delta x \ge x_L x(t)xLx1+tΔxxL
变形:
t ≥ x L − x 1 Δ x 当 Δ x > 0 ⇒ 进入点 t \ge \frac{x_L - x_1}{\Delta x} \quad \text{当} \quad \Delta x > 0 \Rightarrow \text{进入点} tΔxxLx1Δx>0进入点
如果 Δ x < 0 \Delta x < 0 Δx<0,方向相反,说明是离开点

我们定义如下两个变量:

  • r k = − Δ x r_k = -\Delta x rk=Δx
  • s k = x 1 − x L s_k = x_1 - x_L sk=x1xL

于是 t k = s k r k = x 1 − x L − Δ x t_k = \frac{s_k}{r_k} = \frac{x_1 - x_L}{- \Delta x} tk=rksk=Δxx1xL


与右边界 x = x R x = x_R x=xR 相交

推导类似:
x ( t ) ≤ x R ⇒ x 1 + t Δ x ≤ x R ⇒ t ≤ x R − x 1 Δ x x(t) \le x_R \quad \Rightarrow \quad x_1 + t \Delta x \le x_R \Rightarrow t \le \frac{x_R - x_1}{\Delta x} x(t)xRx1+tΔxxRtΔxxRx1
记:

  • r k = Δ x r_k = \Delta x rk=Δx
  • s k = x R − x 1 s_k = x_R - x_1 sk=xRx1
  • t k = s k r k t_k = \frac{s_k}{r_k} tk=rksk

与下边界 y = y B y = y_B y=yB

同理,要求:
y ( t ) ≥ y B ⇒ t ≥ y B − y 1 Δ y y(t) \ge y_B \quad \Rightarrow \quad t \ge \frac{y_B - y_1}{\Delta y} y(t)yBtΔyyBy1
记:

  • r k = − Δ y r_k = -\Delta y rk=Δy
  • s k = y 1 − y B s_k = y_1 - y_B sk=y1yB
  • t k = s k r k t_k = \frac{s_k}{r_k} tk=rksk

与上边界 y = y T y = y_T y=yT

同理:
y ( t ) ≤ y T ⇒ t ≤ y T − y 1 Δ y y(t) \le y_T \Rightarrow t \le \frac{y_T - y_1}{\Delta y} y(t)yTtΔyyTy1
记:

  • r k = Δ y r_k = \Delta y rk=Δy
  • s k = y T − y 1 s_k = y_T - y_1 sk=yTy1
  • t k = s k r k t_k = \frac{s_k}{r_k} tk=rksk
综合表示

我们整理得到:
{ r 1 = − Δ x , s 1 = x 1 − x L r 2 = Δ x , s 2 = x R − x 1 r 3 = − Δ y , s 3 = y 1 − y B r 4 = Δ y , s 4 = y T − y 1 ⇒ t k = s k r k , k = 1 , 2 , 3 , 4 \begin{cases} r_1 = -\Delta x, & s_1 = x_1 - x_L \\ r_2 = \Delta x, & s_2 = x_R - x_1 \\ r_3 = -\Delta y, & s_3 = y_1 - y_B \\ r_4 = \Delta y, & s_4 = y_T - y_1 \\ \end{cases} \quad\Rightarrow\quad t_k = \frac{s_k}{r_k}, \quad k = 1,2,3,4 r1=Δx,r2=Δx,r3=Δy,r4=Δy,s1=x1xLs2=xRx1s3=y1yBs4=yTy1tk=rksk,k=1,2,3,4

  • 如果 r k < 0 r_k < 0 rk<0:表示线段进入区域(进入点)
  • 如果 r k > 0 r_k > 0 rk>0:表示线段离开区域(离开点)
  • 如果 r k = 0 r_k = 0 rk=0 s k < 0 s_k < 0 sk<0:线段平行并在边界外,不可见
  • 如果 r k = 0 r_k = 0 rk=0 s k ≥ 0 s_k \ge 0 sk0:线段平行但在边界内,处理其他边
http://www.xdnf.cn/news/7067.html

相关文章:

  • 【部署】读取excel批量导入dify的QA知识库
  • 【Changer解码头详解及融入neck层数据的实验设计】
  • Fidder基本操作
  • Spring Initializr快速创建项目案例
  • Spark,连接MySQL数据库,添加数据,读取数据
  • Foupk3systemX5OS邮箱上线通知
  • Cadence Allegro安装教程及指导
  • Almalinux中出现ens33 ethernet 未托管 -- lo loopback 未托管 --如何处理:
  • JWT令牌验证
  • 45、简述web.config⽂件中的重要节点
  • Leaflet使用SVG创建动态Legend
  • 文件读取漏洞路径与防御总结
  • AI日报 - 2024年5月17日
  • PyTorch实现三元组损失Triplet Loss
  • 风控域——风控决策引擎系统设计
  • 考研数学微分学(第三,四,五,六,七讲)
  • 【前端基础】HTML元素隐藏的四个方法(display设置为none、visibikity设置为hidden、rgba设置颜色、opacity设置透明度)
  • 软件设计师教程—— 第二章 程序设计语言基础知识(上)
  • Spatial Transformer Layer
  • Vue3学习(组合式API——ref模版引用与defineExpose编译宏函数)
  • 信贷域——互联网金融业务
  • 低空经济发展现状与前景
  • 聚集索引 vs. 非聚集索引
  • 恒大歌舞团全集
  • Android 14 解决打开app出现不兼容弹窗的问题
  • 参考工具/网站
  • scss additionalData Can‘t find stylesheet to import
  • 强化学习入门:马尔科夫奖励过程二
  • 什么是API接口?API接口的核心价值
  • 网关GateWay——连接不同网络的关键设备