6

UE5 Lumen实现分析

 3 years ago
source link: https://blog.uwa4d.com/archives/USparkle_UE5Lumen.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

UE5 Lumen实现分析

Lumen是UE5的GI系统,和传统意义上的实时GI只包含间接漫反射的贡献不同,它同时包含了间接漫反射和间接高光,提供了一套全新的完整间接光照。Lumen同时支持基于硬件的RTX和基于软件Trace两套算法,本文的入手点是Lumen GI使用基于软件Trace的间接漫反射部分的流程、算法和数据结构分析,从宏观上理解Lumen基本原理和运行机制。

Lumen的核心包括以下几个部分:

  • 独特的场景简化表达,Lumen中提供GI反射的场景不是由模型组成,而是由这些模型简化代理MeshCard组成。
  • 基于距离场的求交加速,Lumen中软件Trace使用的核心加速结构为GlobalDistanceField和MeshDistanceField。光照表达与场景结构相分离,Lumen中缓存光照信息的核心组件有两种:一是存储最高精度光照的AtlasTexture,每个SubTexture对应一个MeshCard,也对应一个场景实体模型的某一小分片;另一种组件是体素(Voxel),体素是运行时生成的,是Lumen光照信息表达的最主体部分。
  • 基于Screen Space Probe的GI求解,求解过程中融合了SSGI,基于MeshDistanceField Trace的MeshCard AtlasTexture光照解算、基于GlobalDistanceField Trace的Voxel光照解算等多种GI算法。

一、求交加速结构

Lumen中有两种主要的Tracing求交加速结构:3D空间的Distance Field和HZB,其中Distance Field又分为Mesh Distance Field(以下简称MDF)和Global Distance Field(以下简称GDF)两种。MDF/GDF用于加速3D空间中的模型(MeshCard/Voxel)求交,Hierarchy Z Buffer(以下简称HZB)则用于屏幕空间中的SSGI的RayCast求交。

二、MDF/GDF

在没有BVH的前提下,RayTracing只能使用固定步⻓沿光线方向均匀步进且每次步进后对场景进行求交,为了穿透薄片和小模型不出错,则需要步进⻓度无限小,而为了运行效率则又希望步进⻓度越⻓越好,两者要求完全相反。均匀步进的示意如下图:

1.png

在有了MDF/GDF之后,这一情况可以得到有效的改观,因为MDF/GDF存储的是当前位置离模型表面最近的位置,所以有了MDF/GDF之后,RayMarch的步进⻓度绝大多数情况下可以大幅提高而又不出现穿透“模型的”错误。如下图所示,从相机前面发出一条光线,蓝色圆即为当前点所存储的Distance Field(离物体的最近距离),因为在这个距离内(圆)不可能有其它物体,所以其每次步进的⻓度可以直接为Distance Field的距离:

2.png

三、HZB

屏幕空间中的RayMatch和3D空间的RayTracing有完全类似的步进问题,屏幕空间缺乏完整的3D场景信息,所以其RayMatch的命中判断通过比较当前像素的深度Z和光线方程在当前位置的Z值的大小来近似——当前像素光线的深度大于等于ZBuffer中的深度(以下讨论基于一般ZBuffer,Reversed Z则规则相反),则认为已经相交,相反则认为没被遮挡,可以继续步进。HZB的基本思想类似于BVH,它先为当前的ZBuffer生成Mipmap链,其中高一级的Mip Z值取它上一线Mip中4个像素中的最小值,然后在执行RayMatch的时候从其中 某一级Mip开始。如果当前Mip中没有相交,则提高Mip层级继续求交,否则降低Mip在更精细的粒度上求交。它的意义是先在较大像素Block中去尝试RayMatching是否和当前Block有交点,如果在较小粒度的像素Block中去求交,且一直有交点,则一直下降到所需要的最高精度这一级去查询光线是否和当前像素相交:相反则会尝试更大Block中是否有交点,从而快速跳过大片不需要逐像素Step的区域。在两级HZB上的RayMatch示意如下图所示:

