Unity Shader实现2D天空日夜循环

话不多说直接上脚本,其实逻辑我理不清了,反正瞎调的达到效果就好了。

Shader脚本:

Shader "GreatBug/SkySphere"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "Black" {}
        
//        _SunPos("SunPos", Vector) = (1,1,0,0)
        _SunRadius ("SunRadius", Range(0, 1)) = 1
        _SunIntensity ("SunIntensity", Range(0, 1)) = 1
//        _SunObscure("SunObscure", Range(0, 1)) = 1
    	
        _SunColor("SunColor", Color) = (1.0, 1.0, 1.0, 1.0)
        _SunHalo("SunHalo", Color) = (1.0, 1.0, 1.0, 1.0)
        _SunHaloField("SunHaloField", Range(0, 1)) = 1
    	
        _MoonColor("MoonColor", Color) = (1.0, 1.0, 1.0, 1.0)
    	_MoonOffset("MoonOffset", Range(0, 1)) = 1
    	_MoonObscure("MoonObscure", Range(0, 1)) = 1
        
        _DayTopColor("DayTopColor", Color) = (1.0, 1.0, 1.0, 1.0)
        _DayBottomColor("DayBottomColor", Color) = (1.0, 1.0, 1.0, 1.0)
        _NightTopColor("NightTopColor", Color) = (1.0, 1.0, 1.0, 1.0)
        _NightBottomColor("NightBottomColor", Color) = (1.0, 1.0, 1.0, 1.0)
        
        _HorizonIntensity("HorizonIntensity", float) = 1
 		_HorizonColor("HorizonColor", Color) = (1.0, 1.0, 1.0, 1.0)
        _LightPointIntensity("LightPointIntensity", Range(0, 1)) = 1
    	_HorizonLength("HorizonLength", Range(0, 1)) = 1
