Unity(四十五):光照烘焙反射探头

Posted Prosper Lee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity(四十五):光照烘焙反射探头相关的知识,希望对你有一定的参考价值。

Lightmap

原理:

将场景中的灯光与物体产生的光照与阴影信息烘焙在一张或者多张Lightmap贴图中,这些物体将不再参与实时光照计算,从而减少了大量的性能开销。

缺点:

参与烘焙计算的对象在游戏过程中不能发生移动。

通常会将物体对象分为两类:

  1. 可发生位移变化的:实时光照计算

  2. 不可发生位移变化的:预先烘焙Lightmap

Light组件Mode属性

  • Realtime 实时光照
  • Mixed 实时光和烘焙光共存 (推荐采用)
  • Baked 烘焙光照

烘焙展示

步骤

生成光照烘焙贴图


获取子游戏对象的光照烘焙参数

将光照烘焙下来的参数存储到脚本中以便运行时使用

注意:保存好数据后清空 Lighting Data Asset

using System;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 烘焙贴图
/// </summary>
[Serializable]
public class BakedTexture

    public Texture2D lightmapDir;
    public Texture2D lightmapColor;
    public Texture2D shadowMask;


public class ChangeLightmapData : MonoBehaviour


    [Header("Contribute GI 静态游戏对象")]
    public GameObject staticObj;

    [Header("灯光组件")]
    public Light lightComponent;

    [Header("Mixed 烘焙光照贴图")]
    public List<BakedTexture> mixedLightmaps;

    [Header("Baked 烘焙光照贴图")]
    public List<BakedTexture> bakedLightmaps;

    private void Awake()
    
        SwitchLight(1);
        SwitchLightmapData(0);
    

    /// <summary>
    /// 开灯/关灯
    /// </summary>
    /// <param name="index">索引</param>
    public void SwitchLight(int index)
    
        lightComponent.enabled = index != 0;
    

    /// <summary>
    /// 切换烘焙贴图
    /// </summary>
    /// <param name="index">索引</param>
    public void SwitchLightmapData(int index)
    
        List<BakedTexture> lightmaps = new List<BakedTexture>();
        switch (index)
        
            case 0:
                LightmapSettings.lightmaps = null;
                return;
            case 1:
                lightmaps = mixedLightmaps;
                break;
            case 2:
                lightmaps = bakedLightmaps;
                break;
        
        LightmapData[] data = new LightmapData[lightmaps.Count];
        for (int i = 0; i < lightmaps.Count; i++)
        
            data[i] = new LightmapData()
            
                lightmapDir = lightmaps[i].lightmapDir,
                lightmapColor = lightmaps[i].lightmapColor,
                shadowMask = lightmaps[i].shadowMask,
            ;
        
        LightmapSettings.lightmaps = data;

        SetStaticGameObjectLightmapData();
    

    /// <summary>
    /// 配置静态对象组下子游戏对象的烘焙贴图数据
    /// </summary>
    private void SetStaticGameObjectLightmapData()
    
        GameObjectLightmapData gameObjectLightmapData = staticObj.GetComponent<GameObjectLightmapData>();
        MeshRenderer[] meshRenderers = staticObj.GetComponentsInChildren<MeshRenderer>();
        for (int i = 0; i < meshRenderers.Length; i++)
        
            meshRenderers[i].lightmapIndex = gameObjectLightmapData.lightmapParams[i].lightmapIndex;
            meshRenderers[i].lightmapScaleOffset = gameObjectLightmapData.lightmapParams[i].lightmapScaleOffset;
        
    


运行项目配置光照贴图数据

参数间关系如下

using System;
using System.Collections.Generic;
using UnityEngine;

[Serializable]
public class LightmapParams

    public int lightmapIndex;
    public Vector4 lightmapScaleOffset;


/// <summary>
/// 烘焙完成后存储每个子游戏对象烘焙贴图数据
/// </summary>
public class GameObjectLightmapData : MonoBehaviour

    public List<LightmapParams> lightmapParams = new List<LightmapParams>();

    private void Reset()
    
        GetStaticGameObjectLightmapData();
    

    private void GetStaticGameObjectLightmapData()
    
        MeshRenderer[] meshRenderer = gameObject.GetComponentsInChildren<MeshRenderer>();
        foreach (MeshRenderer item in meshRenderer)
        
            lightmapParams.Add(new LightmapParams()
            
                lightmapIndex = item.lightmapIndex,
                lightmapScaleOffset = item.lightmapScaleOffset
            );
        
    

