NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - AI模型在线查看 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割 - 3D道路快速建模
点云渲染是一种渲染方法,其中空间中的一系列点以视觉方式表示,而不是相互连接的拓扑。你可能有很多原因需要在点云中渲染事物,个人而言,它从很久以前就一直是我的最爱。这就是我在 Unity 和 Unreal 中实现不同版本的原因。
在这篇文章中,我将首先列出点云渲染的一些优点,以及为什么要使用它们。然后我将编写一系列通用步骤,关于如何将你的网格作为点云,在文章的最后我将分享我的一个简单的 Unity 脚本,它在给定网格的顶点上生成粒子并在一个给定的网格中对其纹理进行采样计算着色器。你可以将脚本用于点云,也可以用于在网格上生成火焰、照明、光环和……粒子。
本文的代码可以从 Github 下载。在线查看3D点云可以使用LasViewer。
1、为什么使用点云
当扫描现实世界(激光或摄影测量)时,你的算法首先会生成一堆用于网格划分的点。通常在网格划分之前表示这些点是人们使用点云渲染的原因。然而,即使你有一个精细的网格,使用点云作为你的渲染方法仍然是有利的。
点云将一个特征与拓扑的其余部分解耦。你可以独立于表面上的相邻点对每个特定点做很多事情,例如:
点云有助于风格化或非基于物理的渲染(我将其称为 NRP)。将纹理应用到每个单独的点可以创造出绘画般的外观。以 Playstation Dream 等游戏为例:
这种解耦使得这些点可以很容易地相互独立地移动。多亏了这一点,点云非常适合消散网格、轻松将一个对象变形为另一个对象、为森林、草和毛皮等动画制作动画:
点云的另一个属性是它对美学的影响,这就是为什么在现实中我们对它们进行大量实验的原因。点云还将表面的感知视觉特征频率与表面的实际频率分离。使用点云,你实际上是在获取一些详细且更密集的拓扑结构的点样本,并通过美学上的高频点来表示它们。这解决了我们在摄影测量中遇到的一个独特问题。
摄影测量是真实的。现实世界的物体被最好的 BDRF 和最多的光线照亮。据我所知,没有任何渲染器可以模仿这种真实感,即使处理时间尽可能长。这一直让我在制作中处于一个艰难的境地,当需要向世界添加一个额外的对象时,它还没有与环境一起扫描,我们就会遇到无法重现这个关卡的问题通过其他方式实现现实主义。我们尝试得越多,它看起来就越糟糕。特别是在虚拟现实中。如果我们采用更风格化的方法,我们必须为其创建高频表面细节以适应摄影测量的高频艺术风格。沿着这条道路,资产生产将非常耗时。点云是一个有趣的解决方案。周围飞行粒子的绝对数量创造了艺术指导的高频,但底层拓扑可能是一个低细节的网格,它可以快速生成。如果你想看看这个美学能走多远,看看这个由 Marshmallow Laser Feast 制作的华丽预告片:
3、点云渲染的一般步骤
通常,如果你使用的是实际的点云数据集,可以将位置导出为 CSV,因此可以跳过第一步。如果你想尝试使用网格的工作流程,请执行以下步骤:
- 对网格顶点/曲面进行统一采样。需要有尽可能多的样本才能拥有粒子。将它们保存在某种缓冲区中。这可以是引擎中的数组、json/ csv 文件、服装格式或纹理。如果在引擎中执行此操作,可以直接将其保存在 GPU 上的缓冲区中。
- (可选)根据标准对你采样的此缓冲区进行排序
- 在引擎中创建用于点的几何图形。作为粒子,计算着色器程序网格、预建模四边形或实例化网格。创建尽可能多的这些你想要的网格
- 在计算着色器/顶点着色器或几何着色器中,对创建的缓冲区进行采样,并设置您在缓冲区中保存的每个粒子的位置、法线或颜色等信息。
这些步骤非常简单,但我会更深入地介绍每个步骤。
4、网格的均匀采样
这个想法是你在网格表面上取点,然后将其位置、颜色和法线保存在某处。这些信息用于稍后将四边形定位在采样位置上。如果你希望表面上点的密度在你的渲染中是均匀的,那么需要采取均匀的样本。
最简单的采样方法是将顶点作为样本,并根据需要从网格中选择尽可能多的随机顶点。这很好,因为网格本身在其拓扑中具有均匀的顶点分布,并且顶点的数量与我们需要的点数一样多或更多。
如果没有满足这两个标准,那么我的第一个建议是重新拓扑网格以使其符合标准。或者,你可以实现一个酷炫的系统,在其中计算网格的总表面积,将其除以确定每个表面积的粒子数所需的点数,然后开始迭代地在网格表面上拾取点,然后移动这些点,直到它们彼此之间的地理距离最大。但这将是太多的工作,只需打开一个免费软件,重新设置网格,然后从原始网格中烘焙纹理和法线信息。
在我共享的脚本中,我在计算着色器中执行此步骤(我的意思是我只是对顶点进行采样),这具有额外的优势,即缓冲区保存在 GPU 设备内存中,并且它没有 需要从 CPU 转移到 GPU。
5、点云缓冲区排序
这个阶段是可选的。你可能想要这样做的原因有两个:性能和特殊的视觉特效。
如果以某种方式对该缓冲区进行排序,则可以提高多个操作的缓存一致性。典型 Mesh 顶点缓冲区已针对顶点缓存进行排序和优化,这与我们的使用无关,因此使用缓冲区可以增加我们案例的缓存一致性。从在 Unreal 中尝试过这种技术的人那里,他们发现对缓冲区进行排序以实现缓存一致性可以提高 50% 的性能。
一种对排序有很大帮助的特定 VFX 是变形。想象一下,如果将两个不同网格的点云信息保存在两个不同的缓冲区中。如果你想在它们之间变形,它就像随着时间的推移在这两个缓冲区之间的每个点进行插值一样简单。如果你的缓冲区只是一个随机样本,则第一个网格上的每个点都将被转移到第二个网格上的一个随机点。虽然这看起来很酷,但它有点混乱。
另一种方法是现在根据相同的标准(位置、法线、颜色……)对两个缓冲区进行排序,如果开始在这些缓冲区之间进行插值,则位于网格缓冲区开头的点与来自网格二。通过这种方式,你可以随心所欲地获得幻想。例如,对于来自网格一的点云上的每个点,在网格二中找到最适合它的点。将这两点保存在同一个索引中。
6、点云粒子的创建
人们在这个领域想出了非常有创意的东西。我在无法访问计算着色器的系统上尝试的第一件事是在 CPU 中生成粒子,将它们沿 x 轴排列成一条直线,其中每个粒子都位于一个完整的整数 x 位置:粒子一,(1,0,0),粒子二(2,0,0)等等。然后使用顶点着色器中的 x 位置作为索引,我对保存点云信息的缓冲区进行采样。在我的第一次尝试中,这个缓冲区作为纹理传递给 GPU,其中 RGB 值在其中归一化 XYZ 值。我只需要对 RGB 值进行非规范化来重建点云。
人们使用的另一种方法是事先在 3D 软件中对静态网格进行建模,其中尽可能多的四边形以与粒子工作流程描述的方式相似的方式排列。基本上相同的方法,你只是避免了运行时的第一次设置成本。这是我为Blender编写的脚本,它可以根据需要创建任意数量的平面,并沿着其中一个轴很好地排列它们。你通常可以将其用于粒子系统,当无法访问计算着色器或缓存友好环境。
上述方法容易出现精度问题。如果你可以访问计算着色器,则不一定要走这条路。如果需要,你还可以使用 VFX 图。我也尝试过使用这种技术的 VFX 图,它可以工作,但目前该图对于实际使用来说仍然太繁琐,所以我将把它留到以后。
想法是将网格传递给 Unity 中的计算着色器,然后在计算着色器中随机抽取网格样本,将其保存到 GPU 缓冲区。稍后在渲染循环中使用图形 API 的绘制程序命令,你可以绘制任意数量的点,可以在其中指向 GPU 上保存点云信息的点云缓冲区地址。具体实现可以看我在 Github 上的代码。
上面的方法速度快,更容易控制,而且之前已经准备好网格,效果非常好。唯一的问题是程序绘制命令发生在统一的设置系统之外进行渲染。使用这种方法,你可能会遇到一些需要修复的错误,例如粒子没有投射阴影、未设置一些着色器值以及 VR 中的一些立体实例化/后期处理屏幕空间 UV 问题。你可以一个一个地修复这些,或者代替 GPU 中用于程序绘图的缓冲区,可以填充一个网格缓冲区并使用 Unity 图形管道来渲染这个新创建的网格。在此工作流程中,你可以使用 unity 准备的所有内容。
7、结束语
就是这样。像大多数 VFX 一样,就可以做/改进的事情而言,这是一个无底洞。你可以将这种技术与 Houdini 等软件结合起来,在这些点云上烘焙一些疯狂的东西,并制作出高质量的 VFX。
BimAnt翻译整理,转载请标明出处