图形学初识--多边形剪裁算法

文章目录

  • 前言
  • 正文
    • 为什么需要多边形剪裁算法?
    • 前置知识
      • 二维直线
        • 直线方程:
        • 距离本质:
        • 点和直线距离关系:
      • 三维平面
        • 平面方程
        • 距离本质:
        • 点和直线距离关系:
    • Suntherland hodgman算法
      • 基本介绍
      • 基本思想
      • 二维举例
        • 问题描述:
        • 核心思路:
        • 算法补充:
      • 三维拓展
  • 结尾:你们的点赞 + 关注就是我创作的最大动力!加油!

前言

前面一些章节主要针对各种矩阵变换,模型变换、视图变换、投影变换、屏幕空间变换等等!这一节咱们补充一下多边形剪裁算法的内容,主要讲解一下为什么需要,以及介绍二、三维下三角形裁剪的基本思路。

正文

为什么需要多边形剪裁算法?

以三角形为例,经过了视图变换和投影变换后,咱们已经将三角形所有的顶点坐标转换成了裁剪空间的坐标,咱们得目标只是为了获得 [ − 1 , 1 ] 3 [-1,1]^3 [1,1]3 包围盒内的顶点构成的三角形,但是必定有些三角形的顶点既有在立方体内部的,也有在外部的,这时候必定需要对其进行转化,从而变成内部的!

以二维举例:以下为三角形裁剪的示意图:

在这里插入图片描述

我们发现,其实二维下的三角形的顶点分支大致分为三类情况:

  • (1)三角形的三个顶点都在可视坐标范围内。这种情况不需要裁剪
  • (2)三角形的三个顶点既有可视坐标范围内,也有可视范围外。这种情况就是裁剪算法发挥的地方!
  • (3)三角形的三个顶点都不在可视坐标范围内。这种情况不需要裁剪

我们发现上述的绿色三角形在可视范围内是一个类似楔形的四边形,这时候需要对其分割成两个三角形才行!其他更多情况,大家可自行画示意图理解即可!

前置知识

二维直线

直线方程:

二维空间下,直线方程一般有几种表达形式,如: y = k x + b , a x + b y − c = 0 y = kx+b, ax + by - c = 0 y=kx+b,ax+byc=0 等等,但是为了工程方面的应用,可以用向量进行表达,如下:
a x + b y = d ( a b ) ⋅ ( x y ) = d \begin{align} ax +by &= d\\ \begin{pmatrix} a\\b \end{pmatrix} \cdot \begin{pmatrix} x\\y \end{pmatrix}&=d \end{align} ax+by(ab)(xy)=d=d
n ⃗ = ( a b ) \vec{n} = \begin{pmatrix}a\\b\end{pmatrix} n =(ab) 且它为单位向量, p ⃗ = ( x y ) \vec{p}=\begin{pmatrix}x\\y\end{pmatrix} p =(xy),则带入上式可得: n ⃗ ⋅ p ⃗ = d \vec{n} \cdot \vec{p} = d n p =d

上式表达的本质,可理解为:所有满足向 n ⃗ \vec{n} n ​ 投影长度为d的点集合,示意图如下:

在这里插入图片描述

距离本质:

当d值变化时,表达的是沿着 n ⃗ \vec n n 方向滑动的变化情况,当 d > 0 d>0 d>0,往 n ⃗ \vec n n 指向的方向进行滑动,当 d < 0 d<0 d<0,往反方向滑动,当 d = = 0 d==0 d==0​ 时,则表达过原点的直线!如下图所示:

在这里插入图片描述

点和直线距离关系:

当我们将空间中任一点 p 0 = ( x 0 , y 0 ) p_0 = (x_0,y_0) p0=(x0,y0),带入上述方程,究竟代表什么含义呢?

