从TSDF到Marching Cubes的mesh构建

从TSDF到Marching Cubes的mesh构建

  • 引言

书接上文,我们将空间分成了一个个的小体素,并在体素内用TSDF来表示体素在视线方向上到最近表面的距离。

当把TSDF距离为0的那些体素或者体素点连接起来就构成了三维表面。但一方面,TSDF恰好为0的概率很小,得做取舍处理,损失一部分精度,另一方面,将这些体素点直接连接起来的做法也很粗燥。实际也没有人直接这么做,大家都只是将TSDF作为中间量,再进行后续的建模处理。今天要讲的Marching Cubes——移动立方体算法就是其中之一。(下面我还是以Open3D库的代码为例来介绍)

  • 介绍

Open3D是Inter Visual Computing Lab的研究科学家Qianyi Zhou(前)和Jaesik Park共同完成的开源库,支持处理3D数据的软件快速开发。

http://www.open3d.org/docs/introduction.html

https://github.com/IntelVCL/Open3D

Marching Cubes是一种用于在体积数据(体素)中渲染(生成)等值面(表面)的算法。核心概念是在设定好的立方体(体素)及顶点标量值后(如TSDF算法中的tsdf函数值),通过比较顶点和用户指定阈值(如TSDF中的表面0)时,确定体素的哪些边与等值面相交,创建三角贴片,并连接等值面边界上所有立方体的面片,以此得到一个表面[1]。

  • Marching Cubes算法

三维离散数据场中每个栅格单元作为一个体素,体素的每个顶点都存在对应的标量值。如果体素顶点上的值大于或等于等值面值,则定义该顶点位于等值面之外,标记为“0”;而如果体素顶点上的值小于等值面值,则定义该顶点位于等值面之内,标记为“1”。由于每个体素单元有8个顶点,那么共存在2^8 = 256种情形,下图是Marching Cubes算法的15种基本情形,其他241种情形可以通过这15种基本情形的旋转、映射等方式实现[2]。

每个体素单元上顶点和边的索引规则如下图左所示,假如体素下方的顶点3的值小于等值面值,其他顶点上的值都大于等值面值那么我们可以生成一个与体素边2,3,11相交的三角面片,而三角面片顶点的具体位置则需要根据等值面值和边顶点3-2,3-0,3-7的值线性插值计算得到[2]。

索引规定:

edgeTable=V11 V10 V9 V8 V7 V6 V5 V4 V3 V2 V1 V0

因此上图cubeindex=[0 0 0 0 1 0 0 0] 即 cuberindex=8

查询edgeTable[256]得 edgeTable[8]=1000 0000 1100 即边2/3/11与等值面相交

查询triTable[256]生成对应三角面片,triTable[8]={3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} 即可以生成三角面片(3, 11, 2),三角面片的3个顶点为边3,11,2和等值面相交的交点。

最后通过线性插值计算交叉点,并正确连接每个网格单元的小(三角)平面组合和来自相邻网格单元的小平面,形成表面。

  • Open3D 中的Marching Cubes(承接TSDF)

(以下代码均取自\Open3D\src\Core\Integration\ScalebleTSDFVolume.cpp)

16*16*16的volume,到1*1*1的体素立方体,将TSDF中的权重w,tsdf函数值f,颜色c赋给体素顶点作为标量。

16*16*16的volume结构

当立方体移动到volume的表面时,体素顶点的赋值处理。

在体素立方体里确定cubeindex。关键运算“cubeindex=cubeindex|1<<i”
(先将1在二进制里向左位移i位,然后与原cubeindex进行或运算)

查询edgeTable得到交叉边;查询edge_vertex得到交叉边的两端点;由两端点内插得Mesh格网点(坐标及color)

按Tritable查询合适三角面片点,将前三个点组成的第一个面片加入mesh,三角格网mesh。


[1] Paul Bourke.Polygonising a scalar field.paulbourke.net/geometry/

polygonise/

[2] 算法小丑.水泡动画模拟(Marching Cubes)cnblogs.com/shushen/

p/5542131.html

编辑于 2018-09-25 14:59