3.png

四、MeshCard与LumenScene

LumenScene即为Lumen在计算过程中所使用的场景,它是真实场景的一个不完整简化版。对于基于Trace的算法来说,选择一个简化的场景表达意味着对Trace提速,同时也会带来Trace精度的损失。MeshCard是LumenScene的基本组件,从场景结构的意义上来说,它是LumenScene的基本元件,对LumenScene来说,场景中不存在模型——MeshCard就是它们的替代品(Proxy)。

在实时GI中比较常⻅的模型简化是体素(Voxel)和面元(Surfel),Lumen中的MeshCard是一个⻓宽高不等的且只有一个坐标轴朝向Orientation ∈ [-x,+x,-y,+y,-z,+z]的六面体。从形状上来说,它是方块形的积木:

4.jpg

LumenScene就是靠这样的积木一块块拼成的,只不过它不需要手工去搭建,而是自动生成。MeshCard在Lumen中的主要功用是提供光照采样的位置和方向,用于大幅度减少它真正同时也是缓存光照信息的基本构件,MeshCard的6个Orientation即为Ambient Cube1的6个基底函数,即使在模型中的同一个位置,可能存在多达6个MeshCard,每个MeshCard正好表达不同方向。这一表达方式可以对DiffuseLighting有较高的保真度,被广泛应用于Probe Based的各类实时和烘焙GI解决方案中,同时它在还原数据时指令量也较SH精简。

5.png

五、Screen Space Probe

Lumen选择的是使用当前帧屏幕像素所对应的世界位置来放置Probe,并为之命名为ScreenSpace Probe。

Probe的Radiance有两种表达方式,一种是八面体映射(OctahedralMap)[6]存储,默认大小为8*8,Probe的Radiance另一种表达方式是球谐函数,这将在Probe计算完成之后生成。八面体映射使用一张2D的RenderTarget来做为Atlas Texture存储所有的Probe,同时它又没有椭圆映射存在的边界接缝难以处理的问题。八面体映射从2D纹理到球面和半球的映射过程如下图所示,更详细的算法描述⻅参考6

6.png

在有了Meshcard Atlas/Voxel之后,Lumen再次选择加入ScreenSpaceProbe来做为中间光照存储有许多好处,如:

  • 使用非常低分辨率的SpaceSpaceProbe,可以大大的加速最终GI解算过程。
  • 平滑组合不同信号频率的光照信息(Meshcard Lighting/VoxelLighing/SSGI),八面体映射和低阶SH都是低频的IrradianceMap的表达方式,投射这些频率不同的信号到ScreenSpaceProbe中,就相当于对这些光照源进行了一次低通滤波。
  • Probe可以Cache可以重用,Screen Space Probe的巧妙之处在于虽它是在屏幕空间生成,但其保留了完整的Radiance语义——每个Probe实际上存在于具体的世界空间位置,故在相机移动平缓的的时候,实际上每帧屏幕上可⻅的Probe只有很少一部分会发生变化,这就为Cache Probe创造了可能。
  • 不需要类似RTX那样重的Filter来压低方差。

Lumen基本流程

Lumen的完整流程分为离线数据生成、运行时数据更新与光照计算两个大模块,两个模块的主要工作如下所示:

7.jpg

离线阶段
离线生成的数据有MeshCard、MDF、GDF三份数据,在静态模型导入或修改之后自动异步生成,并不需要执行Build步骤。之所以会同时存在MDF和GDF两部分数据,是因为MDF的精度比GDF更高。在运行时,MeshCard将同时作为场景组件和光照缓存结构使用。

运行时阶段
Lumen在运行时有四个主要工作来完成最终的GI计算:

[1] 更新LumenScene
[2] 注入直接和间接Diffuse光照到光照缓存中(包括MeshCards和基于3D Clipmap的Voxel等)
[3] 基于当前屏幕空间自动化放置Probe及Trace得到Probe的光照信息,对Probe的光照信息进行二次编码及生成Irradniance Cahe
[4] 使用Probe的光照信息、二次编码的光照信息及Irradiance Cache信息计算最终Indirect DIffuse和Indirect Reflection,并混合History光照信息做为最终的GI输出

下面针对这几个阶段的工作要点进行介绍和分析。

一、更新LumenScene

1. 基于Primitive的数据更新
LumenScene中的数据分为两部分,一部分来直接来源于FScene的静态模型(包括MeshCards,两种DF数据),另一部分则来源于使用MeshCards和DF等数据生成用于渲染的光照缓存数据(包括各种编码后的Atlas纹理)。故LumenScene的更新的驱动也有两部分:一是场景中的数据变化,二是每帧需要更新特定的光照缓存数据用于后续的光照计算。这些数据更新是在多线程执行的。

LumenScen的的Primitive数据更新操作包括:

  • 新Primitive加入场景,多Instance如ISM等会进行LumenCard合并 --> 新的MeshCards,DF加入LumenScene。
  • 已有Primitive从场景中被卸掉 --> Dirty MeshCards,DF从LumenScene被移除
  • Primitive有更新 --> 更新MeshCards,DF的Transform/Lod等数据。
  • 为MeshCards分配和更新其在材质、光照信息等AtlasTexture中的位置和大小。
  • 把近处未捕获过材质参数的MeshCards加入渲染列表(默认的近处指的是离相机200米内的所有MeshCards,且要求MeshCards的包围盒大于给定阈值,也限制了每帧渲染的MeshCards不超过给定数量,在此做了分帧处理)。
  • Cache近处MeshCards对应静态模型的渲染指令(DrawCommands)和Nanite的渲染列表,用于捕获材质属性(MateialAttributes),其中静态模型使用最大的Lod Level用于节省材质捕获的开销。

LumenScene中把场景划分为远景和近景两部分,故除Primitive外,场景中的相机移动也会触发LumenScene更新:

  • 生成远景使用的Meshcards(默认只有一级Cascade,即只使用一个MeshCard表达远景)

除此之外,针对Nanite模型:

  • Nanite的多Instance在在加入LumenScene时也会自动执行合并操作以减少MeshCards的总数量。

关于Meshcards和AtlasTexture的说明

  • AtlasTexture的组织使用Bin Packing算法进行组织,每个新的Meshcards会尝试在AtlasTexture中进行分配,这里直接沿用UE4中已有的TextureLayout组件来进行子纹理分配
  • MeshCards在AtlasTexture中的SubTexture Size由MeshCard本身的大小、MeshCard到当前相机的距离所共同决定,所以它相机移动时同样会触发AtlasTexture的重新组织
  • MeshCards对应的Sub Texture的面积一般大于1纹素
  • 因为每帧只更新固定数量的MeshCards,故这儿通过优先级排序来保证New MeshCards会先被创建出来,其后才处理Update MeshCards请求

2. 捕获MeshCards的材质属性(MaterialAttributes)
从MeshCard的存储结构可以看到,它没有保存⾃⼰的材质属性和深度信息,⼤概是为了节省磁盘空间和保证其精度的灵活可控性,这些在离线烘焙所缺失的数据需要在运⾏时补⾜⽣成存入对应的AtlasTexture中以备后⽤。接下来步骤,就是为MeshCards准备好⽤于计算GI的材质和其它⼏何形体的相关数据。这些数据属性主要有:

  • Material Albdo,⽤于⽀持Diffuse Lighting的计算
  • Material Emissive,⽤于⽀持⾃发光照亮场景
  • Material Opacity,⽤于处理光线穿过和在半透物体上的半弹
  • Normal,⽤于光照模型计算各类光照
  • DepthStencil,在Lumen后续的各个阶段均有应⽤,如⽤于计算放置Probe点,⽤于计算光照插值权重等