其实我们得到的就是 p 0 p_0 p0 n ⃗ \vec n n 上的一个投影,具体如下:
n ⃗ ⋅ p ⃗ 0 − d > 0 ,则表示该点在直线的 n ⃗ 方向正侧 n ⃗ ⋅ p ⃗ 0 − d < 0 ,则表示该点在直线的 n ⃗ 方向反侧 n ⃗ ⋅ p ⃗ 0 − d = 0 ,则表示该点就在直线上 \vec n \cdot \vec p_0 - d > 0,则表示该点在直线的\vec n 方向正侧\\ \vec n \cdot \vec p_0 - d < 0,则表示该点在直线的\vec n 方向反侧\\ \vec n \cdot \vec p_0 - d = 0,则表示该点就在直线上\\ n p 0d>0,则表示该点在直线的n 方向正侧n p 0d<0,则表示该点在直线的n 方向反侧n p 0d=0,则表示该点就在直线上
示意图如下所示:

在这里插入图片描述

三维平面

平面方程

根据二维直线表达,同理在三维中,一个平面方程可表达成: a x + b y + c z = d ax+by+cz = d ax+by+cz=d,同理记 n ⃗ = ( a b c ) \vec{n} = \begin{pmatrix}a\\b\\c\end{pmatrix} n = abc p ⃗ = ( x y z ) \vec{p} = \begin{pmatrix}x\\y\\z\end{pmatrix} p = xyz

则可得到 n ⃗ ⋅ p ⃗ = d \vec n \cdot \vec p = d n p =d

类似的当我们保证 n ⃗ \vec n n 为单位向量时,此关系式可以理解为三维空间中,所有满足向 n ⃗ \vec{n} n 投影长度为d的点集合,其实也就是一个平面,如下图所示:

在这里插入图片描述

距离本质:

当d值变化时,表达的是沿着 n ⃗ \vec n n 方向滑动的变化情况,当 d > 0 d>0 d>0,往 n ⃗ \vec n n 指向的方向进行滑动,当 d < 0 d<0 d<0,往反方向滑动,当 d = = 0 d==0 d==0 时,则表达过平面的点!如下图所示:

在这里插入图片描述

点和直线距离关系:

当我们将空间中任一点 p 0 = ( x 0 , y 0 , z 0 ) p_0 = (x_0,y_0,z_0) p0=(x0,y0,z0),带入上述方程,究竟代表什么含义呢?

其实我们得到的就是 p 0 p_0 p0 n ⃗ \vec n n 上的一个投影,具体如下:
n ⃗ ⋅ p ⃗ 0 − d > 0 ,则表示该点在平面的 n ⃗ 方向正侧 n ⃗ ⋅ p ⃗ 0 − d < 0 ,则表示该点在平面的 n ⃗ 方向反侧 n ⃗ ⋅ p ⃗ 0 − d = 0 ,则表示该点就在平面上 \vec n \cdot \vec p_0 - d > 0,则表示该点在平面的\vec n 方向正侧\\ \vec n \cdot \vec p_0 - d < 0,则表示该点在平面的\vec n 方向反侧\\ \vec n \cdot \vec p_0 - d = 0,则表示该点就在平面上\\ n p 0d>0,则表示该点在平面的n 方向正侧n p 0d<0,则表示该点在平面的n 方向反侧n p 0d=0,则表示该点就在平面上
示意图如下所示:

在这里插入图片描述

类似的,咱们也可以延伸思维,拓展到高维空间的对应表达形式,从而得出相应的结论!

Suntherland hodgman算法

基本介绍

Sutherland-Hodgman算法是一种用于多边形裁剪的经典计算机图形学算法。它的主要功能是将一个多边形裁剪到一个凸多边形窗口内,输出裁剪后的多边形。该算法由Ivan Sutherland和Gary Hodgman在1974年提出。

基本思想

Suntherland hodgman算法也叫逐边裁剪法,它将待裁剪目标多边形的每条边逐一与裁剪窗口的每条边比较,然后生成新的顶点集合,最终得到裁剪后的多边形。

二维举例

问题描述:

已知多边形有序顶点集合 V = { v 1 , v 2 , . . . , v n } V = \{v_1,v_2,...,v_n\} V={v1,v2,...,vn} ,几组不同的窗口边线表达方程,如: n ⃗ 1 ∗ p = d 1 , n ⃗ 2 ∗ p = d 2 , n ⃗ 3 ∗ p = d 3 , n ⃗ 4 ∗ p = d 4 \vec n_1 * p = d_1,\vec n_2 * p = d_2,\vec n_3 * p = d_3,\vec n_4 * p = d_4 n 1p=d1n 2p=d2n 3p=d3n 4p=d4

核心思路:
  • 遍历顶点集合的顺序顶点对 p 1 = ( v 1 , v 2 ) , p 2 = ( v 2 , v 3 ) , . . . , p n = ( v n , v 1 ) p_1 = (v_1,v_2),p_2 = (v_2,v_3),...,p_n = (v_n,v_1) p1=(v1,v2),p2=(v2,v3),...,pn=(vn,v1) ,针对每次顶点对的顶点,带入直线方程进行判定内外情况,从而做出不同的顶点选择
  • 针对每个窗口边线方程,进行迭代,得到最终顶点集。每一轮的输入顶点集为上一轮的输出,首轮迭代的输入为多边形有序顶点集!

遍历顶点对的不同情况

假设我们设顶点对的顶点对 ( S , P ) (S,P) (S,P),则有如下几种情况:

在这里插入图片描述

  • 情况1:S外侧,P内侧 => 不选择顶点
  • 情况2:S内侧,P外侧 => 选择交点I
  • 情况3:S外侧,P内侧 => 先选择交点I,然后选择P
  • 情况4:S内侧,P内侧 => 选择顶点P

算法举例1:

输入顶点集合:0、1、2,如下图:

在这里插入图片描述

依次考察右侧边线和顶点对 ( 0 , 1 ) , ( 1 , 2 ) , ( 2 , 0 ) (0,1),(1,2),(2,0) (0,1)(1,2),(2,0) 的关系,然后做出不同的考察,最终得到顶点集 ( 0 ′ , 1 , 1 ′ ) (0',1,1') (0,1,1) ,咱们将这个结果作为输入,针对另外一测边线进行类似的操作,直到四条边线都迭代完成,最终得到的结果就是 ( 0 ′ , 1 , 1 ′ ) (0',1,1') (0,1,1)

算法举例2:

输入顶点集合:0、1、2

先考察上侧边,如下图:

在这里插入图片描述

得到结果顶点集合 ( 0 ′ , 1 , 2 , 2 ′ ) (0',1,2,2') (0,1,2,2)

然后考察右侧边,如下图:

在这里插入图片描述

依次类推,另外两边,最终得到结果就是 ( 1 , 1 ′ , 2 ′ ′ , 0 ′ ) (1,1',2'',0') (1,1,2′′,0)

算法补充:

1、三角形重建

上述得到了剪裁后的多边形顶点序列,但在图形学中,渲染基本以三角形为图元,所以一般还需要多一个步骤:三角形重建。

往往我们都是以第一个顶点固定,后两个顶点从后面以此类推。如上算法举例2结果为例,形成三角形 ( 1 , 1 ′ , 2 ′ ′ ) 和 ( 1 , 2 ′ ′ , 0 ′ ) (1,1',2'')和(1,2'',0') (1,1,2′′)(1,2′′,0)

2、交点插值

当出现将内外侧与边线的交点作为顶点选择的时候,咱们如何计算这个交点的位置?又如何计算它的顶点颜色?uv坐标呢?

其实这个问题,在之前的直线插值早已解释过。如下图所示:

在这里插入图片描述

那么如何计算PS和边线的交点I呢?

