想象一下N³分辨率的体积立方体,其中充满了遮挡体素。立方体可以完全填满,或包含弯曲的“隧道”,或墙壁 - 或只是一些流浪的体素;我们现在选择边界立方体的六个面中的任意两个,并尝试找到连接这两个面的线而不击中其中的任何体素。如果存在这样的线条,则面部可以看到彼此,否则,它们会被完全遮挡。
我的问题是:是否存在O(n)(或更好)算法以快速辨别是否可以绘制这样的线?该行的确切参数无关紧要。
答案 0 :(得分:1)
我不清楚在这个(连续的?离散的?)空间中成为直线的确切参数,但是我想知道您是否在寻找动态编程解决方案?
也许让我们局限于二维从左到右的情况来构建算法,然后进行概括:
遍历数组的第一列, 对于每个不透明的正方形,标记为不可能建立到达该正方形的射线 对于每个不透明的正方形,标记有可能达到该正方形-并且-坡度的跟踪范围可以达到该正方形。您可以通过可能到达体素体另一端的那组斜率来限制此初始化中的斜率集。
然后在下一列上循环
上一列中的任何正方形都可以潜在地到达每个正方形,但前提是可以到达前一列中的正方形的斜率范围与从上一列中的正方形到达当前正方形所需的斜率范围相交。
因此,您可以将当前正方形中的有效斜率范围设置为有效范围(从以前的正方形到有效正方形的交集)到当前正方形的交集。
您将继续遍历各列,直到到达远端为止,远端上所有可到达的条目都将报告允许到达该正方形的矢量的斜率范围。
算法的速度很大程度上取决于您可以合并和相交斜率范围的速度(或在3D情况下,UV坐标的任意范围)。在2D连续空间中,可以通过在3D离散空间中进行排序来快速完成此操作,您可以根据体素空间的尺寸在X,Y中使用一组可能的矢量斜率。在3D连续空间中,某些类型的四叉树可能会接近通过2D排序可以实现的效果。
该算法在输入中的每个单元上循环一次(您是否考虑此O(n)或O(n ^ 3)?),并且所花费的时间将由交集的并集乘以元素数量来限制在您的空间中(我相信在离散情况下最坏的情况是O(n ^ 2),但是如果体积的另一端距离很远,则会在初始化步骤中急剧缩小,并且在许多不透明单元格和适当的情况下可能会迅速缩小)数据结构)
据我所知,处理卷的切片顺序实际上并不重要,因此,如果您知道某些斑点非常不透明(通过不透明单元的总和或其他原因),则可以使用启发式方法进行重新排序交叉口操作。
答案 1 :(得分:0)
Voxel多维数据集看起来像Rubik Cube,体素结构是一个3D矩阵块,所以要从一侧绘制一条线到另一侧,我们需要在每个相关的块中绘制连接到下一个的线,这些线一起形成一条连续的直线。
如果实施得好,以下算法可以正常工作,因为您将在立方体内的本地坐标上工作,3D引擎在将其转换为世界坐标时将自动应用立方体本身的任何变换。
时间复杂度
MATRIX.MAX_Z * (
Time(MATRIX.GET_VOXEL(x,y,z))
+ Time(VOXEL.DRAW-LINE(0,0,0, 0,0,VOXEL_DEPTH))
)
<强>算法强>
FUNCTION DRAW (INTEGER X, INTEGER Y)
INTEGER VOXEL_X = X / MATRIX.VOXEL_WIDTH
INTEGER VOXEL_Y = Y / MATRIX.VOXEL_HEIGHT
FOR i = 0 .. (MATRIX.MAX_Z-1)
VOXEL V = MATRIX.GET_VOXEL(VOXEL_X, VOXEL_Y, i)
INTEGER X_0 = X % MATRIX.VOXEL_WIDTH
INTEGER Y_0 = Y % MATRIX.VOXEL_HEIGHT
INTEGER Z_0 = 0
INTEGER X_1 = X_0
INTEGER Y_1 = Y_0
INTEGER Z_1 = (MATRIX.VOXEL_DEPTH-1)
V.DRAW-LINE(X_0,Y_0,Z_0, X_1,Y_1,Z_1)
END-FOR
END-FUNCTION
答案 2 :(得分:0)
因此,进行此测试的一种简单方法是以任意分辨率渲染从源到目标立方体的视图(正交)。如果剩下任何背景像素,则在两个矩形之间存在一条线。所以复杂性归结为两件事:
现在,对于二进制渲染,您需要知道的唯一内容是覆盖/未覆盖。这可以归结为两个八叉树,一个是最小值,一个是最大值。最小树轨道&#34;是否有任何打开的子节点(或)&#34;最大曲目&#34;是否有任何封闭的子节点(和)&#34;。构建这些树是n log(n),但查询只是log(n)。
对于目标分辨率m,它应该只是log(m)。即使你的浮动尺寸达到m = 2 ^ 23。
答案 3 :(得分:0)
将问题分解为两个维度,显然一些体素配置显然是不可穿透的,例如,从左到右:
+-+-+-+ +-+-+-+-+-+
| |#| | |#| | | | |
+-+-+-+ +-+-+-+-+-+
| |#| | |#| | |#| |
+-+-+-+ +-+-+-+-+-+
| |#| | |#| | |#| |
+-+-+-+ +-+-+-+-+-+
|#| | |#| |
+-+-+-+-+-+
| | | |#| |
+-+-+-+-+-+
......但这可能并不难理解,具体取决于你如何处理角落:
+-+-+-+-+-+
|#| | | |/|
+-+-+-+-+-+
|#| | |/| |
+-+-+-+-+-+
|#| |/|#| |
+-+-+-+-+-+
|#|/| |#| |
+-+-+-+-+-+
|/| | |#| |
+-+-+-+-+-+
......这绝对是可能的:
+-+-+-+-+-+
|#| | | | |
+-+-+-+-+-+
|#| | | | |
+-+-+-+-+-+
|#| | | | |
+-+-+-+-+-+
| | | |#| |
+-+-+-+-+-+
| | | |#| |
+-+-+-+-+-+
现在,如果你能想到任何可以告诉上层2D立方体的技巧,那可能会消除至少一些不可能的像素/体素配置 - 但我担心你需要测试每个像素你的目标面是从任何角度从光源侧射出的光线,听起来非常像n平方问题(2D),或者是3D中的n ^ 4。
在2D中,我从左侧的顶部开始,检查连接我的体素中心到右上方的线是否会碰到一个遮挡像素:如果没有,我们就完成了;如果是这样,你可以提前角度,使光线通过遮挡的左下角并继续检查,直到找到一个通道或到达右侧的末端。
继续使用源端的每个像素,直到完成 - 以某种方式完成。
但那是蛮力的,我有兴趣看到一个更优雅的解决方案,也许是G. Bach ......?