三维网格精简算法(Quadric Error Metrics)附源码
在计算机图形应用中,为了尽可能真实呈现虚拟物体,往往需要高精度的三维模型。然而,模型的复杂性直接关系到它的计算成本,因此高精度的模型在几何运算时并不是必须的,取而代之的是一个相对简化的三维模型,那么如何自动计算生成这些三维简化模型就是网格精简算法所关注的目标。
[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)附源码的更多相关文章
- swfupload多文件上传[附源码]
swfupload多文件上传[附源码] 文件上传这东西说到底有时候很痛,原来的asp.net服务器控件提供了很简单的上传,但是有回传,还没有进度条提示.这次我们演示利用swfupload多文件上传,项 ...
- 【转】.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 ...
- 8个前沿的 HTML5 & CSS3 效果【附源码下载】
作为一个前沿的 Web 开发者,对于 HTML5 和 CSS3 技术或多或少都有掌握.前几年这些新技术刚萌芽的时候,开发者们已经使用它们来小试牛刀了,如今这些先进技术已经遍地开发,特别是在移动端大显身 ...
- C#编程总结(七)数据加密——附源码
C#编程总结(七)数据加密——附源码 概述 数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为“密文”,使其只能在输入相应的密钥之后才能显示出本来内容 ...
- Remote验证及其改进(附源码)
Remote验证及其改进(附源码) 表单中的输入项,有些是固定的,不变的验证规则,比如字符长度,必填等.但有些是动态的,比如注册用户名是否存在这样的检查,这个需要访问服务器后台才能解决.这篇文章将会介 ...
- javaweb异常提示信息统一处理(使用springmvc,附源码)
一.前言 后台出现异常如何友好而又高效地回显到前端呢?直接将一堆的错误信息抛给用户界面,显然不合适. 先不考虑代码实现,我们希望是这样的: (1)如果是页面跳转的请求,出现异常了,我们希望跳转到一个异 ...
- 13行代码实现:Python实时视频采集(附源码)
一.前言 本文是<人脸识别完整项目实战>系列博文第3部分:程序设计篇(Python版),第1节<Python实时视频采集程序设计>,本章内容系统介绍:基于Python+open ...
- 日志组件Log2Net的介绍和使用(附源码开源地址)
Log2Net是一个用于收集日志到数据库或文件的组件,支持.NET和.NetCore平台. 此组件自动收集系统的运行日志(服务器运行情况.在线人数等).异常日志.程序员还可以添加自定义日志. 该组件支 ...
- openlayers5-webpack 入门开发系列结合 echarts4 实现散点图(附源码下载)
前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...
随机推荐
- Log4Net生成出现未引用错误解决方法
1.步骤一: 2.步骤二: 明明添加了引用怎么还提示找不到命名空间呢.解决这个问题很简单,右键项目选择属性: 3.步骤三:换成.NET Framework 4即可,解决! 4.两个有啥区别? Micr ...
- Web API与OAuth:既生access token,何生refresh token
在前一篇博文中,我们基于 ASP.NET Web API 与 OWIN OAuth 以 Resource Owner Password Credentials Grant 的授权方式( grant_t ...
- 前端学HTTP之WEB服务器
前面的话 Web服务器每天会分发出数以亿计的Web页面,它是万维网的骨干.本文主要介绍WEB服务器的相关内容 总括 Web服务器会对HTTP请求进行处理并提供响应.术语“Web服务器”可以用来表示We ...
- 如何在删除ibdata1和ib_logfile的情况下恢复MySQL数据库
昨天,有个朋友对公司内部使用的一个MySQL实例开启binlog,但是在启动的过程中失败了(他也没提,为何会失败),在启动失败后,他删除了ibdata1和ib_logfile,后来,能正常启动了,但所 ...
- CLR via C# 摘要一:托管程序的执行模型
托管程序的执行模型大致如下: 编译源代码为程序集(dll或exe文件),程序集包括了记录相关信息的元数据和IL代码 执行程序集文件时,启动CLR,JIT负责把IL编译为本地代码并执行 IL是微软推出的 ...
- 从架构层面谈web加载优化(个人整理)
最近听了阿里一位大牛的讲座,讲web架构优化对网页加载的影响,看完之后对他所讲的一些优化方法进行一些总结和整理,发现收获还是蛮多的,下面多为个人整理和个人见解,希望有说的不对的,能及时指出 1.DNS ...
- TagHelper是怎么实现的
众所周知,在asp.net core中编写Razor视图的时候,用了一种新的写法--TagHelper 那这个TagHelper是怎么回事呢? 首先来看看TagHelper的项目位置,它是位于Micr ...
- WPF 虚拟化 VirtualizingWrapPanel 和 VirtualLizingTilePanel
一. UI 上两个扩展 public class VirtualizingWrapPanel : VirtualizingPanel, IScrollInfo { #region Fields UI ...
- ASP.NET MVC4入门到精通系列目录汇总
序言 最近公司在招.NET程序员,我发现好多来公司面试的.NET程序员居然都没有 ASP.NET MVC项目经验,其中包括一些工作4.5年了,甚至8年10年的,许多人给我的感觉是:工作了4.5年,We ...
- Spring+ibatis动态管理数据源
Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性.而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时 ...