在步骤1中已经处理好Mesh渲染列表,这⼉需要先组织先组织成Instance,尽量减少DrawCall调⽤以节省性能。因为Nanite的Cull-Draw流程和传统的静态模型是两套完全不同的流程,所以这里的流程也需要执⾏两遍。还需要注意的是因为MeshCards⽤于计算GI,所以不管它是不是在视野范围内都应该提交渲染,因此Cull流程在此不⽣效。

在完成材质属性捕获操作后,还会执⾏以下操作:

  • 计算Depth的矩(Moments)并⽣成Mipmap ,⽤于后续Trace时使⽤切比雪夫不等式估算Occlusion,这⼀处理⽅式来源于Variance Shadow Maps[3],也在DDGI[4]中被⽤来处理Irradiance Volume的可⻅性。
  • 预处理Opacity和⽣成Mipmap链。

二、注入光照到缓存(Inject Lighting To Cache)

在完成MeshCards数据更新及材质属性捕获之后,下⼀步就是需要把当前场景中的光照信息注入到光照缓存中去。Lumen使⽤了三种主要的数据结构来缓存场景中的光照信息,它们分别是MeshCards和其对应的AtlasTexture(最⾼精度)、Voxel 3D Clipmap[2](中精度)和GI Volume(⽤于体渲染)。这三种类型的数据同时可以覆盖场景中的静态物体、动态物体和体渲染的物体,可形成完成的GI照明来源。

注入光照的整体流程如下图所示:

8.png

1. VoxelLighting
Lumen中的VoxelLighting和VXGI类似,使⽤是基于3D Clipmap的⽅式以节省存储空间。但Lumen的VoxelLighting中的每个3D纹素和VXGI中的Voxel并不相同——Lumen的每个3D纹理表⽰的是Ambient Cube[1]某⼀个⽅向上的光照投射参数,实际上它所需要的3D纹素数量是其Size的6倍。这⼉可以看到VoxelLighting选择了和MeshCards⼏乎完全相同的结构(六⾯体)和基函数(AmbientCube)。关于Clipmap的详细介绍可以在参考[2]和[5]中找到。

下图展⽰了⼤⼩为4096的3D纹理的全mip与64 * 64的3D Clipmap两者所需加载的纹素数量的对比:

9.jpg

VoxelLighting默认使⽤4级3d Clipmap,存储的是以相机世界位置为中⼼点周围200米范围(可配置)的间接光照信息。所有MipLevels和Directions均直接平铺在⼀张3D纹理中:

  • 纹理⼤⼩为[64,64 * MipLevels,64 * Directions(6)],除X轴等同于Clipmap Size外,在Y轴上平铺开了所有MipLevels,在Z轴上平铺开了Ambient Cube的6个⽅向。
  • 各级Mip表达的距离以指数形式增⻓,第0级表⽰的范围是[0,25米],第3级是[100米,200米] ,反算其精度,可得第0级的精度为25米*2/64,每个Voxel表达的场景空间⼤约在0.78米,类似可得第3级的精度为3.125米。

2. 为MeshCards注入光照
从上⾯的流程图可知,MeshCards的光照注入分为直接光和间接光两部分,且直接光和间接光也都只计算Diffuse贡献⽽不计算&Specular贡献。

第⼀步是先计算MeshCards的间接光,间接光的计算可以按光照源数据来源,Trace⽅式两个维度进⾏拆分,Lumen共⽀持4种不同的间接光计算模式,如下表所⽰:

10.png

