网格简化(QEM)学习笔记

news2024/9/22 13:25:11

文章目录

  • 网格简化(QEM)
    • 1 概述与原理
      • 1.1 网格简化的应用
      • 1.2 常见的简化操作
      • 1.3 二次误差度量
    • 2 算法流程
      • 2.1 逐步分析
    • 3 Python代码实现
      • 3.1 测试结果
    • 4 总结
    • 参考

网格简化(QEM)

1 概述与原理

网格简化,通过减少复杂网格数据的顶点、边和面的数量简化模型的表达,在图形学领域,这种技术也叫做Level of details(LOD,多层次细节)。

1.1 网格简化的应用

  • 多分辨率渲染:对于投影尺寸较小(远距离显示)的模型,可以渲染它的简化版本替代原本丰富细节的高复杂度网格,提高渲染效率。
  • 代理仿真:在简化模型上进行仿真,然后通过插值方法得到原本复杂网格的近似仿真结果,提高仿真效率。 [ 1 ] ^{[1]} [1]

1.2 常见的简化操作

  • Vertex Decimation(顶点抽取)

    选择一个顶点进行删除,移除该顶点相邻的面,然后对产生的孔洞重新三角化。

  • Vertex Clustering(顶点聚类)

    image-20230730150803895

    划分原始网格的包围盒成一个grid,将每个cell中的顶点聚类成一个,然后依据聚类后得到的顶点更新网格的面。

  • Edge Contraction(边收缩)

    image-20230730151429110

    ( v 1 , v 2 ) → v ‾ (v_1,v_2)\rightarrow{\overline{v}} (v1,v2)v,将一条边收缩为一个点,删除退化的面(上图中阴影所示)。

  • Pair Contraction(点对收缩)

    image-20230730162827401作为边收缩的推广,如果点对 ( v 1 , v 2 ) (v_1,v_2) (v1,v2)是一条边,那么等同于边收缩;如果点对 ( v 1 , v 2 ) (v_1,v_2) (v1,v2)不是一条边,那么对该点对进行收缩会使原本不相连的部分连接到一起。

1.3 二次误差度量

为了保证收缩后的顶点与原始网格之间的局部距离不要太远,我们选择一种基于二次距离度量的方式寻找最优的收缩点。

根据二次距离寻找最优收缩点

image-20230730174452604

此处公式推导请移步至网格简化 QEM 方法详解,文中讲得十分清晰。

考虑一次边收缩。对于两个点 v 1 , v 2 v_1, v_2 v1,v2 ,收缩成一个点 v ˉ \bar{v} vˉ 。定义 plane ( v i ) \left(v_i\right) (vi) 表示 v i v_i vi 对应的那些原始三角面,则我们的优化目标是
v ˉ = arg ⁡ min ⁡ v ∑ p ∈  plane  ( v 1 ) ∪  plane  ( v 2 ) distance ⁡ ( v , p ) 2 \bar{v}=\underset{v}{\arg \min } \sum_{p \in \text { plane }\left(v_1\right) \cup \text { plane }\left(v_2\right)} \operatorname{distance}(v, p)^2 vˉ=vargminp plane (v1) plane (v2)distance(v,p)2
下面一步步化简。令平面 p p p 的表达式为 a x + b y + c z + d = 0 a x+b y+c z+d=0 ax+by+cz+d=0 ,其中 a 2 + b 2 + c 2 = 1 a^2+b^2+c^2=1 a2+b2+c2=1 。 记 v = [ x , y , z , 1 ] T , p = [ a , b , c , d ] T v=[x, y, z, 1]^T, p=[a, b, c, d]^T v=[x,y,z,1]T,p=[a,b,c,d]T ,可得
distance ⁡ ( v , p ) 2 = ( v T p ) 2 = v T p p T v = v T K p v \operatorname{distance}(v, p)^2=\left(v^T p\right)^2=v^T p p^T v=v^T K_p v distance(v,p)2=(vTp)2=vTppTv=vTKpv
其中 K p = p p T K_p=p p^T Kp=ppT ,则原式简化为
v ˉ = arg ⁡ min ⁡ v   v T ( ∑ p ∈  plane  ( v 1 ) ∪ p l a n e ( v 2 ) K p ) v \bar{v}=\underset{v}{\arg \min }\space v^T\left(\sum_{p \in \text { plane }\left(v_1\right) \cup p l a n e\left(v_2\right)} K_p\right) v vˉ=vargmin vT p plane (v1)plane(v2)Kp v
此处取约等于
v ˉ ≈ arg ⁡ min ⁡ v   v T ( ∑ p ∈ plane ⁡ ( v 1 ) K p + ∑ p ∈ plane ⁡ ( v 2 ) K p ) v \bar{v} \approx \underset{v}{\arg \min }\space v^T\left(\sum_{p \in \operatorname{plane}\left(v_1\right)} K_p+\sum_{p \in \operatorname{plane}\left(v_2\right)} K_p\right) v vˉvargmin vT pplane(v1)Kp+pplane(v2)Kp v
Q i = ∑ p ∈  plane  ( v i ) K p Q_i=\sum_{p \in \text { plane }\left(v_i\right)} K_p Qi=p plane (vi)Kp ,则有
v ˉ = arg ⁡ min ⁡ v   v T ( Q 1 + Q 2 ) v \bar{v}=\underset{v}{\arg \min }\space v^T\left(Q_1+Q_2\right) v vˉ=vargmin vT(Q1+Q2)v
初始化时,将 plane ⁡ ( v ) \operatorname{plane}(v) plane(v) 设为点 v \mathrm{v} v 周围的三角形面即可。此时上面的约等号并无大碍,因为一个 三角形面至多重复三次 (三个顶点),不仅不会带来较大的误差,而且简化了计算。
另外, K p K_p Kp 是对称矩阵,故 Q Q Q 也是,所以只需要存储 10 个元素即可。
此时求解 v ˉ \bar{v} vˉ 的坐标变成求解二次函数极值点。 [ 2 ] ^{[2]} [2]

