这就是我想出的。这种方法更像是一种迭代的 3D 布尔运算,因此它可能不是您想要的。表面似乎更难,所以我集中精力。
概述
基本上在形状内部的位置添加球体,以最大限度地覆盖表面。我们将球体转换为有符号字节值的 3D 数组。这些值是点,将被球体吞噬。我们在对象内部一次添加一个球体,然后在不同方向上扩大/缩小它以“吃”尽可能多的点。目标是在每个球体上获得尽可能多的积分。积分是通过将球体区域中的积分相加来获得的。通过添加每个球体,我们计算然后将该区域计算为已使用并将数组值设置为 0。
(A) (B) ZZZZZZ (C) ZZZZZZ (D) ZZZZZZ (E) ZZZZZZ (F) ZZZZZZ
/\ ZX33XZ ZX33XZ ZX33XZ ZX33XZ ZX33XZ
/ \ ZX3223XZ ZX3223XZ ZX##23XZ ZX ##XZ ZX XZ
/ \ ZX321123XZ ZX321123XZ ZX####23XZ ZX ####XZ ZX XZ
| | ZX32111123XZ ZX32111123XZ ZX######23XZ ZX ######XZ ZX XZ
| | ZX32111133XZ ZX32111133XZ ZX######23XZ ZX ######XZ ZX XZ
| | ZX32222223XZ ZX##222223XZ ZX3####223XZ ZX3 ####3XZ ZX3 ##XZ
|------| ZX33333333XZ ZX##333333XZ ZX33##3333XZ ZX33 ##33XZ ZX33 ##XZ
X= -1 ZXXXXXXXXXXZ ZXXXXXXXXXXZ ZXXXXXXXXXXZ ZXXXXXXXXXXZ ZXXXXXXXXXXZ
Y= -2 ZZZZZZZZZZZZ ZZZZZZZZZZZZ ZZZZZZZZZZZZ ZZZZZZZZZZZZ ZZZZZZZZZZZZ
(A) 我们要填充的形状。(此处使用 2D,但 3D 类似)
(B) 在点的 3D 网格中转换形状。表面获得最大的数字,当你工作到中心时,数字会落在低正数上(比如 1);形状外得到负数;深层内部得到 1
(C) 添加一个小球体。(我们会种植它)
(D) 扩大球体,直到我们吞噬最大点数
(E) 添加下一个球体并使其生长。
(F) 添加另一个球体。这个很小。
过程
5)首先将形状分解为 3D 块分辨率。
10)然后给表面周围的块最多的“点”。当您向内或向外移动时,块实际接触表面的高点和低点。当你向外走时,这些点应该很快变成负数,因为这将防止突出的球体。当您从表面向内移动时,这些点应该设置为 1,以便中心区域全为 1。这些点可以以不同的方式设置以产生不同的结果。
15) 在球体外部的形状内边缘上找到一个位置。虽然不需要靠近边缘,但它确实最小化了搜索区域。如果找不到位置,请转到 80。如果找不到附近的位置
20)在未被覆盖的形状内绘制一个半径为零的球体
25)向上/向下移动球体直到点最大化(模拟退火)
26)将球体移入/移出,直到点最大化
27)向左/向右移动球体,直到点最大化
28)向上/向下移动球体的顶部,直到点最大化(模拟退火/爬山)
29)向上/向下移动球体的底部,直到点最大化
30)将球体的左侧移入/移出,直到点最大化
31)将球体的右侧移入/移出,直到点最大化
32)将球体的前部移入/移出,直到点最大化
50) 如果 25-32 有任何变化,请重复 (转到 25)
70) 从最后添加的球体中减去点。将内部值(正数)的所有值设置为零,不要调整外部值(负数)。转到 15。
80)(可选)填补内部空白。基本上访问每个元素以确保它小于或等于 0。如果为正,则使用该元素转到 20。否则,如果没有找到,则转到 85。注意:所有外部值都应该是负数,而球体中的所有内部值都应该是 0。
85) 完成
笔记
- 由于会有一个值网格,因此 1000x1000x1000 的工作空间将消耗 1GB。
- 不是一个精确的解决方案
- 可能需要大量计算才能获得更高的分辨率。
- 为了提高效率,较小的球体可以预先记录它们的像素范围,这样就不需要为每次迭代计算球体。
- 可以先完成较低分辨率(即 500x500x500)的版本,然后将球体的位置和大小应用到更大的 1000x1000x1000。也可以解决非常大的形状子部分。