我怎样才能建立我的世界风格的光传播没有recursionfunction?

这个问题更多的是扩大在一个旧的,但类似的问题发布的答案。

部分答案是这样的:

您只需从顶部到底部填充日光,每层都会从前一层的相邻体素收集光线,并进行衰减。 非常快 – 单遍,没有列表,没有数据结构,没有recursion。

我其实已经有一个更容易的时间来了解如何为点光源充满光线。 但是这样做对于阳光来说,在一次没有recursion的情况下,我还是不能理解它是如何一步一步完成的。

我想知道的具体问题是:

你只比较邻近体素的照明与4个主要方向,还是你也检查上下邻居呢?

如果不存储照明algorithm的数据结构,那么如何检查已经访问过的体素?

如果有一个图解释了一步一步处理单程光传播将是有益的。 看起来性能要比从每个体素中投射几条射线来看它是否轻。

我不能想办法做到这一点,你不重新访问节点…这是因为光传播造成的伪辐射。 从本质上讲,你可以有一个节点比另一个更“接近”光源,但是两者都点亮。 如果您只访问一次,则可能会因错误的光照值而结束。 但是 ,这只有当你允许光线“围绕”角落等。

但是你确实可以在不使用recursion函数的情况下执行传播。

在这种情况下,我做了以下事情:

  1. 从顶部开始创建一个轻的“面具”,空的体素的全光线值,固体的0
  2. 当您从顶部按下时,根据蒙版设置空体素的光照值
  3. 如果遇到一个固体像素,将该位置的掩码值设置为0
  4. 对于在掩码边缘遇到的空体素,将其设置为最大亮度值-1并将其添加到队列中
  5. 重复2,3和4,直到到达底部。

设置初始照明值后,您可以:

  1. 从队列中popup顶部
  2. 检查它的邻居(上,下,左,右,前,后)灯值
  3. 将光照值小于当前值-1的邻居设置为当前值-1并将其添加到队列中
  4. 重复,直到队列为空

这导致使用Google Chrome的256x256x128体素地图的平均光照计算时间为200ms(在中档桌面上)。 使用队列也消除了函数调用的开销(不要低估函数调用的开销)。

我将尝试将我的示例代码迁移到这个答案,但现在你可以在这里看到它的行动。 需要一个浏览器,允许从networking工作者传递arrays缓冲区。

假设就像“我的世界”一样,你只是在做垂直于海平面的照明,也就是直接向上/向下,就好像太阳总是在正午一样……你只是增加了阳光和阴影体素从黎明到中午的相对对比度,从中午到黄昏减less。 但是,无论一天的时间如何,光线投射角度总是直接向下。

你只比较邻近体素的照明与4个主要方向,还是你也检查上下邻居呢?

向下(或向上)都是必需的。 你所做的只是从体素空间的顶部到底部垂直投射光线。 垂直衰减只有在你投射到地平面之下时才需要(不管你是怎么定义的),也就是在地形的一个洞里,这样你仍然可以直视天空,但是现在在地下。 水平传播/衰减可能只需要软化阴影下面的悬边,浮岛等等,否则太阳光就会被阻挡,只能被阳光照射的水平邻居环境照明所渗透。

如果不存储照明algorithm的数据结构,那么如何检查已经访问过的体素?

您不必:从天空到地面的每个体素列上运行一个while循环(反之亦然),即直到太阳射线碰到一个固体像素为止。 就像任何循环一样,当然你只会在每个元素上运行一次 – 过去的任何事情都已经过去了。 您不需要检查已经访问过的内容。 如果你像“我的世界”那样将体素存储为列,那么当然这会变得更简单,因为你可以快速地看到地面的结束和天空的开始。 RLE压缩允许更less的迭代。