已知P点和S点的属性值和位置,假设边线方程为 n ⃗ ⋅ p ⃗ = d \vec n \cdot \vec{p} = d n p =d ,将外侧顶点S带入,得到有向距离 d s = n ⃗ ⋅ S ⃗ d_s = \vec n \cdot \vec S ds=n S ,同理,也得到内侧顶点P的有向距离 d p = n ⃗ ⋅ P ⃗ d_p = \vec n \cdot \vec P dp=n P

这时候我们知道 d s > 0 且 d p < 0 d_s > 0 且 d_p < 0 ds>0dp<0 ,前面的前置知识已经给出解释过了。这时候就可以利用之前的知识,求出权重 $ weight = d_s / (d_s - d_p)$

从而求出交点的属性,如下:
f ( I ) = w e i g h t ∗ f ( P ) + ( 1 − w e i g h t ) ∗ f ( S ) f(I) = weight * f(P) + (1 - weight) * f(S) f(I)=weightf(P)+(1weight)f(S)

三维拓展

在三维情况下,裁剪边变成了裁剪平面,维度上升而已,其实本质没有变化,这里简单介绍一下图形学中的应用。

一般来说,在透视除法之前,会将剪裁空间坐标系下的坐标,进行剪裁操作。从而保证透视除法后,得到正确的包围盒 [ − 1 , 1 ] 3 [-1,1]^3 [1,1]3​ 的NDC坐标,并且位于摄像机前方。

因此剪裁空间的坐标必须满足以下不等式:
w c > 0 − 1 < x c w c < 1 − 1 < y c w c < 1 − 1 < z c w c < 1 w_c > 0\\ -1 < \frac{x_c}{w_c} < 1\\ -1 < \frac{y_c}{w_c} < 1\\ -1 < \frac{z_c}{w_c} < 1\\ wc>01<wcxc<11<wcyc<11<wczc<1

由于咱们需要之前类似的方程形式,所以进行转化为高维平面方程形式:
0 ∗ x c + 0 ∗ y c + 0 ∗ z c + 1 ∗ w c > 0 − 1 ∗ x c + 0 ∗ y c + 0 ∗ z c + 1 ∗ w c > 0 1 ∗ x c + 0 ∗ y c + 0 ∗ z c + 1 ∗ w c > 0 0 ∗ x c + − 1 ∗ y c + 0 ∗ z c + 1 ∗ w c > 0 0 ∗ x c + 1 ∗ y c + 0 ∗ z c + 1 ∗ w c > 0 0 ∗ x c + 0 ∗ y c + − 1 ∗ z c + 1 ∗ w c > 0 0 ∗ x c + 0 ∗ y c + 1 ∗ z c + 1 ∗ w c > 0 0*x_c + 0*y_c + 0*z_c + 1 * w_c > 0\\ -1*x_c + 0*y_c + 0*z_c + 1 * w_c > 0\\ 1*x_c + 0*y_c + 0*z_c + 1 * w_c > 0\\ 0*x_c + -1*y_c + 0*z_c + 1 * w_c > 0\\ 0*x_c + 1*y_c + 0*z_c + 1 * w_c > 0\\ 0*x_c + 0*y_c + -1*z_c + 1 * w_c > 0\\ 0*x_c + 0*y_c + 1*z_c + 1 * w_c > 0\\ 0xc+0yc+0zc+1wc>01xc+0yc+0zc+1wc>01xc+0yc+0zc+1wc>00xc+1yc+0zc+1wc>00xc+1yc+0zc+1wc>00xc+0yc+1zc+1wc>00xc+0yc+1zc+1wc>0

所以咱们就得到了 n ⃗ ⋅ p ⃗ = 0 \vec n \cdot \vec p = 0 n p =0 的边界方程表达式, n ⃗ \vec n n 就是上述每一个方程的系数组成的向量,如 { 0 , 0 , 0 , 1 } , { − 1 , 0 , 0 , 1 } \{0,0,0,1\},\{-1,0,0,1\} {0,0,0,1}{1,0,0,1}等等,一共7组!

