UnityGI3:光照探针

前置:UnityGI1:光照烘培

一、动态物体间接光漫反射

静态物体的光照可以预处理,而动态物体位置会实时变化,这就不好去做提前光照计算,因此一个方案就是在场景中排满一个一个静态的“小球”,预先计算出这些小球的光照。然后游戏运行时,动态物体就可以去每时每刻寻找各方向上离他最近的几个静态“小球”,然后对这些“小球”的光照结果进行插值。用这种方法就可以对动态物体打上间接光漫反射,这个思路和分块打表算法比较相像

间接光高光(镜面反射)无法用这种方法计算得到,这个需要去考虑 IBL

图片中一个一个黄色的“小球”就是光照探针,可以通过下面的步骤创建并修改:

  • 尽量避免出现无意义的光照探针,例如布在非透明的物体里面,又或者永远无法被看到的地面之下等等
  • 注意性价比,尽可能以更少的光照探针布满整个场景不遗漏(一并情况下使用代码/工具布置)
  • 光照探针并需要有空间感,也就是说要是立体的

1.1 光照探针四面体区域

光照探针组(LightProbeGroup)将空间划分成多个四面体区域,每个四面体(锥体)的四个角都对应着四个光照探针:

场景中的动态物体位置变化时会去判断它的中心被包括在了哪个四面体之内,并拿到这四个光照探针数据参与计算,如果这个物体过大就有可能需要拆分考虑,或者使用代理体

扫描二维码关注公众号,回复: 14742748 查看本文章

二、球谐光照

按照上面布置完光照探针,并生成 lightmap 后,就可以在游戏中看到效果:动态物体也有了正确的间接光照,几乎不需要代码因为 Untiy3D 已经帮我们算好了:

#if defined(LIGHTMAP_ON)
    float3 indirectDiffuse = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lightmapUV));
    #if defined(DIRLIGHTMAP_COMBINED)
        float4 lightmapDirection = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, i.lightmapUV);
        indirectDiffuse = DecodeDirectionalLightmap(indirectDiffuse, lightmapDirection, normal);
    #endif
#else
    float3 indirectDiffuse = max(0, ShadeSH9(float4(normal, 1)));
#endif

主要代码就在 ShadeSH9 方法当中,其实计算插值当然不是难点,难点在于如果存储每个探针的球面光照,要知道设计积分的东西都不会好解决,因此想要用尽可能快又省的方法去获得球面光照信息也非常的困难,这也就是球谐光照的核心

球谐光照的算法非常的复杂,甚至超过了之前 IBL 的难度,有兴趣的话推荐这一系列的文章:球谐光照与PRT学习笔记,目前只需要只需要知道的是,它可以帮我们重建环境光

2.1 注意 MeshRendere 组件的设置

如果 MeshRenderer 组件中的 LightProbes 设置为 Off,我们就无法拿到对应球谐函数的参数信息,这也可以在 FrameDebug 中确认

参考文章:

猜你喜欢

转载自blog.csdn.net/Jaihk662/article/details/117161314