Unity引擎中全局光照中的可见性(Visibility)预计算、存储与使用


1. 可见性(Visibility)在全局光照中的作用

在全局光照(尤其是烘焙光照、间接光照)中,“可见性”指的是某一点(或体素、表面片元)能否直接看到某个光源或其他表面

  • 这决定了光线是否能从光源或其他反射面到达该点。
  • 可见性信息用于计算阴影、间接光照、光子传递等。

2. Unity全局光照系统的可见性预计算

Unity的全局光照系统主要有两种模式:Baked GI(烘焙GI)实时GI(Enlighten)
可见性预计算主要体现在烘焙GI流程中。

2.1 烘焙GI中的可见性预计算

a. 光照贴图(Lightmap)烘焙流程
  1. 场景体素化/采样
    • Unity会将场景划分为一系列采样点(如表面片元、体素、探针点)。
  2. 可见性测试(Visibility Test)
    • 对每个采样点,Unity会发射射线(Ray)到场景中的光源或其他表面,判断是否被遮挡(即是否有物体阻挡)。
    • 这通常用**射线追踪(Ray Tracing)路径追踪(Path Tracing)**算法实现。
    • 结果是一个二值(可见/不可见)或概率(部分可见,考虑软阴影)。
  3. 存储可见性信息
    • 可见性结果不会直接存储为“可见性贴图”,而是用于计算最终的光照值(直接光、间接光、阴影等),这些值被烘焙进Lightmap、Light Probe、Reflection Probe等数据结构中。
b. Light Probe(光照探针)和可见性
  • Light Probe用于动态物体的间接光照采样。
  • 在预计算时,Unity会对每个探针点进行可见性测试,决定其能接收到多少间接光。
c. Shadowmask与可见性
  • Shadowmask模式下,Unity会为每个像素存储来自静态光源的阴影信息(即可见性),用于混合实时和烘焙阴影。

2.2 实时GI(Enlighten)中的可见性

  • Enlighten采用辐射度(Radiosity)方法,预先计算场景的可见性关系(如Patch之间的可见性),以加速实时间接光照的更新。
  • 这些可见性关系以稀疏矩阵等形式存储在Enlighten的数据结构中,运行时用于快速更新光照。

3. 可见性信息的存储

3.1 Lightmap

  • 最终的可见性信息(阴影、间接光)被编码进Lightmap贴图中。
  • Lightmap本身不直接存储“可见性”,而是存储了可见性影响下的光照结果。

3.2 Shadowmask

  • Shadowmask贴图为每个像素存储了静态光源的可见性(0=被遮挡,1=可见,或灰度=部分可见)。

3.3 Probe数据

  • Light Probe和Reflection Probe的数据中包含了可见性影响下的间接光照信息。

3.4 Enlighten内部数据

  • Enlighten会存储Patch之间的可见性矩阵(Visibility Matrix),但这些数据对开发者不可见。

4. 可见性信息的使用

  • 渲染时,Unity会查找当前像素/物体对应的Lightmap、Shadowmask、Probe数据,结合实时光源,决定最终的光照和阴影效果。
  • 动态物体通过采样Light Probe间接获得可见性影响下的间接光照。
  • 混合阴影时,Shadowmask用于区分静态和动态阴影。

5. 总结

  • 可见性预计算是全局光照烘焙的核心步骤,决定了光照和阴影的真实性。
  • 存储:可见性本身不直接暴露为贴图,而是影响了Lightmap、Shadowmask、Probe等数据的内容。
  • 使用:渲染时通过查表、插值等方式获得最终光照结果。

6. 参考资料


下面我将更深入地剖析Unity全局光照中可见性(Visibility)预计算、存储与使用的底层原理和实际流程,并补充一些开发者常见疑问的解答。


一、可见性预计算的底层原理

1. 预计算的目标

  • 加速运行时渲染:通过离线阶段预先计算好场景中各点的可见性关系,避免实时逐像素射线检测。
  • 提升间接光照和阴影的真实性:可见性决定了光线能否到达某点,直接影响光照分布和阴影形状。