//    	_SunAngle("SunAngle", Range(0, 360)) = 1
    }
    SubShader
    {
        
        LOD 100
//        Cull Front // 只剔除正面
        
        Pass
        {
        	Tags { "LightMode" = "UniversalForward"}
 			HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
            };

            struct v2f
            {
            	float2 sky_uv : TEXCOORD2;
                float2 tex_uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 normal : NORMAL;
                float3 worldPos : TEXCOORD1;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
 			
            float2 _SunPos;
            float _SunRadius;
 			float _SunIntensity;
 			float4 _SunColor;
 			float4 _SunHalo;
 			float _SunHaloField;
 			// float _SunObscure;
 			float4 _MoonColor;
 			float _MoonOffset;
 			float _MoonObscure;

            float4 _DayTopColor;
            float4 _DayBottomColor;
            float4 _NightTopColor;
            float4 _NightBottomColor;

 			float _HorizonIntensity;
 			float4 _HorizonColor;
 			float _LightPointIntensity;
 			float _HorizonLength;

 			// float _SunAngle;
 			// float _DayTime;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = TransformObjectToHClip(v.vertex);
                o.tex_uv = TRANSFORM_TEX(v.uv, _MainTex);
            	o.sky_uv = v.uv;
                o.normal = normalize(TransformObjectToWorldNormal(v.normal));
                o.worldPos = TransformObjectToWorld(v.vertex.xyz);
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {
            	//Directional Light
                Light light = GetMainLight();
				float3 lightDir = normalize(light.direction);
            	
            	//太阳和月亮位置
                _SunPos.y = (lightDir.y + 1) / 2;
            	_SunPos.x = (lightDir.x + 1) / 2;
                float2 moonPos = float2(1 - _SunPos.x,1 - _SunPos.y);
                
                // 白天和晚上的颜色
                float3 gradientDay = lerp(_DayBottomColor, _DayTopColor, saturate(i.sky_uv.y));
                float3 gradientNight = lerp(_NightBottomColor, _NightTopColor, saturate(i.sky_uv.y));

            	//混合后的底色
                float temp = smoothstep(-1,1,lightDir.y);
                float3 skyGradients = lerp(gradientNight, gradientDay,saturate(temp));

            	//天际线
                float3 horizon = abs((i.sky_uv.y * (_HorizonIntensity )) - (_HorizonIntensity/2 ));
            	float3 absLightDir = abs(lightDir.y);
                temp = smoothstep(0.8,0,absLightDir);//越是中午 值越小
            	
                float lightPoint = 1 - smoothstep(_LightPointIntensity,0,abs(i.sky_uv.x - _SunPos.x));//太阳位置的天际线加强,其他位置压低
            	
            	//这里的步骤和数值都是在特定属性值下测试调整的,以达到满意的过度效果,实际请根据需要修改微调
            	horizon = saturate(1 - horizon - (1 - _HorizonLength)* lightPoint);
                horizon = pow(horizon,2) * 1.5* (_HorizonColor * saturate(temp));
                horizon = smoothstep(0,1 ,horizon );
				horizon = saturate(lerp(horizon, 0,(_SunPos.y - 0.5)*10));

            	//太阳
                float sunDis = distance(i.sky_uv, _SunPos);
                float3 sun = 1 - (sunDis / _SunRadius * 10);
            	//模糊太阳 中午越模糊
                sun = saturate(sun * pow(temp,2)*10) * _SunColor.xyz;
				//太阳辐射强度
            	float sunIntensity = smoothstep(0.5, 0.6,_SunPos.y) * _SunIntensity;
            	float temp2 = 1.0 - exp(-temp * 5.0);//越靠近0 下降接近0越快
            	sunIntensity = sunIntensity * temp2;//再让它影响辐射强调,让太阳达到顶点时取消辐射光,以免让天空背景颜色过曝和偏移
                float3 sunLight = saturate((1 - sunDis*(pow(1- _SunHaloField,2))*(2 -_SunRadius)) * sunIntensity) * _SunHalo.xyz;
                sun = saturate(sun * 0.5 + sunLight*1.5);
				//月亮
                float moonDis = distance(i.sky_uv, moonPos);
                float3 moon = 1 - (moonDis / _SunRadius * 15);
                moon = saturate(moon * _MoonObscure*10 ) * _MoonColor.xyz;
				//月亮遮罩
            	float crescentMoon = distance(float2(i.sky_uv.x - _MoonOffset / 15, i.sky_uv.y - _MoonOffset / 30), moonPos);
				float crescentMoonDisc = 1 - (crescentMoon / _SunRadius * 15);
				crescentMoonDisc = saturate(crescentMoonDisc * _MoonObscure*10  ) * _MoonColor.xyz;

				moon = saturate(moon - crescentMoonDisc);

            	//最终画面
                float3 sky = skyGradients  + (horizon + sun) + moon*2;

            	//旋转贴图
            	float angle = -atan2(lightDir.y, lightDir.x);
            	float c = cos(angle);
            	float s = sin(angle);
            	float2x2 rot = float2x2(c,-s,s,c); 
				float2 rotatedUV = mul(rot,i.tex_uv - 0.5) + 0.5;
            	
                half4 col = tex2D(_MainTex, rotatedUV);
            	
            	temp2 = 1.0 - exp((-1 + _SunPos.y + 0.1) * 5.0);//越是中午 越小
            	//加上星空贴图
            	sky = sky + col.xyz * saturate(sunDis*temp2 - moon - sun);
                col = half4(sky, col.a);
                return col;
            }
            ENDHLSL
        }
    }
}

给场景中的平行光写个旋转脚本,就大功告成。

C#脚本:

public class DayNightContorl : MonoBehaviour
{
    public float time;
    public float speed;
    void FixedUpdate()
    {
        time += Time.deltaTime * speed / 100;
        transform.rotation = Quaternion.Euler(0,0,time * 360 + 90);
    }
}

最终效果:

52320a5bdd454354b0f1e2e175f5280f.png

视频连接:

【unity 2d 实现日夜循环效果(附带脚本)-哔哩哔哩】 https://b23.tv/zAIv4BC

 

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值