反射探头

效果

配置游戏对象静态属性

为要实现反射的游戏对象绑定材质组件

Unity高级开发-光照系统(三)-使用Unity的Progressive工具去正确的烘焙光照

参考技术A 1-烘培的代价是非常高的
2-烘培贴图的数量和体积非常的大,因为它是RGB通道的一些彩色图片,所以是无法改变的。
3-通过格式压缩,但压缩会出现质量下降的情况。贴图加载会占用大量的显存。

我们自动生成的一些UV可以使用Unity的功能,在物体上有UV Charting Control,进行动态合并。在合并完成后,我们进行预计算,看看合并上有没有问题。
合并UV的时候可能会出现扭曲现象,这种扭曲现象在烘焙Lightmap时是非常有问题的。

UV Charts等于6的情况下,如果Box分成左边是比较合理的,右边这么分在Enlighten的计算量最起码要增加3倍。

常见的物体Cluster Resolution 参考(每单元大小):

小火车做了一个Light Probe Proxy Volume,这样就可以控制接受间接光的情况。注意这种方式目前不支持移动平台
项目中的整体地面,都是使用的Blend Probes模式的混合,比较小或者不显眼的物体,并非游戏重要物体的都可以使用Blend Probes进行照明,我们需要勾选Static类型,它们一定在Static批次中,后面把它Lightmap Static去掉就可以了,去掉后就不会生成Lightmap,但是会接收Light Probe的影响。

如上图所示,在整个光照当中,我们加了一些面光源,这是为了提高场景的窗户透光的光亮。如果不加,就没法按窗户形成面光源,向内部进行照明的。
需要注意,面光源在移动平台上,如果不是HDRP的话,就只支持静态的,只支持烘培,不是烘培的模型它是不支持的。
下图是场景的光照贴图大概是这样的,比较符合白天的光照效果。

我们可以看看它的设置。
首先Procedural Skybox在这里加进来。在Enlighten当中,千万不要使用渐变和颜色进行烘焙,两者烘焙出来的东西会比较风格化,并不写实。有很多人选择用某个颜色烘渐变,但效果会非常不理想,所以一般选择Skybox进行烘焙,而Skybox一般使用Procedural Skybox。
烘焙完后,再替换为自己场景的风格化Skybox作为最终显示效果。Procedural Skybox是仅用于烘焙的,不是用于制作最终的Skybox效果。
我们再举一个简单的例子。如果要形成一个特别颓废和压抑的环境,我们可以将大气密度提到很高,然后将染色降一下,或者偏向一个色彩。
我们可以将整个曝光度调低,把大气密度调高,实现让人很压抑的环境,这种环境烘焙出来的Lightmap比较接近于比较邪恶的地方,从而获得更加压抑的光照效果。

尤其是一些非常小的物体,如果想要表现出好的效果,一定要对Lightmap大小进行放大。例如:铅笔在Scale In Lightmap里要放大一倍,不然烘出来基本上没效果。但对于有的物体,我们要保证统一性,如果能保证统一性,有的地方会出现一些色斑。
在示例场景中,我们优化掉了一部分的东西,整个Lightmap的照明还可以,但是你会看到这些东西都浮起来了,靠屏幕空间的AO是控制不住的,效果会产生大量的损失。所以这样的东西只在室外有用,室内的话是不建议这么用。
Enlighten烘焙在示例场景中的效率,代价是非常大的,因为场景中的物体非常的多,它的UV Charts基本上没办法看到,非常碎,所以烘焙时间也非常长。
在小火车的场景中,使用Enlighten大概烘焙4分钟。在这个教室场景,因为物体非常多而杂,大概是小火车场景的5倍左右时间,大概20分钟。
使用Progressive烘培则很稳定,它只看场景有多大的精度,不管场景有多少物体,这就是Progressive和Enlighten之间的差异。

以上是关于Unity(四十五):光照烘焙反射探头的主要内容,如果未能解决你的问题,请参考以下文章

Unity高级开发-光照系统(三)-使用Unity的Progressive工具去正确的烘焙光照

转载“最简单的” Unity 光照探头总结

Unity基础(四)渲染烘焙Lightmap光照贴图(未完)

Unity-LightMap

Unity教程||Unity 渐进式光照贴图烘焙详解

Unity5中的软阴影烘焙