目录
OpenVDB简介
VDB(Voxel Data Base)存储结构
距离场(SDF)和密度场(Density)
VDB格式特点
VDB应用案例
1. 网格运算
2.Ray Marching算法优化
3.模型转流体
PBRT V4
OpenVDB在Unreal Engine中的应用
OpenVDB在Unreal Engine中渲染存在的问题
1.阴影问题
2.可视问题
Unreal Engine 异构体积渲染会用到的一些命令行工具
OpenVDB简介
OpenVDB 是一个获得奥斯卡奖的数据结构,有其对应的C++开源库,包含一个分层数据结构和一套工具,用于高效存储和操作在三维网格上离散化的稀疏体积数据。它由 DreamWorks Animation 开发。在视觉效果行业中,它被用于模拟和渲染水、火、烟、云和大量其他依赖于稀疏体积数据的效果。而这类数据通常的特点是全局稀疏而局部稠密(如下图)。
稀疏结构
在现实中这类数据也很常见,比如风场,核污染等场数据。这类数据往往具有数据量比较大,且存在动态更新,需要空间分析等应用场景的需求。
VDB(Voxel Data Base)存储结构
OpenVDB的数据结构是一种B+ Tree的变体(如下图所示),在这个树状结构中,Root(灰色文字)是稀疏的,大小可调节。而其他节点(绿色,橙色和蓝色文字)则是稠密的,且长度是2的N次方。节点上对应的数组(竖长的大方块)分别是mRootMap,mInternalDAT,mLeafDAT,分别保存了指向子节点的指针(绿色,橙色,蓝色),上层切片的值(白色,灰色)或者体素的值(叶子节点中的灰色和红色)。其中,灰色表明该节点术语不活跃状态,最下面的白色节点则是压缩后的叶子节点,去除灰色节点。而DAT(direct access table)上面的扁平的小方块是压缩后的bit mask,用来记录局部的拓扑结构。
OpenVDB数据结构
距离场(SDF)和密度场(Density)
通常,在OpenVDB上,会保存density属性,还有一个可选的temperature属性,每个体素(voxel)存储的是signed distance field(SDF),标识inside或outside的距离。如下是离散形式下的计算过程,根据曲线获取临近四个点的distance value,通过插值方式计算voxel内任意点的distance值。
SDF双线性插值
在Houdini中,可以很直观的看到模型,VDB盒子和SDF的直观效果,如下图所示
原始模型
VDB体素盒子
SDF距离场
VDB FOG密度场
可以看到VDB的内部数据存储结构:
vdb内部存储结构
VDB格式特点
-
动态性:包括随时间的模拟和动画,以及拓扑结构的动态变换
-
内存高效:包括内存的动态和分层分配和数据的向量化压缩
-
泛型拓扑:支持任意动态拓扑结构
-
快速数据访问(随机或顺序)
-
没有范围限制,无限范围
-
高效的层级算法,基于B+树的缓存优化和bounding-volume查询,以及SSE,多线程,blocking等加速技术
-
自适应分辨率,树状结构
-
简易可配置:比如数据树的深度,节点大小等
-
out of core:具有动态调度
VDB应用案例
VDB支持一些拓扑运算,偏微分计算,CSG建模,布尔运算,填充算法以及Ray Marching的优化,在实际中有很多的应用场景和案例。
1. 网格运算
网格求交
可以清楚直观的在Houdini中看到网格的实际应用
模型VDB
盒子VDB
格网求和(Combining Grids)
网格求差(Subtraction Grids)
网格求交 (Intersection Grids)
求和后SDF显示
求和后FOG显示
2.Ray Marching算法优化
左图是原始的云,是一个多边形表面,采用VDB的树状结构,转化为15000900500的体素网格,并最终渲染得到右图
3.模型转流体
模型转流体
PBRT V4
2020年Matt Pharr介绍了PBRT V4[1]从V3升级的的技术实现,里面很多的经验都很有价值。而V4中采用了新的体渲染的算法,引入了Null Scattering的概念,而且对Heterogeneous的数据,采用了NanoVDB格式。NanoVDB是一个迷你版的OpenVDB,其最大的特点是同时支持CPU和GPU下的高分辨率稀疏体积数据的渲染,包括:C++,C99,CUDA,OpenCL,OpenGL,WebGL,DirectX12,OptiX,HLSL和GLSL,且不依赖OpenVDB,并可以和OpenVDB相互转换。OPenVDB和NanoVDB的结构对比如下:
OpenVDB和NanoVDB结构示意图
在数据结构上,NanoVDB是对OpenVDB的线性快照,节点严格的4字节对齐,广度优先,如上图,同一个level的节点都紧凑的存储在一起而抛弃了指针(链表),因此在不同设备(CPU与GPU)之间的拷贝性能更快,且对缓存更为友好。并且,支持元数据的统计能力,以及 out-of-core 和 in-core 的数据压缩支持。而NanoVDB最大的局限是无法修改数据的拓扑结构。
OpenVDB在Unreal Engine中的应用
在UE5.3之前,需要下载Unreal VDB插件,插件下载地址为:unreal-vdb,在版本包里选择自己对应的UE版本进行下载。
unreal-vdb 插件下载
然后打开Unreal Engine 项目,转至 File > Manage Project > Plugins。
将克隆的 unreal-vdb 文件夹复制到项目的 Plugins 目录下。重启 Unreal Editor 以加载新插件。在插件管理中确保 Unreal VDB 已启用。然后就可以正常使用VDB插件了。
Unreal Engine VDB 插件配置
从UE5.3之后,UE将VDB相关操作全部集成到了UE引擎中,就可以很方便的使用VDB相关的操作了。首先需要准备相关的VDB数据,可以在free-vdb-animations下载自己感兴趣的VDB数据。
free-vdb-animations VDB数据下载
下载后的数据有两类,一类是静态的单个VDB数据,另一类是带有序列的多VDB数据,在UE5.3中,将VDB数据拖入引擎可以将VDB数据以资产的形式导入到引擎中。
Unreal Engine 导入VDB数据
可以看到VDB数据导入时会提供是否导入序列选项,如果是单个静态VDB数据,就不需要勾选此选项,如果是多序列数据,就需要勾选此选项。可以看到,VDB数据提供了两个属性,分别是属性A和属性B,存储的数据类型可选,除了density之外,在不同的通道内还存有不同的数据,本质上属性A和属性B没有区别。
导入VDB数据之后,UE中需要使用异构体积渲染器进行渲染。
将异构体积(HeterogeneousVolume)拖入场景之后,需要根据VDB数据制作相关的材质,在制作材质的时候,使用UE提供的稀疏体积纹理进行制作,附相关蓝图节点如下,里面对应的属性A和属性B就是导入的VDB数据的属性A和属性B。
Unreal Engine VDB蓝图
这里渲染了一个烟雾扩散的序列效果
OpenVDB在Unreal Engine中渲染存在的问题
1.阴影问题
Unreal Engine 在Lumen模式下渲染VDB是没有光照阴影的,如图所示
Lumen模式下渲染VDB数据
添加一个球体进行对比,球体是有光照阴影的,如图所示
Lumen模式下渲染球体VDB数据
Unreal Engine在光线追踪模式下对VDB进行渲染,是可以生成阴影的,如图所示,开启光线追踪后,会发现VDB是没有被渲染出来的,这是因为Unreal Engine在光线追踪模式下默认是不开启VDB渲染的,需要再控制台使用命令行工具开启VDB渲染 :r.PathTracing.HeterogeneousVolumes 1
光线追踪模式下渲染VDB
2.可视问题
Unreal Engine在渲染异构体积时,默认当相机拉远之后会出现异构体积消失问题
异构体积消失
需要通过命令行设置异构体积最大可视距离,设置之后就不会出现异构体积消失问题命令行:r.HeterogeneousVolumes.MaxTraceDistance 1000000
Unreal Engine 异构体积渲染会用到的一些命令行工具
-
r.PathTracing.HeterogeneousVolumes(Default = 0), =1 光线追踪模式下关闭/开启异构体积渲染
-
r.HeterogeneousVolumes.MaxTraceDistance (Default = 30000) 设置异构体积最大可视距离
-
r.HeterogeneousVolumes.Debug:(Default = 0),=1进入可视化Debug模式,显示体素网格透光率
-
r.HeterogeneousVolumes.DepthSort:(Default = 1),启用深度排序
-
r.HeterogeneousVolumes.HardwareRayTracing:(Default = 0), = 1进入硬件光追模式【只支持N卡】
-
r.HeterogeneousVolumes.MaxStepCount : (Default = 512)步进次数,越大效果但性能消耗越高,如果觉得掉帧有些厉害,可以适当降低
-
r.HeterogeneousVolumes.StepSize:主步进步幅,使用该命令覆写
-
r.HeterogeneousVolumes.ShadowStepSize:ShadowRay步幅,会影响体积对象上的阴影分布
-
r.HeterogeneousVolumes.MaxTraceDistance:(Default = 30000),ViewRay的最大步进距离
-
r.HeterogeneousVolumes.MaxShadowTraceDistance:(Default = 30000),ShadowRay的最大步进距离
-
r.HeterogeneousVolumes.IndirectLighting:(Default = 0),=1为半透明注入Lumen GI [二阶球谐]
-
r.HeterogeneousVolumes.Jitter:(Default = 1) 默认为步进过程进行抖动(不是沿绝对直线),这可以一定程度避免较低步进次数下的摩尔纹,保持默认即可
-
r.HeterogeneousVolumes.Preshading:(Default = 0),默认为0渲染模式处于LiveShading状态, =1进入PreShading模式,后者可以看作是体积雾的增强版。LiveShading和PreShading个人感觉谈不上哪种方案更好,只是两种实现体积效果的代表思路
-
r.HeterogeneousVolumes.VolumeResolution.X:控制PreShading模式下Lighting Cache Volume的分辨率。