Unity Shader如何实现基于光照图的简易昼夜变化

这篇文章主要介绍Unity Shader如何实现基于光照图的简易昼夜变化,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

Unity Shader如何实现基于光照图的简易昼夜变化

Unity Shader如何实现基于光照图的简易昼夜变化

好,还是先上一张最终效果的动态图,变化过程有点卡顿,是因为GIF压缩抽帧导致的,实际没有这个问题。不过应该可以表现出一天的时段变化了。

可能有的朋友发现问题了,哎呀,怎么影子木有变化.....是的,变不了,因为我们这是基于烘焙过得光照图做的变化,所以,阴影是固定的。如果我们有实时光,就不是这个教程所涉及的了,直接调整方向光就可以了。

这个方案最早是基于我以前做的一个MMO项目,在几年前,实时光并不现实(现在对于很多项目来说也不现实),光线几乎都是由烘焙后的光照图来决定。但是我们在做一些剧情动画时,又需要一些昼夜变化,通常这些变化还是很快速的。譬如,剧情中写道“就这么,一夜过去了.....”,如果这时候能加一个快速变化的光照系统,还是很有画面感的,对吧?然后,就有了这个暴力简陋版昼夜系统。

为什么说它暴力简陋版呢?因为它真的很暴力,我们最终想到的性能最优办法,就是直接修改所有材质的颜色,当然最终如果实现出好的效果的话,还是需要很多方面考量的,这里只提供一个简单的解题思路。

修改材质的颜色,总不能让我们写代码去挨个遍历场景中所有的材质来修改颜色吧,累死了,而且一想就知道性能堪忧。好在Unity为我们提供了一个便利的修改方法,就是全局修改shader属性。我们来看看官方的这个API,修改全局shader颜色的,(Shader.SetGlobalColor)。

Unity Shader如何实现基于光照图的简易昼夜变化

用起来很简单,这个API可以直接的修改场景里所有叫这个名字的属性,前提是这个属性没有被暴露在编辑器里,也就是说你只能在Pass通道里声明它,如果你在属性块里声明了它,对不起,这个API无效,它会优先使用属性块里定义的参数。

熟悉了这个API,接下来就简单了,我们只需要在每一个需要变化的shader里,加入一个天光的颜色属性,直接乘上去就行了,最后再全局修改这个颜色。看看下面的shader重点代码,多出来的代码,用手指头都能数的过来。

    //这里就是需要修改的全局颜色---天光颜色    fixed4 _SkyColor;
   void surf (Input IN, inout SurfaceOutputStandard o) {      // 直接乘上去就好了      fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color*_SkyColor;

好,还没完,重点是我们需要用一个脚本来控制修改这个颜色。

这里我写了四个时段的颜色,分别是,早晨,中午,下午,晚上(事实上如果不计较细节,早晨和中午可以合并)。并把这四个颜色暴露出来,供场景人员修改。还有一个一整天循环一次所需要的时间,单位为秒。

Unity Shader如何实现基于光照图的简易昼夜变化

接下来就是在代码里去推进时间了,下面是代码,还是比较简单的,每一行我都写了详细注释,但我代码写的并不好,请谅解。

public class DayAndNightManager : MonoBehaviour{    public float oneDayTime = 10; //一整天循环一次的时间,这里默认的十秒    public Color morningColor = Color.white; //早晨颜色    public Color noonColor = Color.white; //中午颜色    public Color afterNoonColor = Color.white; //傍晚颜色    public Color nightColor = Color.white; //晚上颜色
   private Color[] colors;//所用的所有时间段的颜色    private Color currentColor;//当前颜色    private float dayTimer; //时间    // Use this for initialization    void Start () {        //把所有时段的颜色收集起来,这里多了一个,是因为整个是一个循环,结束的时候要回到凌晨时段,所以最后一个颜色是早晨的颜色        colors = new Color[5];        colors[0] = morningColor;        colors[1] = noonColor;        colors[2] = afterNoonColor;        colors[3] = nightColor;        colors[4] = morningColor;        //初始化        Shader.SetGlobalColor("_SkyColor",Color.white);        currentColor = morningColor;        dayTimer = 0;    }
   // Update is called once per frame    void Update()    {        //时间开始推进,乘以4是因为我们有四个时段,这样再乘以后面的一整天时间才是准确的。        dayTimer += Time.deltaTime*4/oneDayTime;        //一个循环结束了,重新开始        if (dayTimer >= (float)colors.Length - 1)        {            dayTimer = 0;        }        //采样两个颜色,第一个是即将过去的时间颜色,第二个是即将到来的时间颜色,我们通过两个数学方法向下和向上取整。        Color color01 = colors[Mathf.FloorToInt(dayTimer)];        Color color02 = colors[Mathf.CeilToInt(dayTimer)];        //两个颜色的占比,我们通过取时间的小数部分,就可以了。        float weight = dayTimer - Mathf.FloorToInt(dayTimer);        //利用权重来对颜色进行融合        currentColor = Color.Lerp(color01, color02, weight);        //修改全局颜色,_SkyColor已经写到所有的shader里了        Shader.SetGlobalColor("_SkyColor", currentColor);        //修改全局时间,这个主要是控制天空盒的贴图融合        Shader.SetGlobalFloat("_DayAndNightChange", dayTimer);


   }

代码的最后一行是修改天空盒的贴图融合,是的,光变了,天空盒怎么能不变,所以我用了四张天空盒的贴图来做过度,听着内存有点吃紧是吧?如果想节约的话,可以用一张贴图来做颜色变化就可以了,但是效果可能没有这样好一点,美术同学可以把四张图都给你画的很美吆。

至于天空盒的shader,也很简单,我使用了一个float属性来融合四张贴图,重点代码如下。

    //重点是这个变量,通过全局修改这个变量的参数来对四个时段的贴图采样,并融合。    //这个变量的范围与脚本的时间一致,都是0-4循环,最后一个时段与第一个一样,都是凌晨    float _DayAndNightChange;
   half4 frag (v2f i) : SV_Target    {      //基本就是一些融合算法,先利用时间来算出每个贴图的颜色占比,然后统一加到一起。      //这只是计算了天空盒的一面,后面的Pass算法相同     half4 col01 = skybox_frag(i,_Tex01, _Tex01_HDR)*(saturate(1- _DayAndNightChange));     half4 col02 = (skybox_frag(i,_Tex02, _Tex02_HDR)*(saturate(2- _DayAndNightChange)))-(skybox_frag(i,_Tex02, _Tex02_HDR)*(saturate(1- _DayAndNightChange)));     half4 col03 = (skybox_frag(i,_Tex03, _Tex03_HDR)*(saturate(3- _DayAndNightChange)))-(skybox_frag(i,_Tex03, _Tex03_HDR)*(saturate(2- _DayAndNightChange)));     half4 col04 = (skybox_frag(i,_Tex04, _Tex04_HDR)*(saturate(4- _DayAndNightChange)))-(skybox_frag(i,_Tex04, _Tex04_HDR)*(saturate(3- _DayAndNightChange)));     half4 col05 = skybox_frag(i,_Tex01, _Tex01_HDR)*(saturate(_DayAndNightChange -3));     half4 c = col01 +col02+col03+col04+col05;     return c;     }

代码有些冗余,有很大的修改空间........但是这样看着比较清楚,其实就是利用_DayAndNightChange这个属性对每张贴图进行采样,然后融合。

好,这里我只是实现了一个简易版的效果,如果想在项目中使用,并实现好的效果,还有很多需要考虑的,譬如,全局修改雾的颜色,还有晚上开启一些灯光效果,火把效果,还可以写一个方法,用于跳转到某个时间。还有如果这种属性多了的话,最好重新修改一下编辑窗口,否则美术同学看着会很乱。

至于性能方面,这种系统还是很好控制的,个人推荐时间的变化不要像我写的这样每帧一次,可以控制一下,譬如0.1s一次。

上面这个简单工程我也附在这里,如果有什么不对的地方,望指正。

对了,这个工程在打开的时候可能场景是黑的,运行一次就好了。原因是,全局修改的变量,也就是那个_SkyColor,在没有赋值的时候,是黑色的。后期这个东西可能需要改一下,

以上是“Unity Shader如何实现基于光照图的简易昼夜变化”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程之家行业资讯频道!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍了Unity游戏开发中外观模式是什么意思,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章主要介绍Unity中地面检测方案的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1.普通射线在角色坐标(一般是脚底)...
这篇文章主要介绍了Unity游戏开发中如何消除不想要的黄色警告,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带...
这篇文章主要介绍了Unity中有多少种渲染队列,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解
这篇文章主要介绍Unity中如何实现Texture,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!了解Texture2D 如上图,Texture2D是一张
小编给大家分享一下Unity中DOTS要实现的特点有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让...
这篇文章给大家分享的是有关unity中如何实现UGUI遮罩流光特效的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。下面是核心shader:Sh...
这篇文章主要为大家展示了“Unity中如何实现3D坐标转换UGUI坐标”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下...
这篇文章主要介绍了Unity游戏开发中设计模式的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章主要介绍了Unity中如何实现仿真丝袜渲染,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了...
这篇文章给大家分享的是有关Unity插件OVRLipSync有什么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。项目需要接入对话口型动...
这篇文章主要介绍了Unity性能优化之DrawCall的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章给大家分享的是有关Unity给力插件之Final IK怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。这插件有什么用:一般游...
这篇文章给大家分享的是有关Unity中如何内嵌网页插件UniWebView的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、常见Unity中内...
小编给大家分享一下Unity如何做流体物理的几个轮子,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让...
小编给大家分享一下Unity中Lod和Occlusion Culling的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收...
这篇文章将为大家详细讲解有关Unity中LineRenderer与TrailRenderer有什么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获...
这篇文章主要介绍了Unity中coroutine问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起...
这篇文章将为大家详细讲解有关unity中spine怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。骨骼动画首先我们来看到...
这篇文章主要为大家展示了“Unity Shader后处理中如何实现简单均值模糊”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学...