Q = Q 1 + Q 2 Q=Q_1+Q_2 Q=Q1+Q2,通过解如下方程求解 v ˉ \bar{v} vˉ的坐标:
[ q 11 q 12 q 13 q 14 q 12 q 22 q 23 q 24 q 13 q 23 q 33 q 34 0 0 0 1 ] v ˉ = [ 0 0 0 1 ] \left[{\begin{array}{cccc}q_{11}&q_{12}&q_{13}&q_{14}\\q_{12}&q_{22}&q_{23}&q_{24}\\q_{13}&q_{23}&q_{33}&q_{34}\\0&0&0&1\end{array}}\right]\bar{v}=\left[{\begin{array}{c}0\\0\\0\\1\end{array}}\right] q11q12q130q12q22q230q13q23q330q14q24q341 vˉ= 0001
上式中, q 11 q_{11} q11表示 Q Q Q的第一行的第一个元素的值,这里 v ˉ \bar{v} vˉ使用的是齐次坐标。如果上式中左侧矩阵可逆,则
v ˉ = [ q 11 q 12 q 13 q 14 q 12 q 22 q 23 q 24 q 13 q 23 q 33 q 34 0 0 0 1 ] − 1 [ 0 0 0 1 ] \bar{v}=\left[{\begin{array}{cccc}q_{11}&q_{12}&q_{13}&q_{14}\\q_{12}&q_{22}&q_{23}&q_{24}\\q_{13}&q_{23}&q_{33}&q_{34}\\0&0&0&1\end{array}}\right]^{-1}\left[{\begin{array}{c}0\\0\\0\\1\end{array}}\right] vˉ= q11q12q130q12q22q230q13q23q330q14q24q341 1 0001
如果不可逆,则 [ 4 ] ^{[4]} [4]
v = ( 1 − k ) v 1 + k v 2 , where  k ∈ [ 0 , 1 ] v ˉ = arg ⁡ min ⁡ v   v T ( Q 1 + Q 2 ) v v=(1-k)v_1+kv_2,\text{where}\space{k}\in[0,1]\\ \bar{v}=\underset{v}{\arg \min }\space v^T\left(Q_1+Q_2\right) v v=(1k)v1+kv2,where k[0,1]vˉ=vargmin vT(Q1+Q2)v
如果还是不行,就选择端点 v 1 , v 2 v_1,v_2 v1,v2或者中点 v 1 + v 2 2 \frac{v_1+v_2}2 2v1+v2三者中误差( Δ ( v ) = v T Q v \Delta(v)=v^TQv Δ(v)=vTQv)最小的作为 v ˉ \bar{v} vˉ [ 3 ] ^{[3]} [3]

