在计算机图形应用中,为了尽可能真实呈现虚拟物体,往往需要高精度的三维模型。然而,模型的复杂性直接关系到它的计算成本,因此高精度的模型在几何运算时并不是必须的,取而代之的是一个相对简化的三维模型,那么如何自动计算生成这些三维简化模型就是网格精简算法所关注的目标。

  [Garland et al. 1997]提出了一种基于二次误差作为度量代价的边收缩算法,其计算速度快并且简化质量较高。该方法在选择一条合适的边进行迭代收缩时,定义了一个描述边收缩代价的变量Δ,具体如下:对于网格中的每个顶点v,我们预先定义一个4×4的对称误差矩阵Q,那么顶点v = [vx vy vz 1]T的误差为其二次项形式Δ(v) = vTQv。假设对于一条收缩边(v1, v2),其收缩后顶点变为vbar,我们定义顶点vbar的误差矩阵Qbar为Qbar = Q1 + Q2,对于如何计算顶点vbar的位置有两种策略:一种简单的策略就是在v1, v2和(v1+ v2)/2中选择一个使得收缩代价Δ(vbar)最小的位置。另一种策略就是数值计算顶点vbar位置使得Δ(vbar)最小,由于Δ的表达式是一个二次项形式,因此令一阶导数为0,即,该式等价于求解:

其中qij为矩阵Qbar中对应的元素。如果系数矩阵可逆,那么通过求解上述方程就可以得到新顶点vbar的位置,如果系数矩阵不可逆,就通过第一种简单策略来得到新顶点vbar的位置。根据以上描述,算法流程如下:

  那么剩下的问题就是如何计算每个顶点的初始误差矩阵Q,在原始网格模型中,每个顶点可以认为是其周围三角片所在平面的交集,也就是这些平面的交点就是顶点位置,我们定义顶点的误差为顶点到这些平面的距离平方和:

其中p = [a b c d]T代表平面方程ax + by + cz + d = 0(a2 + b2 + c2 = 1)的系数,Kp为二次基本误差矩阵:

因此原始网格中顶点v的初始误差为Δ(v) = 0,当边收缩后,新顶点误差为Δ(vbar) = vbarTQbarvbar,我们依次选取收缩后新顶点误差最小的边进行迭代收缩直到满足要求为止。

%% surface simplification using quadratic error metrics
clc
clear all
close all load('bunny.mat'); V = surfdata.point;
F = surfdata.face; nv = size(V,); % total vertex number
np = 0.1*nv; % remained vertex number % fundamental error quadric
N = normals(V,F);
N = normalizeVector3d(N);
p = [N, -sum(N .* V(F(:,),:), )];
Q0 = bsxfun(@times, permute(p, [,,]), permute(p, [,,])); % compute the Q matrices for all the initial vertices.
nf = size(F,);
Q = zeros(,,nv);
valence = zeros(nv,);
for i = :nf
for j = :
valence(F(i,j)) = valence(F(i,j)) + ;
Q(:,:,F(i,j)) = Q(:,:,F(i,j)) + Q0(:,:,i);
end
end % all valid pairs
E = edges(F); % compute Q1+Q2 for each pair
Qbar = Q(:,:,E(:,)) + Q(:,:,E(:,)); % a simple scheme: select either v1, v2 or (v1+v2)/
ne = size(E,);
v1 = permute([V(E(:,),:),ones(ne,)], [,,]);
v2 = permute([V(E(:,),:),ones(ne,)], [,,]);
vm = 0.5 .* (v1 + v2);
v = [v1, v2, vm]; cost = zeros(ne,);
cost(:,) = sum(squeeze(sum(bsxfun(@times,v1,Qbar),)).*squeeze(v1),)';
cost(:,) = sum(squeeze(sum(bsxfun(@times,v2,Qbar),)).*squeeze(v2),)';
cost(:,) = sum(squeeze(sum(bsxfun(@times,vm,Qbar),)).*squeeze(vm),)'; figure;
draw_t = ;
num = nv;
tic
for i = :nv-np
if (nv - i) < 0.9*num
num = nv - i; clf
drawMesh(V, F, 'facecolor','y', 'edgecolor','k', 'linewidth', 1.2);
view([ ])
axis equal
axis off
camlight
lighting gouraud
cameramenu
drawnow
end [min_cost, vidx] = min(cost,[],);
[useless, k] = min(min_cost);
e = E(k,:); % update position for v1
V(e(),:) = v(:, vidx(k), k)';
V(e(),:) = nan; % update Q for v1
Q(:,:,e()) = Q(:,:,e()) + Q(:,:,e());
Q(:,:,e()) = nan; % updata face
F(F == e()) = e();
f_remove = sum(diff(sort(F,),[],) == , ) > ;
F(f_remove,:) = []; % collapse and delete edge and related edge information
E(E == e()) = e();
E(k,:) = [];
cost(k,:) = [];
Qbar(:,:,k) = [];
v(:,:,k) = []; % delete duplicate edge and related edge information
[E,ia,ic] = unique(sort(E,), 'rows');
cost = cost(ia,:);
Qbar = Qbar(:,:,ia);
v = v(:,:,ia); % pairs involving v1
pair = sum(E == e(), ) > ;
npair = sum(pair); % updata edge information
Qbar(:,:,pair) = Q(:,:,E(pair,)) + Q(:,:,E(pair,)); pair_v1 = permute([V(E(pair,),:),ones(npair,)], [,,]);
pair_v2 = permute([V(E(pair,),:),ones(npair,)], [,,]);
pair_vm = 0.5 .* (pair_v1 + pair_v2);
v(:,:,pair) = [pair_v1, pair_v2, pair_vm]; cost(pair,) = sum(squeeze(sum(bsxfun(@times,pair_v1,Qbar(:,:,pair)),)).*squeeze(pair_v1),)';
cost(pair,) = sum(squeeze(sum(bsxfun(@times,pair_v2,Qbar(:,:,pair)),)).*squeeze(pair_v2),)';
cost(pair,) = sum(squeeze(sum(bsxfun(@times,pair_vm,Qbar(:,:,pair)),)).*squeeze(pair_vm),)'; fprintf('%d\n', i);
end clf
drawMesh(V, F, 'facecolor','y', 'edgecolor','k', 'linewidth', 1.2);
view([ ])
axis equal
axis off
camlight
lighting gouraud
cameramenu

 