2. 预计算的主要方法

  • 射线投射(Ray Casting):对每个采样点,向光源或其他表面发射射线,检测是否被遮挡。
  • Hemisphere Sampling:对每个点的半球空间进行多次采样,统计可见方向的比例(用于软阴影、间接光)。
  • Patch-to-Patch Visibility(Enlighten等辐射度算法):将场景表面划分为Patch,计算Patch之间的可见性(即Form Factor)。

二、可见性数据的存储方式

1. Lightmap/Shadowmask

  • Lightmap:存储了每个表面点的最终光照(已包含可见性影响),通常为RGB贴图。
  • Shadowmask:每个像素为每个静态光源存储一个可见性值(通常为0~1的灰度),用于混合实时和烘焙阴影。

2. Probe数据

  • Light Probe:每个探针点存储了球谐系数(SH),这些系数已包含可见性影响下的间接光照分布。
  • Reflection Probe:存储了环境贴图,间接反映了可见性。

3. Enlighten内部数据

  • Visibility Matrix:Enlighten会为Patch之间存储稀疏的可见性矩阵(Form Factor Matrix),用于实时间接光照的快速更新。
  • 这些数据通常以稀疏矩阵、压缩表等形式存储在Enlighten的专有数据结构中,开发者不可直接访问。

三、可见性数据的使用流程

1. 离线阶段(烘焙时)

  • Unity的烘焙器(如Progressive Lightmapper)会:
    • 对每个采样点/体素/探针点进行可见性测试。
    • 结合光源、表面反射率、可见性,计算直接光、间接光、阴影等。
    • 将结果写入Lightmap、Shadowmask、Probe等数据。

2. 运行时(实时渲染时)

  • 静态物体:直接查表(Lightmap/Shadowmask)获得光照和阴影。
  • 动态物体:通过插值采样Light Probe获得间接光照(已包含可见性影响)。
  • 混合阴影:Shadowmask用于区分静态和动态阴影,动态阴影通过实时Shadow Map补充。

四、开发者常见疑问解答

1. Unity是否存储了“可见性贴图”?

  • Unity不会单独存储“可见性贴图”,而是将可见性影响编码进Lightmap、Shadowmask等贴图中。

2. 能否自定义可见性数据?

  • Unity不开放底层可见性数据的自定义接口,但你可以通过自定义Shader、脚本等方式实现自己的可见性检测(如自定义遮挡剔除、特殊阴影效果)。

3. 可见性预计算对性能的影响?

  • 预计算阶段耗时较长,但极大提升了运行时性能。可见性预计算越精细,烘焙时间越长,但光照和阴影越真实。

4. 可见性与实时阴影的关系?

  • 实时阴影(如Shadow Map)在运行时动态计算可见性,烘焙阴影则在预计算阶段通过可见性测试生成。

五、可见性预计算的实际例子(简化流程)

以一个表面点P为例:

  1. 采样点P
  2. 对每个光源L
    • 从P向L发射射线
    • 如果射线被阻挡,则P对L不可见(阴影)
    • 如果射线未被阻挡,则P对L可见(受光)
  3. 对每个间接光方向
    • 从P向半球空间发射多条射线
    • 统计未被阻挡的比例,决定P的间接光强度
  4. 将结果写入Lightmap/Probe/Shadowmask

六、可见性预计算的优化

  • 加速结构:如BVH、KD-Tree等空间划分结构,加速射线检测。
  • 重要性采样:对重要方向(如主光源方向)增加采样密度。
  • 稀疏存储:只存储有用的可见性关系,减少内存占用。

七、参考论文与资料


我们继续深入,从算法细节、数据结构、开发者可控性、与其他引擎对比等角度,进一步剖析Unity全局光照中可见性(Visibility)的预计算、存储与使用。


八、可见性预计算的算法细节

1. 射线投射与遮挡检测

  • 核心算法:对每个采样点(如Lightmap texel、Probe点、Patch),向光源或半球空间发射射线。
  • 遮挡检测:每条射线与场景几何体(Mesh、Collider)做交点测试,判断是否被遮挡。
  • 加速结构:Unity内部会构建BVH(Bounding Volume Hierarchy)或KD-Tree等空间索引,大幅加速射线与场景的相交测试。