2 算法流程

img

图源自:QEM网格简化 - 简书 (jianshu.com)

2.1 逐步分析

  • 计算所有初始顶点的 Q Q Q矩阵

    令平面 p p p 的表达式为 a x + b y + c z + d = 0 a x+b y+c z+d=0 ax+by+cz+d=0 ,其中 a 2 + b 2 + c 2 = 1 a^2+b^2+c^2=1 a2+b2+c2=1 。记 p = [ a , b , c , d ] T p=[a, b, c, d]^T p=[a,b,c,d]T。由此,我们定义 Q i Q_i Qi(4x4,顶点 v i v_i vi Q Q Q矩阵)如下:
    Q i = ∑ p ∈ p l a n e s ( v i ) p p T Q_i=\sum_{p\in planes(v_i)}pp^T Qi=pplanes(vi)ppT

  • 选择合法点对

    一个顶点对 ( v i , v j ) (v_i,v_j) (vi,vj)是合法点对的条件为:

    • ( v i , v j ) (v_i,v_j) (vi,vj)是一条边;
    • ‖ v i − v j ‖ < t ‖v_i − v_j‖ < t vivj<t t t t为阈值参数。

    以上条件满足其一即可。

  • 计算每个合法点对 ( v i , v j ) (v_i,v_j) (vi,vj)的最小收缩误差 c o s t i j cost_{ij} costij,以及最佳收缩点 v o p t v_{opt} vopt的位置

    首先计算 v o p t v_{opt} vopt对应的 Q o p t Q_{opt} Qopt
    Q o p t = Q i + Q j = [ q 11 q 12 q 13 q 14 q 12 q 22 q 23 q 24 q 13 q 32 q 33 q 34 q 14 q 24 q 34 q 44 ] . Q_{opt}=Q_i+Q_j=\begin{bmatrix}q_{11}&q_{12}&q_{13}&q_{14}\\q_{12}&q_{22}&q_{23}&q_{24}\\q_{13}&q_{32}&q_{33}&q_{34}\\q_{14}&q_{24}&q_{34}&q_{44}\end{bmatrix}. Qopt=Qi+Qj= q11q12q13q14q12q22q32q24q13q23q33q34q14q24q34q44 .
    定义 c o s t i j cost_{ij} costij如下:
    c o s t i j = v T Q o p t v cost_{ij}=v^TQ_{opt}v costij=vTQoptv
    最小化收缩误差,得到 v o p t v_{opt} vopt。具体计算参见上一节[二次误差度量](#1.3 二次误差度量)。

  • 将所有合法点对按其对应的 c o s t i j cost_{ij} costij的顺序放置在一个堆中,最小 c o s t i j cost_{ij} costij对位于顶部

    一般使用小根堆进行排序。

  • 移除最小 c o s t i j cost_{ij} costij对应的点对,收缩 ( v i , v j ) → v o p t (v_i,v_j)\rightarrow{v_{opt}} (vi,vj)vopt,更新所有包含了 v i v_i vi v j v_j vj的合法点对的 c o s t cost cost

    这一步是迭代进行的,结束的标志为达到了设定的简化率或者堆空了 [ 5 ] ^{[5]} [5]

3 Python代码实现

代码实现方面,推荐直接学习该项目:Mesh_simplification_python: An implementation of mesh simplification algorithm using python,其中代码注释很全,条理清晰,值得学习。

3.1 测试结果

输入模型网格(9397 vertices, 18794 faces):

image-20230802000140688

t = 0 ,   r a t i o = 0.5 t=0,\space ratio=0.5 t=0, ratio=0.5(4698 vertices, 9396 faces):

image-20230802000230337

t = 0 ,   r a t i o = 0.1 t=0,\space ratio=0.1 t=0, ratio=0.1(939 vertices, 1878 faces):

image-20230802000546218

4 总结

  • 代码功能优化

    在原论文中还提到了如下两个细节:

    • 保留边界

      对于一些在简化过程中需要保持边界的模型网格,我们在点对收缩时判断点对是否为边界边,如果是,我们可以给该点对cost加权一个较大的惩罚因子,阻止收缩。

    • 防止面片翻转

      直接使用QEM算法进行网格简化,可能会导致一些面片翻转。所以我们需要在计算点对收缩cost时,同时判断点对的每一个相邻面片是否发生了翻转。可采用收缩前后面片法向量的夹角大小进行判断。同时,我们也对其代价进行惩罚。

参考

[1] GAMES102:几何建模与处理
[2] https://zhuanlan.zhihu.com/p/411865616
[3] Michael Garland and Paul S. Heckbert. 1997. Surface simplification using quadric error metrics. In Proceedings of the 24th annual conference on Computer graphics and interactive techniques (SIGGRAPH '97). ACM Press/Addison-Wesley Publishing Co., USA, 209–216. https://doi.org/10.1145/258734.258849
[4] https://www.jianshu.com/p/2bf615c38165
[5] https://github.com/AntonotnaWang/Mesh_simplification_python

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

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

相关文章

MIT 6.S081 Lab Ten -- mmap

MIT 6.S081 Lab Ten -- mmap 引言mmap(hard)代码解析 引言 本文为 MIT 6.S081 2020 操作系统 实验十解析。 MIT 6.S081课程前置基础参考: 基于RISC-V搭建操作系统系列 mmap(hard) map和munmap系统调用允许UNIX程序对其地址空间进行详细控制。它们可用于在进程之间共享内存&a…

SOLIDWORKS Flow Simulation可以便捷的进行降压分析

导读&#xff1a;现如今压降等应用的工程分析一直是由分析部门的专家执行&#xff0c;这些部门独立于主流设计和开发部门&#xff0c;或者仅为一些重要产品制造昂贵的物理原型。要测试或验证其设计&#xff0c;机械工程师必须依赖于创建物理原型并在工作台或测试台上对其进行测…

【Maven】Nexus3上传maven依赖jar

后端依赖 上次说到前端的批量tgz文件上传私服&#xff0c;其实服务端也有类似情况&#xff0c;我们有个私服也需要进行上传到私服&#xff0c;这里做个记录。因为上次有个小细节没注意白白传错了一遍&#xff0c;这里重新记录总结一下。 # 查看一下结构 $ tree -L 2 . |-- re…

春秋云镜 CVE-2021-32305

春秋云镜 CVE-2021-32305 WebSVN RCE 靶标介绍 WebSVN是一个基于Web的Subversion Repository浏览器&#xff0c;可以查看文件或文件夹的日志&#xff0c;查看文件的变化列表等。其search.php?search 参数下过滤不严谨导致RCE。 启动场景 漏洞利用 EXP PAYLOAD "/bi…

快速消除视频的原声的技巧分享

网络上下载的视频都会有视频原声或者背景音乐&#xff0c;如果不喜欢并且想更换新的BGM要怎么操作呢&#xff1f;今天小编就来教你如何快速给多个视频更换新的BGM&#xff0c;很简单&#xff0c;只需要将原视频的原声快速消音同时添加新的背景音频就行&#xff0c;一起来看看详…

express学习笔记3 - 三大件

便于统一管理router&#xff0c;创建 router 文件夹&#xff0c;创建 router/index.js&#xff1a; const express require(express)// 注册路由 const router express.Router() router.get(/,function(req,res){res.send(让我们开始express之旅) }) /*** 集中处理404请求的…

2023 全国大学生电子设计竞赛题目

2021 全国大学生电子设计竞赛题目 目录 1&#xff08;A题&#xff09;单相逆变器并联运行系统2 &#xff08;B题&#xff09;同轴电缆长度与终端负载检测装置3 &#xff08;C题&#xff09;电感电容测量装置4 &#xff08;D题&#xff09;信号调制方式识别与参数估计装置5 &am…

数据库访问中间件--springdata-jpa的基本使用

二、单表SQL操作-使用关键字拼凑方法 回顾 public interface UserRepository extends JpaRepository<User,Integer> {User findByUsernameLike(String username); }GetMapping("/user/username/{username}")public Object findUserByUsername(PathVariable S…

软考A计划-系统集成项目管理工程师-项目沟通管理-下

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

C语言进阶——文件的读写(文件使用方式、文件的顺序读写、常用函数、fprintf、fscanf)

目录 文件使用方式 文件的顺序读写 常用函数 用法示例 fprintf fscanf 文件使用方式 在fopen函数中详细的各种使用方式&#xff1a; 文件使用方式含义如果指定文件不存在“r”&#xff08;只读&#xff09;为了输入数据&#xff0c;打开一个已经存在的文本文件出错“w”…

2023牛客暑期多校训练营5-I The Yakumo Family

2023牛客暑期多校训练营5-I The Yakumo Family https://ac.nowcoder.com/acm/contest/57359/I 文章目录 2023牛客暑期多校训练营5-I The Yakumo Family题意解题思路代码 题意 解题思路 考虑将序列拆位计算。 先考虑一个简化版本&#xff0c;求&#xff1a; ∑ 1 ≤ l 1 ≤…

新闻标题文本分类任务

目录 知识回顾使用debug调试 知识回顾 预处理内容 文本主要进行清洗、分词/分字 ID替换(不希望计算机看到文字&#xff0c;而是ID)&#xff0c;通过语料表来表示&#xff0c;根据频率高低来分配ID号 文本的ID映射到文本的一个特征向量&#xff0c;进行词嵌入(Embedding)&…

【docker】Windows11系统下安装并配置阿里云镜像加速

【docker】Windows11系统下安装并配置阿里云镜像加速 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【docker】Windows11系统下安装并配置阿里云镜像加速一、查看Windows环境是否支持docker二、 启动Hyper-V三、 官网下载安装Docker应用和数据…

VIOOVI分享:什么是丰田精益生产方式?丰田精益生产方式有哪些?

作为全球知名的汽车生产企业&#xff0c;日本丰田在行业的影响力巨大。而其企业运营模式&#xff0c;也广为经营领域热议&#xff0c;其中&#xff0c;大家对丰田精益生产方式一直都是津津乐道。那么什么是丰田精益生产方式&#xff1f;以下内容为您全面解析。 丰田精益化生产模…

数据结构 | 线性数据结构——双端队列

目录 一、何谓双端队列 二、双端队列抽象数据类型 三、用Python实现双端队列 四、回文检测器 一、何谓双端队列 双端队列是与队列类似的有序集合。它有一前、一后两端&#xff0c;元素在其中保持自己的位置。与队列不同的是&#xff0c;双端队列对在哪一端添加和移除元素没…

Linux - 进程控制(进程等待)

进程等待必要性 之前讲过&#xff0c;子进程退出&#xff0c;父进程如果不管不顾&#xff0c;就可能造成‘僵尸进程’的问题&#xff0c;进而造成内存泄漏。 另外&#xff0c;进程一旦变成僵尸状态&#xff0c;那就刀枪不入&#xff0c;“杀人不眨眼”的kill -9 也无能为力&…

Activiti 深入理解:Activiti 流程引擎的 25 张数据库表都存储了什么?ing

1. Activiti 数据库表名说明&#xff08;分类与说明&#xff09; https://www.activiti.org/userguide/#database.tables.explained \qquad Activiti 的数据库表名称都以 ACT_ 开头&#xff0c;而第二部分是表 use case 的双字符标识&#xff0c;use case 也大致与 Activiti 服…

Vue3中使用事件总线Bus的两种方式(mitt)

首先咱们得先下载mitt指令如下&#xff1a; npm i mitt --save 接下来介绍Vue3中通过mitt使用事件总线的两种方式 方式一&#xff1a; 该方式为全局挂载mitt,个人感觉有点繁琐&#xff0c;不太推荐 创建&#xff1a; 1.首先找到你的main.js或main.ts文件 2.引入mitt 3.…

MIT 6.S081 Lab Nine --- file system

MIT 6.S081 Lab Nine --- file system 引言File systemLarge files(moderate)预备看什么你的工作代码解析 Symbolic links(moderate)硬链接代码解析 可选的挑战练习 引言 本文为 MIT 6.S081 2020 操作系统 实验九解析。 MIT 6.S081课程前置基础参考: 基于RISC-V搭建操作系统系…

pc文件上传

1.代码&#xff1a; <template><div><el-upload:multiple"true":auto-upload"true":headers"headers":action"uploadFileUrl":before-upload"handleBeforeUpload":on-error"handleUploadError":o…