本文为原创,转载请注明出处:http://www.cnblogs.com/shushen

参考文献:

[1] 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., New York, NY, USA, 209-216.

三维网格精简算法(Quadric Error Metrics)附源码的更多相关文章

  1. swfupload多文件上传[附源码]

    swfupload多文件上传[附源码] 文件上传这东西说到底有时候很痛,原来的asp.net服务器控件提供了很简单的上传,但是有回传,还没有进度条提示.这次我们演示利用swfupload多文件上传,项 ...

  2. 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生

    [转].NET(C#):浅谈程序集清单资源和RESX资源   目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...

  3. 8个前沿的 HTML5 & CSS3 效果【附源码下载】

    作为一个前沿的 Web 开发者,对于 HTML5 和 CSS3 技术或多或少都有掌握.前几年这些新技术刚萌芽的时候,开发者们已经使用它们来小试牛刀了,如今这些先进技术已经遍地开发,特别是在移动端大显身 ...

  4. C#编程总结(七)数据加密——附源码

    C#编程总结(七)数据加密——附源码 概述 数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为“密文”,使其只能在输入相应的密钥之后才能显示出本来内容 ...

  5. Remote验证及其改进(附源码)

    Remote验证及其改进(附源码) 表单中的输入项,有些是固定的,不变的验证规则,比如字符长度,必填等.但有些是动态的,比如注册用户名是否存在这样的检查,这个需要访问服务器后台才能解决.这篇文章将会介 ...

  6. javaweb异常提示信息统一处理(使用springmvc,附源码)

    一.前言 后台出现异常如何友好而又高效地回显到前端呢?直接将一堆的错误信息抛给用户界面,显然不合适. 先不考虑代码实现,我们希望是这样的: (1)如果是页面跳转的请求,出现异常了,我们希望跳转到一个异 ...

  7. 13行代码实现:Python实时视频采集(附源码)

    一.前言 本文是<人脸识别完整项目实战>系列博文第3部分:程序设计篇(Python版),第1节<Python实时视频采集程序设计>,本章内容系统介绍:基于Python+open ...

  8. 日志组件Log2Net的介绍和使用(附源码开源地址)

    Log2Net是一个用于收集日志到数据库或文件的组件,支持.NET和.NetCore平台. 此组件自动收集系统的运行日志(服务器运行情况.在线人数等).异常日志.程序员还可以添加自定义日志. 该组件支 ...

  9. openlayers5-webpack 入门开发系列结合 echarts4 实现散点图(附源码下载)

    前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...

随机推荐

  1. <a>与文件下载-(下载一)

    <a>可直接下载xls,doc,rar,zip,exe,js文件(图片跟txt文件是直接打开的) <a href="wKioJlJolKeCIzkCADd3Wf7OPI42 ...

  2. PHP资源列表

    一个PHP资源列表,内容包括:库.框架.模板.安全.代码分析.日志.第三方库.配置工具.Web 工具.书籍.电子书.经典博文等等. 初始翻译信息来自:<推荐!国外程序员整理的 PHP 资源大全& ...

  3. php数据库访问及增删改

    利用PHP访问由MySQL构建的数据库 连接到数据库 //1.造连接对象 $db = new MySQLi("localhost","root","1 ...

  4. 2.JAVA之GUI编程布局

    布局管理器 容器中的组件排放方式,就是布局 常见的布局管理器: **************************************************** 1.FlowLayout(流式 ...

  5. Keil> 编译器特有的功能 > 关键字和运算符 > __weak

    __weak 此关键字指示编译器弱导出符号. 可以将 __weak 关键字应用于函数和变量声明以及函数定义. 用法 函数和变量声明 对于声明,此存储类指定一个 extern 对象声明,即使不存在,也不 ...

  6. Get radio selected value

    先看下面 foreach得到的radio list: 现在想实现把选择的选项值Post至服务端:

  7. 设计模式(十)组合模式(Composite Pattern)

    一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象 ...

  8. ORACLE实现自定义序列号生成

    实际工作中,难免会遇到序列号生成问题,下面就是一个简单的序列号生成函数 (1)创建自定义序列号配置表如下: --自定义序列 create table S_AUTOCODE ( pk1 ) primar ...

  9. Singleton(单例模式)的一种实现 -- 基于【惰性】适用于【大对象】的一种生产实践

    一.说明 本文中的代码类,在生产中使用了很长的时间,曾应用于多个企业多个项目实践中,其中也踩了不少坑,总结了一些适用的业务情景, 重要的事情说三遍: a.本代码类不是万能药,不要在业务情景中滥用! b ...

  10. atitit.http原理与概论attilax总结

    atitit.http原理与概论attilax总结 1. 图解HTTP 作者:[日]上野宣 著1 2. HTTP权威指南(国内首本HTTP及其相关核心Web技术权威著作)1 3. TCP/IP详解(中 ...