话不多说直接上脚本,其实逻辑我理不清了,反正瞎调的达到效果就好了。
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);
}
}
最终效果:
视频连接:
【unity 2d 实现日夜循环效果(附带脚本)-哔哩哔哩】 https://b23.tv/zAIv4BC