如何快速,实时地生成带符号的距离场(2D)?


21

在上一个问题中,建议可以对带符号的距离字段进行预先计算,在运行时加载然后从那里使用。

由于某些原因,我将在本问题末尾(针对感兴趣的人)进行解释,因此我需要实时创建距离字段。

有一些针对不同方法的论文,这些方法应该在实时环境中可行,例如用于倒角距离变换和基于Voronoi图逼近的变换的方法(如Pixeljunk Shooter开发人员本演示文稿中所建议的),我(因此可以假设很多其他人)实际上很难使用它们,因为它们通常很长,大部分时间都在数学上and肿,并且在解释上不太算法。

您会建议使用哪种算法实时(最好在GPU上)创建距离场,尤其是考虑到距离场的最终质量?

由于我正在寻找实际的解释/教程,而不是指向另一篇论文或幻灯片的链接,因此,只要有资格获得此问题,它就会得到悬赏:-)。

这就是我需要实时进行操作的原因:

如果您必须针对大型2D环境(例如,大型Terraria类地图)预先计算这些SDF,则这意味着您要接受更大的存储空间开销(以及地图生成时间),而需要实施更多足够快的实时SDF生成的复杂算法。

例如,如果您选择一个相对较小的,具有1000 * 256(宽*高)且地图尺寸为10 * 10像素,因此总尺寸为10000 * 2560像素的地图,则已经需要花费大约2兆字节的空间假设您仅存储从0到255的距离值,则SDF分辨率为128x128。

显然,这很快就会变得太多,并且是我不想拥有的开销。

还有别的:

SDF可以用于很多事情(例如冲突检测),并且甚至可能尚未发现一些有用的应用程序。我认为将来会有很多人去寻找这些东西,如果我们在这里得到全面的答复,我想我们将为很多人提供帮助。


我用谷歌搜索“什么是有符号距离字段”,并且第一个点击是GPU版本:http.developer.nvidia.com/GPUGems3/gpugems3_ch34.html 有点老了,但可能会有助于您进行进一步的搜索。
Patrick Hughes

1
也许我错过了一些东西,但是我对为什么需要实时进行处理的陈述感到困惑(尤其是为什么它会被扰乱了)。首先,对于128x128的SDF,您从哪里得到2MB的数字?其次,为什么您认为2MB的内存使用量特别大?我同意这并非微不足道,但这似乎只占您整个地图内存使用量的一小部分。第三,如何实时生成字段以节省内存?无论是动态生成还是预先计算的,您仍然需要存储完全相同的数据,不是吗?
史蒂文·斯塔德尼基

更广泛地说,很可能SDF不是您需要的技术。有关您的具体情况的更多信息-静态障碍物计数,动态障碍物计数等-以及您希望达到的效果将有助于尝试确定最有可能对您有用的内容。
史蒂文·斯塔德尼基

1
如果我实时生成距离场,则每帧只能创建一次2MB的内存(总内存开销始终是一个距离场所需的内存,因为我只需要一个用于屏幕)。如果我的地图比我的1000x128示例更大(我认为大型Terraria地图远超过10000),则该地图的每个1000x128子地图都需要2mb之一。为什么我首先需要SDF,在我在该问题的开头链接的第一个问题中进行了描述(它用于GPU 2D阴影投射)。
TravisG

1
@heishe您是否尝试每帧生成2Mb数据?认真吗
kaoD 2012年

Answers:


9

Catalin Zima在他的文章中解释了如何实现动态2D阴影-并且他确实使用了带符号的距离字段(据我所知,这只是在这种情况下阴影缓冲区的一个奇特名称)。他的方法确实需要一个GPU,而他的实现方式并不是最好的(他在我的机器上大约20灯时降到60Hz以下,我的大约500灯);这是可以预料的,因为他更喜欢代码的清晰性而不是速度。

实作

完全由他执行:

  1. 将所有阴影脚轮渲染为纹理。
  2. 计算每个像素到光源中心的距离,并将该值分配给不透明像素的RGB。
  3. 扭曲图像,使其代表3D相机如何看到这些像素。
  4. 使用他的文章中描述的异常调整大小将图像压缩为2xN大小的图像(普通调整大小将不起作用)。
  5. 现在,2xN图像是光的所有四个象限的符号距离字段(请记住,一个象限基本上是90度的单个摄像机平截头体)。
  6. 渲染光照贴图。
  7. 模糊光照贴图(基于与光照的距离),以便获得柔和的阴影。

我的最终实现是(每个步骤都是一个着色器):

  1. 做(1)。
  2. (2)和(3)
  3. 做(4)。他的执行速度非常慢:如果可以尝试使用GPGPU。我无法使用GPGPU(XNA),所以我做的是:
    • 设置一个网格,其中前N / 2列由N / 2个四边形表示,位置完全相同(覆盖最终缓冲区的第一列),但纹理坐标不同(第二N / 2列也是如此)
    • 关闭GPU上的深度测试。
    • 使用MIN像素混合功能。
  4. 执行(6)和(7)。

这非常巧妙:基本上是将阴影从3D处理为2D的直接转换。

陷阱

主要的陷阱是不应遮蔽某些对象:在我的示例中,我正在编写Liero(实时蠕虫)克隆,因此不希望例如对玩家的蠕虫进行遮蔽(至少一个)在每个玩家的屏幕上)。我为这些“特殊”对象所做的全部工作是最后一步,将它们重绘。具有讽刺意味的是,大多数对象没有被遮盖(蠕虫,风景前景),因此这里存在透支问题。


您对调整大小方法的调整是否是加速处理60fps以上500灯的唯一方法?
TravisG

好的,我会接受答案,因为它可以解决我原来的问题,但是并不能真正回答我所提供的赏金。我将等待,也许有人会花很多时间来解释用于生成有符号距离场的几种O(N)方法之一。
TravisG 2012年

@heishe关于您的第一个问题:不确定。我一次完成了所有优化操作-我想我记得将其关闭并观察到帧率大幅下降。每盏灯共进行6次抽奖,将杀死您的帧率。就像我说的那样,据我所知,您在步骤(5)上有4个带符号的距离字段-但是对它们了解更多的人将需要确认。
乔纳森·迪金森

好吧,这是有符号距离字段的非常特殊的情况。在正常的有符号距离字段中,每个像素都包含到最近障碍物的距离。在该算法中,距离场仅包含一个障碍物,并且障碍物在整个图像(光源)中仅为1个像素,这就是为什么可以在O(N)中生成此距离场的原因。
TravisG

1
@heishe这是我的着色器:gist.github.com/2384073。DistortPS为2 + 3。
乔纳森·迪金森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.