2. Form Factor(形状因子)计算

  • 在Enlighten等辐射度算法中,Patch之间的可见性用Form Factor(Fij)表示,反映了能量从Patch i传递到Patch j的比例。
  • 计算Fij时,需考虑两Patch之间的可见性(即是否有遮挡),通常通过多次射线采样估算。

3. 多重采样与软阴影

  • 为了获得软阴影和更平滑的间接光照,Unity会对每个点进行多重采样(Monte Carlo Integration),统计可见方向的比例。
  • 采样越多,结果越平滑,但烘焙时间也越长。

九、可见性数据的存储结构

1. Lightmap/Shadowmask

  • Lightmap:每个像素存储最终光照(RGB),已包含可见性影响。
  • Shadowmask:每个像素为每个静态光源存储一个可见性值(通常为RGBA通道,支持最多4个光源)。

2. Probe数据

  • Light Probe:每个探针点存储球谐系数(SH),这些系数已包含可见性影响下的间接光分布。
  • Reflection Probe:存储环境贴图,间接反映可见性。

3. Enlighten内部数据

  • Patch可见性矩阵:稀疏存储Patch之间的可见性(Form Factor),用于实时间接光照更新。
  • 这些数据对开发者不可见,仅用于Enlighten内部计算。

十、开发者可控性与调优

1. 可控参数

  • 烘焙分辨率:影响采样点密度,分辨率越高,可见性计算越精细。
  • 采样数:影响每点的射线数量,采样越多,阴影和间接光越平滑。
  • 光照模式:选择Baked、Mixed、Realtime等模式,影响可见性数据的存储和使用方式。
  • 光源类型:不同类型的光源(点光、聚光、平行光)可见性计算方式略有不同。

2. 常见调优建议

  • 减少不必要的静态物体:只对需要烘焙的物体设置为Static,减少可见性计算量。
  • 合理分区:用Lightmap分区(Lightmap Group)控制烘焙范围,提升效率。
  • 遮挡剔除:利用Occlusion Culling减少运行时的可见性计算压力(但与GI烘焙可见性无直接关系)。

十一、与其他引擎的对比

1. Unreal Engine

  • UE4/UE5的Lightmass系统也采用射线投射和体素化进行可见性预计算,存储在Lightmap和Volumetric Lightmap中。
  • UE5的Lumen系统则采用实时全局光照,运行时动态计算可见性(基于Screen Space和体素追踪)。

2. 自研引擎/离线渲染器

  • 通常会将可见性矩阵(Visibility Matrix)或可见性贴图(Visibility Map)单独存储,便于后续多次利用。
  • Unity为节省内存和提升效率,直接将可见性影响编码进最终光照数据。

十二、可见性与运行时动态变化

  • 静态场景:可见性在烘焙时一次性计算,运行时查表即可。
  • 动态物体/光源:Unity通过实时Shadow Map、实时GI补充动态可见性变化,烘焙数据仅适用于静态部分。
  • 混合模式:Shadowmask等模式下,静态阴影用烘焙数据,动态阴影用实时Shadow Map,两者混合。

十三、可见性预计算的局限与未来趋势

  • 局限:烘焙可见性只适用于静态场景,动态变化需实时补充;高分辨率下存储和计算压力大。
  • 趋势:实时全局光照(如UE5 Lumen、RTXGI)正逐步普及,未来可见性更多在运行时动态计算,减少预计算依赖。

十四、伪代码示例(简化版)

for each lightmap_texel in scene:
    for each light_source in scene:
        direction = (light_source.position - texel.position).normalized()
        if not is_occluded(texel.position, direction):
            direct_light += compute_light(light_source, texel)
        else:
            shadow += 1
    for i in range(num_indirect_samples):
        sample_dir = random_hemisphere_direction()
        if not is_occluded(texel.position, sample_dir):
            indirect_light += sample_indirect_light(sample_dir)
    store_in_lightmap(texel, direct_light, indirect_light)

十五、参考资料补充


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值