默认的,Lumen使⽤VoxelLighting做为间接光的来源并使⽤分块Trace复⽤来计算MeshCard的间接照明。此外,间接光的光源和采样⽅式还有两个值得注意的点:

  • 间接光的两个来源VoxelLighting和Irrdiance Cache都是在后续的Lumen流程中才⽣成的,所以在这⼉采样到的数据是上⼀帧或更早的历史数据。
  • 逐纹素采样⽣成的Indirect Lighting具有更⾼的精度,但需要更多的采样点从⽽性能更差,基于分块的Trace因为复⽤相邻纹素的采样结果,所以在⼤多数情况下可以使⽤更少的采样数量达到更平滑的采样结果。
    11.jpg

关于间接光的Voxel Trace部分的简要说明:

  • 使⽤Global Distance Field进⾏加速求交
  • 使⽤的是Voxel ConeTrace采样VoxelLighting,默认的每个纹素采样8个Cone,根据Hit距离确定使⽤哪⼀级Mipmap
  • 采样的Cone同时会采样天光(如果天光开启)叠加到Lighting结果中

第⼆步是对间接光的结果再次进⾏Bilinear Filter并过滤掉<0的异常值。

第三步是计算直接光照的贡献,Lumen⽀持的直接光类型包括: PointLight 、SpotLight 、RectLight和DirectionalLight。除DirectionalLight是逐盏灯计算外外,其它三种类型的光照都是分批执⾏的——因为它们光照范围有限,可以只把这⼀批次内影响的MeshCards找出来,每批次的直接光渲染只对在他们影响范围内的MeshCards⽣效。

直接光计算的另⼀个问题是需要考虑当⾯MeshCard对灯光的可⻅性问题,Lumen⽀持使⽤ShadowMap或RTX光追来确定灯光到当前MeshCard的遮挡比例(ShadowFactor)。

直接光计算的最后⼀个要点是:只计算Diffuse贡献项。

光照注入的最后两步是:采样Albedo和Emissive到MeshCards对应的DiffuseAtlas和EmissiveAtlas,为MeshCard的最终光照(Indirect+Direct)⽣成Mipmaps,⽣成Mipmaps的时候和⼀般的Mipmap⽣成⽆⼆,使⽤双线性采样过滤⽣成⾼⼀级的纹素。

3. 更新VoxelLighting Mips,Voxel光照注入
从上⾯VoexlLighting介绍⼀节可以看到它是⼀个以相机世界位置为中⼼点的Voxel Clipmap,这样在相机发⽣移动时,Clipmap也同样需要进⾏更新。为减少单次需要更新的Voxel数量,有如下优化。

(1)保证每帧最多更新⼀级Mips,Voxel Clipmap四级Mip更新的的顺序如下如⽰:
a. 第 0,2,4,6,8,... 帧允许更新第0级mip
b. 第 1 ,5,9,13,17,... 帧允许更新第1级mip
c. 第 3,11,19,27, ... 帧允许更新第2级mip
d. 第 7,15,23,31,... 帧允许更新第3级mip

(2)在相机未发⽣剧烈移动时,理论上只需要更新移动⽅向上影响部分的Voxel,如下图所示:

12.jpg

除了相机更新,场景中的Primitive增删修改也会影响到它周围的Voxel,所以这个策略实际上在Lumen的实作中采⽤的是更⼀般的PrimitiveUpdateBounds去和Clipmap Tile Bound求交,来确定真正需要更新的Voxel数量,更新的也不是Voxel,⽽是接下来会介绍到的VisibilityBuffer。

VoxelLighting光照解算过程使⽤MeshDistanceField来加速求交:Lumen选择的是先使⽤当前Voxel Clipmap的Boundbox去剔除掉不在此范围内的所有Objects及其对应的MeshDistanceField,再使⽤这些通过剔除的MeshDistanceField包围盒来计算它们⾃⼰所覆盖了哪些Voxel并把⾃⼰的索引写入所有覆盖Voxel的Trace参数中。在接下来的Voxel Trace Pass⾥,每个Voxel仅需处理上⼀步所填入的MeshDistanceFiled即可。Voxel Trace Pass的输出数据是包含HitDistance和HitObjectIndex组合的VisibilityBuffer。VisibilityData结构如下所示:

uint32_t NormalizedHitDistance : 8 ; //相交距离
uint32_t HitObjectIndex : 24 ; //物体ID

最后的Voxel Shading Pass则从压缩过的VisibilityBuffer中获取到最佳的三张MeshCard来用对Voxel解算光照,这儿计算光照的权重系数不只使用AmbientCube的系数,同时考虑到物体的透明度和MeshCard的可⻅性(类似于VSM,使用切比雪夫不等式估算)。

4. ⽣成和计算GIVolume
此处的GIVolume即为传统Irradiance Volume,其默认覆盖离相机距离80米的世界(z轴)。实现要点如下:

  • 光源来自于VoxelLighting ,使用ConeTrace解决光照,默认的每个Volume采样16个Cone
  • 使用SH2编码每个最终结果
  • 除VoxelLighting外每个ConeTrace也会采样天光
  • 会混合历史光照数据,产生更平滑的变化

三、ScreenSpace Probe与Indirect Lighting解算

根据⼀般的RTGI⽅案,在有了MeshCards及对应的LightingAtlas+MaterialAtlas,⼜有了VoxelLighting和GI Volume的信息,已有⾜够信息解算正常游戏中的GI了。比如我们可以这样去算:

  1. 光源:把场景分为近景和远景,近景使⽤VoxelLighting,远景使⽤DistantMeshCard(相当于⼀个巨⼤的AmbientCube)。

  2. 光照计算:使⽤PixelWorldPosition和PixelWorldNormal获取最近且⽅向匹配的3个Voxel来解算当前GI。

  3. 效率:可以使⽤半屏或更⼩分辨率的GI RenderTarget。

  4. 效果:使⽤spatial和temporal Filter平滑光照,使⽤⼀些粗糙的⼿段处理漏光(比如Normal offset,限制墙体厚度,使⽤stencil标记室内外,使⽤SDF推采样点到物体外等等)。

也可以把VoxelLighting换成GI Volume,仅仅在光照计算获取Volume及计算权重时有所不同:

  1. 光源:把场景分为近景和远景,近景使⽤GI Volume,远景使⽤DistantMeshCard(相当于⼀个巨⼤的AmbientCube)。

  2. 光照计算:使⽤PixelWorldPosition和PixelWorldNormal获取最近的数个GI Volume

  3. 效率:可以使⽤半屏或更⼩分辨率的GI RenderTarget。

  4. 效果:使⽤使⽤spatial和temporal Filter平滑光照,使⽤⼀些粗糙的⼿段处理漏光(比如Normal offset,限制墙体厚度,使⽤stencil标记室内外,使⽤SDF推采样点到物体外等等)。

如果效果想要好一点,我们也可以Per Pixel根据PDF Importance Sample生成采样方向去Trace MeshCard,注意到MeshCards的缓存数据中包含深度相关信息,这就可以直接照搬VoxelLighting的 VisibilityWeigth的计算方式来估算可⻅性,得到类似于GGDI的遮挡效果。

Lumen同时使用了SSGI,Detail MeshCard Trace,VoxelLighting Trace,Distant Meshcard Trace四种方式去 求解最终光照,其中各种Trace的作用距离和优先性排列如下:

  • SSGI 的作用范围是全场景的,即只要SSGI可以Trace到Hit则使用SSGI的反弹信息,SSGI介绍参见《UE4.24 SSGI实现分析》
  • Detail MeshCard Trace的作用起始 范围在距离不超过2米,Trace距离不超过离相机40米,和计算 VoexLighting时一样的方式在采样 MeshCard 光照信息时会使用类似VSM的方式使用概率估算遮挡,在有SSGI确定和MeshCard Trace确定的Probe,不使用VoxelLighting。
  • VoxelLighting Trace的作用范围只覆盖了离相机200米以内的像素范围,遮挡估算是基于Cone实施的。
  • Distant MeshCard Trace作用范围在200~1000米范围内。
  • 半透物体的处理有生成GI Volume。