边界方程也有了,需要裁剪的多边形顶点也有了,思路也就类似二维,代码就是体力劳动喽!

结尾:你们的点赞 + 关注就是我创作的最大动力!加油!

希望对各位小伙伴能够有所帮助哦,有任何问题请评论或私信哦,有空一定会回复的哦!永远在学习的道路上伴你而行, 我是航火火,火一般的男人!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/20936.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最小时间差

首先可以想到&#xff0c;可以计算出任意两个时间之间的差值&#xff0c;然后比较出最小的&#xff0c;不过这种蛮力方法时间复杂度是O(n^2)。而先将时间列表排序&#xff0c;再计算相邻两个时间的差值&#xff0c;就只需要计算n个差值&#xff0c;而排序阶段时间复杂度通常为O…

C语言实现贪吃蛇小游戏(控制台)

本篇主要内容是使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇。 一、准备工作 我们要实现的基本功能有&#xff1a; 地图绘制蛇吃食物的功能&#xff08;上、下、左、右方向键控制蛇的动作&#xff09;蛇撞墙死亡蛇撞自身死亡计算得分蛇身加速、减速暂停游戏 …

9-Django项目--验证码操作

目录 templates/login/login.html utils/code.py views/login.py 验证码 生成验证码 code.py 应用验证码 views.py login.html templates/login/login.html {% load static %} <!DOCTYPE html> <html lang"en"> <head><meta charset&q…

PID算法入门

文章目录 122.12.22.3 344.14.24.3 1 e(t) 是偏差 实 和 目u(t) 是运算结果 2 层层叠加 得出完整的离散公式 2.1 kp 越大 系统偏差 减小的越快kp大的时候 会出现过冲现象&#xff1f; 0.5 那个会快他解释过冲 &#xff1a; 0.2的 5分钟正好到了 那0.5的五分钟 升的就比20多 就…

④单细胞学习-cellchat细胞间通讯

目录 1&#xff0c;原理基础 流程 受体配体概念 方法比较 计算原理 2&#xff0c;数据 3&#xff0c;代码运行 1&#xff0c;原理基础 原文学习Inference and analysis of cell-cell communication using CellChat - PMC (nih.gov) GitHub - sqjin/CellChat: R toolk…

在 JavaScript 中实现数据加密与解密:Web Cryptography API 与 CryptoJS详解

在 JavaScript 中&#xff0c;可以使用 Web Cryptography API 或第三方库如 crypto-js 来实现加密和解密。本文将介绍如何使用这两种方法在客户端进行数据的加密和解密。 使用 Web Cryptography API Web Cryptography API 是现代浏览器提供的一个强大、原生的加密 API。它允许…

关于留痕的使用常见的问题

1. 登录微信 登录要导出数据的微信&#xff08;不支持微信多开&#xff0c;不支持部分老版本微信&#xff09; 相关信息 想把手机端的微信聊天记录转移到电脑上可以使用微信自带的聊天记录迁移功能 操作步骤&#xff1a; 安卓&#xff1a; 手机微信->我->设置->聊…

[深度学习]使用python部署yolov10的onnx模型

测试环境&#xff1a; onnxruntime1.15.1 opencv-python4.8.0.76 部分实现代码&#xff1a; parser argparse.ArgumentParser()parser.add_argument("--model", typestr, default"yolov10n.onnx", help"Input your ONNX model.")parser.add_arg…

电子电器架构 --- 什么是域控制器?

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

美颜相机与美图秀秀的非会员图片保存技巧畅享专业级图像处理探索

美颜相机与美图秀秀的非会员图片保存技巧畅享专业级图像处理探索 今日对美颜相机和美图秀秀的深入使用中&#xff0c;我遇到了一些功能限制&#xff0c;特别是在尝试保存特定处理后的图片时&#xff0c;发现通常需要开通VIP会员才能享受完整服务。作为一名热衷于技术探索的爱好…

【数据结构】二叉树的层序遍历~动画超详解

