本节实现Unity日夜循环天空球♥(´∀` )人
Unity中有两类skybox,一类是贴图类(6 sided, cubemap, panoramic),一类是procedural类,本文实现的就是procedural天空盒(其实就是100%纯手写天空盒= - =)
本文中的天空盒主要参考Minionsart的分享(日常表白→
Making a Stylized Skybox Shader www.patreon.com
进行制作,根据需求有魔改,并关联时间系统,repo在此(」・ω・)」→
llapuras/UnityProceduralSkybox github.com
确保摄像机中设定Clear Flags
为skybox
模式,然后在随便哪个物体下挂上skybox组件,添加使用了skybox shader的材质。
Unity内置变量_WorldSpaceLightPos0存储了directional light的方向。这样就可以通过改变directional light的旋转使天空球旋转,形成日夜交替效果。
首先,光指向的正反方向就是我们绘制日月的地方!
计算uv坐标上天空球上的坐标与_WorldSpaceLightPos0间的距离,根据距离返这个数值绘制,得到的是一个中心到边缘亮度递减的圆形效果(距离方向坐标越近数值越小),可以用saturate
对球形区域内的颜色再处理一次,将sphere
乘上一个大点的数,返回数都为1,即可获得清晰边界。
月亮的绘制同理,月食/日食的效果可以通过两个球实现——
一共需要黑夜和白天两种天色。
使用lerp函数形成颜色渐变,根据uv坐标判定非日夜交替时的天色,根据saturate函数和世界坐标y值判定日夜交替。
星空和云朵使用noise贴图+cutoff制作。
在“天空”贴贴图不能直接使用uv坐标,uv坐标下就是emmm感觉贴在一个巨大的球形上,这里星空和云彩只会出现在“天上”,到画面上的表现即只会出现在屏幕的上半部分。所以这里使用世界坐标实现,将贴图显示在xz平面,并用y轴坐标控制显示范围在上半部分。
对天空贴图使用的坐标处理如下。使用clamp控制世界坐标y值在0~最大值间(不知道咋获得y轴最大值但是大于10000的时候没差别了所以就用这个数了...然后是熟悉的cutoff操作,使用step设置一个cutoff阈值,凸显亮色部分。关键代码如下:
同理加上云朵(跟星星的一模一样只是换了张贴图啦),效果如下:
现在的云朵只是一张单层贴图,显得很没层次感而且可以看出明显贴图图案。接下来通过添加噪音贴图丰富云朵形状。
这里添加了两张贴图,一张用来和原贴图叠加丰富云朵的图案,一张用来制造更明显的扭曲效果。
现在的云朵边缘太过清晰,接下来让云显得更加蓬松,添加一个参数,在一个cutoff区间内平滑取值,使云在边缘处模糊一点。
这样显得更接近真实一点了。
把之前的那层cloud复制粘贴再加一层,赋一个不一样的cutoff范围效果就很好了,浓密或稀疏的云层都可以做出来,多层也方便之后添加不同色彩。
给上下两层云赋予不同的颜色,这里根据白天黑夜加了两套颜色,然后根据日夜交替替换云朵颜色。
星空不同于云的地方在于它只在夜晚出现。用saturate和世界坐标y轴返回1或者0作为乘数即可。
目前的叠加星星和云的效果如下,星星看上去位于云前。
判定一下只在没有云的地方画星星即可。
最后一步,添加地平线。根据uv.y可以绘制出水平线。然后依然是根据日夜判定不同的地平线颜色。地平线还有个功能就是模糊上下边界让云和地的边界看起来不那么明显,这里多画一道线赋上亮色其遮挡作用。
功能如下:
可选是否与现实时间同步
可选从游戏开始时计时,可自定义游戏中时间与现实时间兑换,支持时间暂停
结束了!
Minionsart的梦幻天空球
ps: 感觉step,smoothstep,saturate,clamp和lerp这五个函数承包了shader里的画面绘制呢...
声明:发布此文是出于传递更多知识以供交流学习之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与我们联系,我们将及时更正、删除,谢谢。
作者:alfxian
原文:https://zhuanlan.zhihu.com/p/197107007
More:【微信公众号】 u3dnotes
本文分享自微信公众号 - Unity3D游戏开发精华教程干货(u3dnotes)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。