Voxelization 三维模型体素化
- 导入mesh文件,以obj文件为例:
一般文件mesh文件内容有顶点与面,可以用三维设计软件生成,生成的时候注意mesh文件只保存三角形面片,以便后面读取
obj文件格式:
v x y z
f v1 v2 v3
只需要处理这两个关键字就行了,v开头的是三角形面片,f开头的是三角形的三个顶点。 - 离散三角形面片
这里分为两步:
第一步:离散三条边(线段)
这个应该很简单,沿着边每隔dx去取点,然后吧取到的点放在放在体素中心就行了(可以看图形学的书)
第二步:离散三边围成的面
如果上面写好了离散线段的程序的话,这一步也很简单,首先很容易得到平行线与三角行的两个交点,直接利用向量计算就行了,得到交点以后就得到线段了。这里的间距要取的小一点,这个图里的间距太大了,两条平行线的最短距离应该要小于0.707*dx,这个0.707是二分之根号二,可以证明。
最后一张离散完的bunny:
- 体的离散
最后一步,实体的离散,只要保证表面没有空洞,最简单的办法就是在实体内部找一个种子,用种子填充算法进行填充,算法可以参考二维的扫描种子填充算法,百度就有一大堆。
稍微不足的是,体内的种子需要手动指定,没有高效的办法。下面给出两种我觉得还可行的方法。
方法一:可以尝试任取一个面片的中心向法向量负方向移动一段距离作为种子(当然有可能不在体内),但是大概率还是在体内的,但是如果不在的话,就吧体外给填充了,而且会触碰到包围盒边界一般就终止报错了。
方法二:还可以取一个体素,在这个体素上随便做个小面,然后遍历整个模型在这个小面上的投影面积,如果是正数,就在模型内部,如果为负数的话,再找下一个种子点,这个种子点可以随机生成,因此这个方法是自适应的,但是当模型占空间位置较小的时候,种子点随机撒不到模型内部的话,就要花点时间了(按照概率论总会撒到的你说是不是?)。 - 关于效率
这个程序因为基本都是写浮点数运算,不需要迭代,所以比较还是比较快的,基本上点一下就出来了。没有用到GPU加速。
如果有性能要求的话,可以在离散面片的时候用上OpenMP并行,因为每个面片的离散都是独立的,而且也没有访问冲突,所以加速比可以达到很高。
如果还有更高的要求的话,可以用八叉树算法(看论文),用八叉树编码整个空间,然后用八叉树编码的位运算代替浮点数运算,可以达到更高的效率。
这儿应该离散个上亿规模的体素应该不是问题了。
如果还有更高更高的要求的话,用GPU,因为这本来就是图形学的任务。
最终效果:https://www.bilibili.com/video/BV14K4y1U72v?p=7