Answers:
第一。让我们写下我们对每个体素的了解:
voxel = (x, y, z, color) // or some other information
一般的方法就是这样:
set of voxels = set of (x,y,z, color)
请注意,三元组(x,y,z)唯一地标识每个体素,因为体素是空间中的点,并且不可能有两个点占据一个位置(我相信我们正在谈论静态体素数据)。
对于简单数据应该没问题。但这绝不是一种快速的数据结构。
渲染是通过扫描线算法完成的AFAIK。汤姆在体素上的硬件文章中有scanline算法的图像。
如果需要快速查找,则用于查找的最快数据结构是哈希(aka数组,映射...)。因此,您必须利用它进行哈希处理。因此,我们天真地希望获得最快的方法来获取任意元素:
array [x][y][z] of (color)
它具有O(1)用于通过x,y,z坐标查找体素。
问题是,它的空间要求是O(D ^ 3),其中D是每个x,y和z数的范围(忘记实数,因为如果它们是Char,具有256个值的范围,则将有256 ^ 3 = 2 ^ 24 == 16777216个元素)。
但这取决于您要对体素做什么。如果渲染是您想要的,则可能是您想要的此数组。但是存储问题仍然存在...
一种方法是在阵列中使用RLE压缩。想象一下一个体素切片(一组体素,其中体素具有一个坐标常数值.....例如,z = 13的平面)。这样的体素切片看起来像MSPaint中的一些简单绘图。我会说,体素模型通常占据所有可能位置的一部分(所有可能体素的D ^ 3空间)。我相信,“从三元组的坐标中获取一对并压缩剩余的轴”将达到目的(例如,取[x] [y]并为每个元素在给定的x,y下压缩z轴上的所有体素。 。应该有0到几个元素,RLE在这里可以做得很好):
array [x][y] of RLE compressed z "lines" of voxel; each uncompressed voxel has color
解决存储问题的另一种方法是使用树数据结构代替数组:
tree data structure = recursively classified voxels
for octrees: recursively classified by which octant does voxel at (x,y,z) belong to
如果体素是一些简单的高度图,则可以将其存储起来。或者您可以将参数存储到生成高度图的函数,也可以按程序生成高度图...
当然,您可以组合所有可能的方法。但是不要过度使用它,除非您测试您的代码是否正常运行并确定它确实更快(因此值得进行优化)。
除了Octrees以外,还有使用体素,Google“ voxlap”,“ ken silverman”的RLE压缩...
他们可能在谈论两个不同的数据结构方面。
数组结构
当您引用任意数量维度的数组的元素时,请考虑该数组本身,一旦传递索引(例如myArray[4][6][15]
),便知道该位置的内容。如果该位置的是体素,则该体素不需要另外记录自己的x,y和z坐标-持有体素的数组会根据其数组索引位置隐式指定其世界位置。
之所以如此好,是因为用于这种数组访问的指针算法本质上是快速的,通常来说,它为跨语言找到的大多数快速(通常称为“本机”)数组提供了基础。这些数组的缺点是它们必须具有大小相等的字节元素,以使所述指针算法适用。
八进制
(我要注意第二点,因为这几乎不是维基百科所指的,并且体素实现不需要使用八叉树,尽管几乎所有现代人都使用八叉树。)
八叉树的根节点是单个不可分割的多维数据集。让我们建立一个例子。说八角的根,即立方体的正中心{0, 0, 0}
位于3D空间中。一旦开始在该空间中放置对象(阅读:多个对象),就该进一步细分八叉树了。在这里,您可以使用3个平面将其切成8(八进制),这些平面是xy,xz和yz平面。现在,原始多维数据集正好包含8个较小的多维数据集。这些子节点中的每个子节点都与中央父多维数据集偏移。也就是说,例如,位于正xyz八分圆中的多维数据集与父/包含多维数据集的中心的偏移量为{root.width / 4, root.height / 4, root.depth / 4}
。与其为每个子节点指定绝对位置,不如将父节点视为其子空间的原点更具逻辑意义。这与场景图的工作方式相同。
在2D绘图中看到一个正方形非常简单,您可以在其中绘制一个正方形并将其细分为4个相等的区域。如果像八叉树的根节点一样,将父正方形的中心视为{0, 0}
,则子正方形的4个中心将为
{root.width / 4, root.height / 4}
,
{-root.width / 4, root.height / 4}
,
{root.width / 4, -root.height / 4}
,
{-root.width / 4, -root.height / 4}
...相对于其父级-与3D中的原理相同。
您可以使用RLE。但是您可以使用SVO(Sparse Voxel Octree),id Tech 6使用SVO。SVO是一种3D计算机图形渲染技术,使用射线投射或有时将射线跟踪方法转换为八叉树数据表示形式。
该技术有所不同,但是在给定屏幕分辨率和尺寸的情况下,通常依赖于生成和处理可见或可能可见的点(稀疏体素)的外壳。
使用光线投射,因为它更快。
通常,您可以避免地形的3D数据结构。您可以改用高度图。在运行时可以非常便宜和高效地对其进行体素化。按照我的经验,通常需要跟踪每列中需要渲染的最小高度,有时还需要跟踪起点到终点的角度,以便也可以剔除背面的列。
这是我回想很久的一个:http : //sites.google.com/site/williamedwardscoder/spinning-voxels-in-flash
如果您的地形有少量的悬突,山洞或其他无法由高度图表示的要素,那么您可以在高度图中有孔并具有其他表示形式,例如真正的3D体素对象,这些对象仅填充那些在运行时所花费的局部位置是有保证的。
当您拥有大量的真实体素世界时,稀疏体素表示是值得的。 约翰·卡马克(John Carmack)过去几年一直在谈论他们。