很容易看到在室外场景中,主要是靠VoxelLighting(含DistantMeshCard)照明,如下图所示:

13.png

有了Probe之后,Lumen的Indirect Diffuse解算流程调整如下:

14.png
  1. Downsample屏幕⼤⼩到1/16,1/16 + 1/32,其中[1/16,1/16]部分均均⽣成Probe,剩下的[1/16,1/32]根据周围probe的空间信息来和⾃适应⽣成。其中uniform placement⼀个pass按16像素距离 + jitter 放置,adaptive placment部分分两个pass,分别按8像素和4像素的距离进⾏迭代,查找需要放置probe的位置。Adaptive Placement的算法可描述为:
sample周围4个probe {sample_probe(uv) , uv|uv + [(0,0),(1,0),(0,1),(1,1)]}
计算bilinear weight
获取这些probe和当前position的深度差和夹⾓, 计算depth weight & corner weight 叠加
biliner weight成finalWeight
如果所有 finalWeight < 0 ,说明周围没有有效的Probe可以采样,则放置⼀个新的probe
  1. 使⽤ConeTrace采样MeshCard和VoxelLighting及SSGI⽣成probe的radiance、对probe做sptial filter和修复边界上的采样点,转⼀份probe到基于SH的数据但并不清理掉原始的probe数据。这样,probe实际上存在两份radiance数据——octahedral map + sh双料存储。

  2. Upsample Probe到屏幕⼤⼩,temporal blend Indirect Diffuse。Upsample有两个主要分⽀:

  • 对于非hair stand的像素使⽤第2步中⽣成的Probe SH,使⽤Adaptive Placement相同的权重进⾏SH混合计算最终光照
  • 对于hair会使⽤BRDF Importance Sample Weight,采样Probe octahedral map进⾏混合计算最终光照

如果不使用RTX reflection,接下来还会进行indirect specular的解算,最后把indirect diffuse和上一帧的indirect diffuse进行混合,做为最终indirect diffuse输出。这样就完成整个Lumen GI的计算工作。可以看到的是Lumen在整个流程中没有像RTX一样,依赖很重的时频域Filter来压像素间的方差。

Lumen的无限反弹是如何实现的?
MeshCard采样的VoxelLighting是上一帧的数据,这样MeshCards反弹数据会从第二帧开始累积,每帧都会多一次反弹。

官方文档中的SurfaceCache在哪?
MeshCard Lighting + Voxel Lighting大概等同于官方文档中的SurfaceCache。

World Space Probe Cache
Cache方式、作用范围、更新策略类似于Voxel Lighting(3D Clipmap),只是其存储的数据为Radiance/Irradiance且Trace方式和数据格式等同于Screen Space Probe。

参考

1 . Jason Mitchel , Gary McTaggart and Chris Green , Shading in Valve’s Source Engine ,Advanced Real-Time Rendering in 3D Graphics and Games Course – SIGGRAPH 2006

2 . Cyril Crassin1,Fabrice Neyret1,Miguel Sainz,Simon Green4 Elmar Eisemann , Interactive Indirect Illumination Using Voxel Cone Tracing

3 . William Donnelly, Andrew Lauritzen, Variance Shadow Maps

4 . Zander Majercik Jean-Philippe Guertin,Derek Nowrouzezahrai,Morgan McGuire, Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields

5 . Christopher C. Tanner, Christopher J. Migdal, and Michael T. Jones, The Clipmap: A Virtual Mipmap

6 . Thomas Engelhardt, Carsten Dachsbacher, Octahedron Environment Maps

这是侑虎科技第991篇文章,感谢作者Jiff供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859)

作者主页:https://www.zhihu.com/people/jeff-wong-92,再次感谢Jiff的分享,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK