千家信息网

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

发表于:2024-10-01 作者:千家信息网编辑
千家信息网最后更新 2024年10月01日,这篇文章主要介绍Unity Shader如何实现基于光照图的简易昼夜变化,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!好,还是先上一张最终效果的动态图,变化过程有点卡顿,是因为
千家信息网最后更新 2024年10月01日Unity Shader如何实现基于光照图的简易昼夜变化

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


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

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

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

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

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

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

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

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

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

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

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

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如何实现基于光照图的简易昼夜变化"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!

颜色 时间 变化 代码 全局 属性 效果 时段 就是 贴图 还是 光照 天空 循环 昼夜 变量 场景 重点 控制 简易 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 社交网络安全调查报告总结 5g互联网科技产品 以色列网络安全部队 电信网络安全工程师答辩 一个文件管理系统的数据库设计 护苗网络安全课昆山 电脑找不到dns服务器 数字化网络技术监管大屏幕 网络安全手抄报图片8年级 山东蓝狐网络技术有限公司 数据库登录了怎么写代码 广西远程服务器租赁收费标准 数据库网站检索界面消失 四川和江苏的网络安全 烟台嘉乔网络技术有限公司 网络安全考公工资多少 网络技术工作者考试 网络安全法新司法解释 软件开发流程有哪几个步骤 布卡云电脑连接不到服务器 运用网络技术的论文 企业软件开发测试程序 大兴区智能网络技术价格行情 数据库表的默认值 杭州计算机网络安全培训机构 洋河网络安全宣传周 嘉定区企业金融网络技术服务热线 我们的节目网络安全怎么做 为什么阴阳师老是连接服务器失败 华为生产什么5g服务器
0