我认为最简单的方法就是将中点圆算法扩展到 3D。
首先,让我们弄清楚我们要填充哪些块。假设原点位于块的中间(0,0,0)
和半径R
:
- 我们只想填充球体内的盒子。这些正是盒子
(x,y,z)
这样x²+y²+z² <= R²
; and
- 我们只想填充能显示脸部的盒子。如果一个盒子有一张脸,那么至少有一个邻居是not在球体中,所以:
(|x|+1)²+y²+z² > R²
OR x²+(|y|+1)²+z² > R²
OR x²+y²+(|z|+1)² > R²
这是第二部分,让它变得棘手,但请记住这一点(|a|+1)² = |a|² + 2|a| + 1
。如果说,z
is the largest球体内部盒子的坐标,如果该盒子有一个面显示,那么z
尤其是脸部会被暴露出来,因为x²+y²+(|z|+1)² = x²+y²+z²+2|z|+1
,并且该值至少与类似值一样大x
and y
.
因此,很容易计算 1) 在球体内部,2) 有的盒子z
作为它们的最大坐标,并且 3) 具有最大可能的 z 值,即,将 1 添加到 z 会导致球体外部出现一个框。此外,4)对所有人都有积极的价值x,y,z
.
然后可以通过 24 种不同的方式反映这些盒子的坐标,以生成球体表面上的所有盒子。这些是坐标符号的所有 8 种组合乘以轴具有最大坐标的所有 3 个选项。
以下是如何生成正数点x,y,z
and z
最大:
maxR2 = floor(R*R);
zx = floor(R);
for (x=0; ;++x)
{
//max z for this x value.
while(x*x+zx*zx > maxR2 && zx>=x)
--zx;
if (zx<x)
break; //with this x, z can't be largest
z=zx;
for(y=0; ;++y)
{
while(x*x+y*y+z*z > maxR2 && z>=x && z>=y)
--z;
if (z<x||z<y)
break; //with this x and y, z can't be largest
FILLBOX(x,y,z); //... and up to 23 reflections of it
}
}
注意:如果这对您很重要,请在计算反射时小心,以免绘制,例如,(0,y,z)
and (-0,y,z)
,因为这是同一个盒子两次。也不要交换具有相同值的轴,因为这又会绘制同一个框两次(例如,如果您有(1,5,5)
,不交换y
and z
并再次绘制。
另请注意R
不一定是整数。如果再加0.5,看起来会好一点。
这是一个考虑了上述所有内容的示例(您需要支持 webgl 的浏览器)https://jsfiddle.net/mtimmerm/ay2adpwb/ https://jsfiddle.net/mtimmerm/ay2adpwb/