目录 1 什么是层序遍历2 二叉树层序遍历的基本思路3 二叉树层序遍历的实现 1 什么是层序遍历 我们从字面意思就明白,所谓层序,就是一层一层按顺序去遍历一个二叉树,这和我们之前了解的按前中后序遍历方式完全不同 比方说这颗二叉树: 前序遍历: 层序遍历: 2 二叉树层序遍历的…

Android 使用kotlin Retrofit2 + Dagger2完成网络请求跟依赖注入组合使用

文章目录 &#xff08;一&#xff09;引入依赖&#xff08;二&#xff09;基本概念Dagger中的基本概念&#xff1a;Retrofit介绍 &#xff08;三&#xff09;Dagger2 Module 和 Provides 和 Component Inject&#xff08;四&#xff09;Retrofit2 创建数据类Bean跟Service服务&…

3. MySQL 数据表的基本操作

文章目录 【 1. MySQL 创建数据表 】【 2. MySQL 查看表 】2.1 查看表的属性DESCRIBE/DESC 以表格的形式展示表属性SHOW CREATE TABLE 以SQL语句的形式展示表属性 2.2 查看表的内容 【 3. MySQL 修改数据表结构 】3.1 修改表名3.2 修改表字符集3.3 添加字段在末尾添加字段在开头…

LLMs Can’t Plan, But Can Help Planning in LLM-Modulo Frameworks

更多精彩内容&#xff0c;请关注微信公众号&#xff1a;NLP分享汇 原文链接&#xff1a;LLMs Can’t Plan, But Can Help Planning in LLM-Modulo Frameworks 你是怎么理解LLM的规划和推理能力呢&#xff0c;来自亚利桑那州立大学最近的一篇论文&#xff0c;对LLM的规划、推理…

ios 新安装app收不到fcm推送

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

拼图游戏完整思路(全代码演示)

主界面 小练习1&#xff1a; 一、三个界面的设置1&#xff1a;创建窗体 1、将三个主界面分开为三个类&#xff0c;每个类都去继承JFrame这个类&#xff0c;使得每个类都可以使用创建页面功能 2、对每个类进行空参构造&#xff0c;在空参构造里面进行窗体属性的赋值 3、创建一个…

苍穹外卖--sky-take-out(二)3-5

sky-take-out&#xff08;一&#xff09;1-2https://blog.csdn.net/kussm_/article/details/138614737?spm1001.2014.3001.5501 第三天 公共字段填充--利用AOP 问题提出 这些字段属于公共字段 &#xff1a;在新增员工或者新增菜品分类时需要设置创建时间、创建人、修改时间…

蓝桥杯软件测试-十五届模拟赛2期题目解析

十五届蓝桥杯《软件测试》模拟赛2期题目解析 PS 需要第十五界蓝桥杯模拟赛2期功能测试模板、单元测试被测代码、自动化测试被测代码请加&#x1f427;:1940787338 备注&#xff1a;15界蓝桥杯省赛软件测试模拟赛2期 题目1&#xff1a;功能测试题目 1&#xff08;测试用例&…

[极速版]写个linux探测自己机器ip地址的tool(基于shell + sshpass)

适用情况&#xff1a;上级路由ssh or teamviewer访问下级路由的机器&#xff0c;但下级路由不支持查看IP 自行完成端口映射or DMZ整机映射 apt-get install sshpass#!/bin/bash mkdir log for i in $(seq 2 255) dosshpass -p tmp ssh -E err.log -o StrictHostKeyCheckingno …

【解决】Tree prefab at index 8 is missing.

开发平台&#xff1a;Unity 2020 版本以上   问题描述 翻译&#xff1a;树预制体集合中第8位预制体丢失。   解决方法&#xff1a;修复丢失树资产 关联 Unity Terrier 组件使用&#xff0c;前往 树绘制工作区&#xff0c;检查 “树资产” 引用是否丢失&#xff1f;删除或重…