美文网首页unity
[Unity 3d] 实现黑夜/白天一键切换全攻略

[Unity 3d] 实现黑夜/白天一键切换全攻略

作者: 雨落随风 | 来源:发表于2019-09-15 23:55 被阅读0次

在本文,笔者讲简单的讲一讲怎么在 Unity 中实现黑夜白天的一键切换。

演示:

场景中的灯效,除了直射光其他均是烘焙出来的。


色彩太丰富,实在不敢录太长时间

原理:

如果想要实现上面的这个黑夜白天切换效果,控制好以下几点就行了:

  1. 保证烘焙黑夜和白天光照贴图使用的是同一个场景(Ctrl+D挺好用)。
  2. 动态切换 黑夜和白天的 光照贴图设置(LightmapSettings)。
  3. 动态修改天空盒白天和黑夜对应的天空盒,或者像上面演示的那样:仅仅修改天空盒曝光值。
  4. 修改直射光的强度(如果有必要,可以修改直射光的角度)。
  5. 如果像演示中的镜面建筑,加了光照探针(ReflectionProbe)的需要指定对应的烘焙OK的贴图。
  6. 关于黑夜白天差异性的游戏对象:
    • 不参与烘焙的,比如上面的效果晚上多加的 Lens 辉光,直接白天显示隐藏晚上显示即可。
    • 参与烘焙的,可以直接使用显示 / 隐藏操作。
    • 参与烘焙的,也可以存为预制体动态加载,但该方案要写点代码保证游戏对象上烘焙的光照信息能被加载出来。

示例:

using System.Linq;
using UnityEngine;
using DG.Tweening;

public class TestSwitchBakedLightMap : MonoBehaviour
{
    [Header("Common Configuration and Component ")]
    public ReflectionProbe reflectionProbe;
    public Light directLight;
    public GameObject effectLights; //晚上要打灯,白天不打灯

    [Header("Configuration and Component For Day"), Space(10)]
    public LightDataConfiguration dayConfig;
    public Cubemap dayReflect;
    public float daySkyboxExposure = 1f;
    public float directLightDayIntensity = 1;
    public float dayLightIntensityMultiplier = 1;

    [Header("Configuration and Component For Night"), Space(10)]
    public LightDataConfiguration nightConfig;
    public Cubemap nightReflect;
    public float nightSkyboxExposure = 0.2f;
    public float directLightNightIntensity = 0.2f;
    public float nightLightIntensityMultiplier = 0.3f;

    // private fields
    LightmapData[] day;
    LightmapData[] night;
    bool isDay = true;

    private void Start()
    {
        night = nightConfig.Lightmaps
            .Select(x => new LightmapData() { lightmapColor = x.lightmapColor, shadowMask = x.shadowMask })
            .ToArray();
        day = dayConfig.Lightmaps
            .Select(x => new LightmapData() { lightmapColor = x.lightmapColor, shadowMask = x.shadowMask })
            .ToArray();
        RenderSettings.skybox.SetFloat("_Exposure", daySkyboxExposure);
        reflectionProbe.customBakedTexture = dayReflect;
    }

    void OnGUI()
    { 
        if (GUILayout.Button(isDay ? "To Night" : "To Day"))
        {
            SwithDayAndNight();
        }
    }

    public void SwithDayAndNight()
    {
        if (!isDay)
        {
            // 切换为白天的配置
            LightmapSettings.lightmaps = day;
            directLight.DOIntensity(directLightDayIntensity, 0.5f);
            DOTween.To(()=> RenderSettings.ambientIntensity, y=> { RenderSettings.ambientIntensity = y; },dayLightIntensityMultiplier,0.5f);
            RenderSettings.skybox.DOFloat(daySkyboxExposure, "_Exposure", 0.5f);
            effectLights.SetActive(false);
            reflectionProbe.mode = UnityEngine.Rendering.ReflectionProbeMode.Custom;
            reflectionProbe.customBakedTexture = dayReflect;
        }
        else
        {
            // 切换为晚上的配置
            LightmapSettings.lightmaps = night;
            directLight.DOIntensity(directLightNightIntensity, 0.5f);
            DOTween.To(()=> RenderSettings.ambientIntensity, y=> { RenderSettings.ambientIntensity = y; },nightLightIntensityMultiplier,0.5f);
            RenderSettings.skybox.DOFloat(nightSkyboxExposure, "_Exposure", 0.5f);
            effectLights.SetActive(true);
            reflectionProbe.customBakedTexture = nightReflect;
        }
        isDay = !isDay;
    }
}

Tips:

  • 仅仅是将原理中提到的几点找到对应的 API 通过代码动态修改罢了,仅供熟悉API.
  • 使用了 DoTween 的非扩展方法形式的缓动,可以熟悉下。
  • 使用了 DoTween 的扩展方法形式对天空盒(材质球)的曝光值进行了缓动。
  • 使用了 ScriptableObject 分别保存的黑夜/白天的光照贴图设置信息,只需要 lightmapColor 和 shadowMask 两组信息,使用 ScriptableObject 在本示例中的好处可要好好体会体会哈~
  • 演示中没有出现原理中第六条第三点提到的问题,所以示例代码没做演示。

扩展阅读:

  1. Unity5.x场景优化之动态设置光照贴图lightmap - yuyingwin的专栏 - CSDN博客
    ↑怎么让动态加载的游戏对象实例化后自动加载光照贴图效果:↑

  2. [Unity3D]Lightmapping使用及动态加载lightmap方案 - bread's code - CSDN博客
    ↑更多关于光照贴图+光照探针的参考资料↑

转载请注明出处,谢谢!

相关文章

网友评论

    本文标题:[Unity 3d] 实现黑夜/白天一键切换全攻略

    本文链接:https://www.haomeiwen.com/subject/wcimyctx.html