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

  [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. java发送http的get、post请求

    转载博客:http://www.cnblogs.com/zhuawang/archive/2012/12/08/2809380.html Http请求类 package wzh.Http; impor ...

  2. -Android -线程池 批量上传图片 -附php接收代码

    (出处:http://www.cnblogs.com/linguanh/) 目录: 1,前序 2,类特点 3,用法 4,java代码 5,php代码 1,前序 还是源于重构,看着之前为赶时间写着的碎片 ...

  3. Oracle --> Vertica 数据类型转换规则

    需求:在Vertica数据库上建表,表结构来源于原Oracle数据库,故需要转换成Vertica数据库库表结构.   实际转换操作需要评估源库用到的所有数据类型和数据本身特性. 下面是总结的某场景下的 ...

  4. Angular2 小贴士 RouterLink 导航

    AngularJS的路由一直是学习的一大难点,我们只能边看边学边掌握,边看边学边推翻.今天我们来看一下在angular2中通过routerLink实现导航的几种方式,以及各自的优缺点. Angular ...

  5. iFrame 功能详解

    目录索引: 一. 简介二. 属性三. 功能四. 应用 一.简介 网页“帧”的概念最早是由Netscape所提出,当时全部由“帧”构成的页面,也被称之为 “框架集”页面,在一个“框架集”页面中,“帧” ...

  6. 微服务(Microservices)—Martin Fowler【翻译】

    本文转载自:http://www.cnblogs.com/liuning8023/p/4493156.html -------------------------------------------- ...

  7. C# 条件编译

    本文导读: C#的预处理器指令从来不会转化为可执行代码的命令,但是会影响编译过程的各个方面,常用的预处理器指令有#define.#undef.#if,#elif,#else和#endif等等,下面介绍 ...

  8. WPF binding 参考

    Introduction This is an article on WPF Binding Cheat Sheet. Some of the Binding won't work for Silve ...

  9. dpkg:处理软件包dradis (--configure)时出错

    dpkg:处理软件包dradis (--configure)时出错!解决方案:1.将info文件夹更名%mv /var/lib/dpkg/info /var/lib/dpkg/info_old2.新建 ...

  10. spring源码:学习线索(li)

    一.spring xml配置(不包括AOP,主要了解在初始化及实例化过程中spring配置文件中每项内容的具体实现过程,从根本上掌握spring) <bean>的名字 &,alia ...