如何为动态世界实现符号距离场射线行进?


10

我想我了解“签名距离场射线行进”的基本知识。您使用一堆距离场(例如:http : //iquilezles.org/www/articles/distfunctions/distfunctions.htm)为场景建模,然后对于投射射线的每个像素,从射线的起点开始,找到到该点最近的物体的距离,然后将该点增加最近的距离,直到您碰到东西。我设法制作了一个简单的渲染器,这是该技术的大多数描述都停止的地方。

这使我对如何在实际场景中使用SDF Ray Marching提出了一些疑问:

问题1:在真实游戏中,场景通常很复杂,并加载到CPU上,并带有许多动态对象。我了解基本的遮挡剔除(例如八叉树),并且通过多边形渲染,可以在视锥中创建要渲染的项目列表(在CPU上)。

因此,想象一下我有一个非常复杂的场景,其中许多字符和动态对象在屏幕上移动,并由CPU控制。如何将每帧要渲染的对象流式传输到GPU?每个示例都将场景硬编码为GLSL。有人可以分享动态传输到着色器的级别的示例吗?

问题2:物体如何具有多种颜色?distance函数仅返回一个距离,但是实现通常如何将颜色传回?(例如,您击中了一个红色的球体,而不是一个蓝色的立方体。)如果这是一个CPU实现,那么在终止光线行进器时,我可以在distance函数内部调用一个global函数,这也可以传递被击中对象的纹理/颜色。但是,如何在GLSL中返回商品的颜色或纹理?

谢谢。

Answers:


2

这是一个最小的答案,但是希望共享信息,以防您没有更好的答案。

关于真实游戏如何使用光线行进,通常不使用。仅在最近几年中,游戏才开始对深度缓冲区进行光线行进以进行屏幕空间反射,但是我所知没有一款游戏以您描述的方式使用光线行进-是吗?

对于有关颜色等的另一个问题,人们通常将材料与对象关联起来,并使用射线撞击对象的点的“纹理坐标”来确定对象上该点处的材料属性。常见的材料包括漫反射色,镜面反射强度,发光色和透明度/折射率。

希望至少对您有所帮助!您可能还会从图形堆栈交换站点获得好的答案。


2
“我所知没有游戏会以您描述的方式使用光线行进” Media Molecule即将推出的游戏Dreams使用带符号的距离字段进行用户生成的内容雕刻,但是如果我正确理解,这些字段将转换为点云以进行渲染,而不是被直接光线照射。本文可能有一些想法:dualshockers.com/2015/08/15/…–
DMGregory

1
@DMGregory不错,但是我认为这并不是严格的雷·马兴。因此,这一点仍然有效,游戏通常不使用光线行进。
concept3d

1
更新此线程- 据报道,即将推出的游戏Claybook使用直接通过距离场发射的光线渲染其场景,而不是先将其转换为常规几何形状。那么“还?” 似乎已经证实了两年。:)
DMGregory

1

我目前正在开发一个游戏引擎,该引擎使用带符号的距离场作为渲染技术来显示平滑的过程几何体(现在通过简单的图元(如您的链接中的图元生成)生成,希望将来实现Julia和IFS分形。由于我的引擎专注于过程生成,并且必须以使它们对光线行进者友好的方式定义图形,因此我认为我是回答这个问题的好地方:P。

关于流传输,简单的解决方案是使用某种类型的缓冲区,并在需要进行光线行进时将其扔到GPU上。缓冲区的每个元素都是复杂的类型(例如,C / C ++中的结构),并且每个类型都包含定义您应使用哪些函数来表示它,其位置,旋转度,比例等以及平均颜色的元素。然后,该过程简化为:

  1. 将场景划分为可管理的子集(请注意,无论如何,视锥细胞剔除和遮挡剔除部分还是由光线行进算法自动执行的)
  2. 将子集传递到渲染输入缓冲区
  3. 将缓冲区传递给GPU(如果尚不存在),然后使用普通的传统光线行进渲染场景。您将需要执行某种按步搜索,以评估光线行进器的每次迭代,输入缓冲区中哪个项最接近每个光线,并且您需要对这两个光线进行转换(在这种情况下)您需要在图形旋转到达GPU之前对其进行反转)或距离函数本身(移动函数原点以进行位置更改,例如调整立方边的长度以进行比例更改等)。最简单的方法是在您将它们传递给实际的核心距离函数。

关于图形颜色,请记住,着色器允许您定义复杂的类型以及图元;)。这样,您就可以将所有内容都放入C样式的结构中,然后将这些结构从distance函数中传回。

在我的引擎中,每个结构都包含一个距离,一个颜色以及一个将其与输入缓冲区中相应图形定义相关联的ID。每个ID都是从相关距离函数的周围环境中推断出来的(由于我的映射函数遍历了输入缓冲区以查找与每一步最接近的光线图形,因此当调用每个SDF时,我可以安全地处理循环计数器的值作为该功能的图形ID),而距离值是使用任意核心SDF定义的(例如point - figure.pos 颜色)是根据图形缓冲区中相应元素的平均颜色(因此,为什么保持图形ID有用)来定义颜色,也可以通过对存储的平均值加权的过程颜色来定义颜色(一个例子可能是在Mandelbulb上某个点的迭代计数,将您的“平均颜色”从FP颜色空间映射到整数颜色空间,然后通过对迭代计数进行异或运算,将映射的颜色用作调色板。

程序纹理是另一种方法,但是我从未亲自使用它们。iq在该领域进行了大量研究,并在Shadertoy上发布了一些有趣的演示,因此这可能是收集一些额外信息的一种方式。

无论每个图形的颜色是静态的,是通过程序生成的还是从程序纹理中神奇地采样的,基本逻辑都是相同的:将抽象图形转换为某种中间复杂类型(例如,结构),存储局部距离存储局部颜色,然后再将复杂类型作为距离函数的返回值进行传递。然后,根据您的实现,输出颜色可以直接传递到屏幕,或跟随碰撞点进入照明代码。

我不知道上面的内容是否足够清楚,所以不必担心是否有任何不合理的地方。因为我正在使用HLSL和计算阴影,所以我真的不能给出任何GLSL /像素阴影代码示例,但是我很乐意尝试并解决所有我最初未正确编写的内容:)。

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.