我们平时做天空球的uv接缝贴图不好处理,看了官方shader的源码,结合借鉴了candycat美女的动态噪波云效果,做了一个天空球
Unity中Lighting里的天空盒的UV是纯圆形的
官方shader中是用CUBEMap实现的,我也在这基础上修改
分为几大块:背景上下渐变色+一层云半透cubemap+中景山脉半透cubemap+前景动态噪波云
Properties {
_SkyColor0 ("Sky Color Up", Color) = (0, 0, 1, 1)
_SkyColor1 ("Sky Color Down", Color) = (0.5, 0.5, 1, 1)
[Space(50)]
[NoScaleOffset] _Tex ("BackCloudCubemap (HDR)", Cube) = "grey" {}
_Tint ("Tint Color", Color) = (1, 1, 1, 1)
[Gamma] _Exposure ("Exposure", Range(0, 8)) = 1.0
_RotationSpeed ("RotationSpeed", Range(0, 10)) = 2.51
[Space(50)]
[NoScaleOffset] _Tex2 ("MiddleTex", Cube) = "grey" {}
_UVY ("UVY", Range(-1, 3.0)) = 0
[Space(50)]
[NoScaleOffset] _Octave0 ("Octave 0", 2D) = "white" {}
[NoScaleOffset] _Octave1("Octave 1", 2D) = "white" {}
[NoScaleOffset] _Octave2 ("Octave 2", 2D) = "white" {}
[NoScaleOffset] _Octave3 ("Octave 3", 2D) = "white" {}
_CloudColor ("Cloud Color", Color) = (1, 1, 1, 0.7)
_Speed ("Speed", Range(-1.0, 1.0)) = -0.49
_Emptiness ("Emptiness", Range(0.0, 1.0)) = 0.441
_Sharpness ("Sharpness", Range(0.0, 1.0)) = 0.711
}
SubShader {
Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
Cull Off ZWrite Off
//渐变背景色pass
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
fixed _BackTexSpeed;
fixed4 _SkyColor0;
fixed4 _SkyColor1;
sampler2D _Octave0;
sampler2D _Octave3;
float _UVY;
struct appdata {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
float2 texcoord1 : TEXCOORD1;
};
v2f vert (appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
o.uv = half2(o.uv.x+_Time.y*_BackTexSpeed,o.uv.y);
o.texcoord1 = v.texcoord;
o.texcoord1 = half2(o.texcoord1.x,o.texcoord1.y + _UVY);
return o;
}
fixed4 frag (v2f i) : SV_Target {
fixed4 col;
col.rgb = lerp(_SkyColor1.rgb, _SkyColor0.rgb, pow(i.uv.y, 1));
col.a = 1.0;
return col;
}
ENDCG
}
//背景云pass
Pass {
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
half4 _Tint;
half4 _Tex_HDR;
half4 _Tint1;
samplerCUBE _Tex;
float _Rotation;
fixed _Emptiness;
fixed _Sharpness;
sampler2D _Main_Textures;
float4 _Main_Textures_ST;
float _RotationSpeed;
struct appdata {
float4 vertex : POSITION;
float3 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f {
float4 pos : SV_POSITION;
half4 uv0 : TEXCOORD0;
half4 uv1 : TEXCOORD1;
half2 uv2 : TEXCOORD2;
float3 texcoord : TEXCOORD3;
float3 texcoord1 : TEXCOORD4;
UNITY_VERTEX_OUTPUT_STEREO
};
//旋转矩阵
float3 RotateAroundYInDegrees (float3 vertex, float degrees)
{
float alpha = degrees * UNITY_PI / 180.0;
float sina, cosa;
sincos(alpha, sina, cosa);
float2x2 m = float2x2(cosa, -sina, sina, cosa);
return float3(mul(m, vertex.xz), vertex.y).xzy;
}
v2f vert (appdata v) {
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
float3 rotated = RotateAroundYInDegrees(v.vertex, _Rotation+_Time.y*_RotationSpeed);
o.pos = UnityObjectToClipPos(rotated);
o.texcoord = v.vertex.xyz;
return o;
}
fixed4 frag (v2f i) : SV_Target {
half4 tex = texCUBE (_Tex, i.texcoord) ;
half3 c = DecodeHDR (tex, _Tex_HDR) ;
c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb ;
return half4(c,tex.a);
}
ENDCG
}
//动态云和中景山
Pass {
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
half4 _Tint;
half4 _Tint1;
float _Rotation;
fixed4 _CloudColor;
sampler2D _Octave0;
sampler2D _Octave1;
sampler2D _Octave2;
sampler2D _Octave3;
float4 _Octave0_ST;
float4 _Octave1_ST;
float4 _Octave2_ST;
float4 _Octave3_ST;
float _Speed;
fixed _Emptiness;
fixed _Sharpness;
samplerCUBE _Tex2;
float _UVY;
struct appdata {
float4 vertex : POSITION;
float3 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f {
float4 pos : SV_POSITION;
half4 uv0 : TEXCOORD0;
half4 uv1 : TEXCOORD1;
half2 uv2 : TEXCOORD2;
float3 texcoord : TEXCOORD3;
float3 texcoord1 : TEXCOORD4;
UNITY_VERTEX_OUTPUT_STEREO
};
float3 RotateAroundYInDegrees (float3 vertex, float degrees)
{
float alpha = degrees * UNITY_PI / 180.0;
float sina, cosa;
sincos(alpha, sina, cosa);
float2x2 m = float2x2(cosa, -sina, sina, cosa);
return float3(mul(m, vertex.xz), vertex.y).xzy;
}
v2f vert (appdata v) {
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.pos = UnityObjectToClipPos(v.vertex);
o.texcoord1 = v.vertex.xyz;
o.texcoord1 = half3(o.texcoord1.x,o.texcoord1.y + _UVY,o.texcoord1.z);
o.uv0.xy = TRANSFORM_TEX(v.texcoord, _Octave0) + _Time.x * 1.0 * _Speed * half2(-1.0, 0.5);
o.uv0.zw = TRANSFORM_TEX(v.texcoord, _Octave1) + _Time.x * 1.5 * _Speed * half2(-1.0, 1.0);
o.uv1.xy = TRANSFORM_TEX(v.texcoord, _Octave2) + _Time.x * 2.0 * _Speed * half2(-1.0, -1.0);
o.uv1.zw = TRANSFORM_TEX(v.texcoord, _Octave3) + _Time.x * 2.5 * _Speed * half2(-1.0, -0.5);
return o;
}
fixed4 frag (v2f i) : SV_Target {
fixed4 col = 0;
float4 n0 = tex2D(_Octave0, i.uv0.xy);
float4 n1 = tex2D(_Octave1, i.uv0.zw);
float4 n2 = tex2D(_Octave2, i.uv1.xy);
float4 n3 = tex2D(_Octave3, i.uv1.zw);
//分型布朗函数计算
float4 fbm = 0.5 * n0 + 0.25 * n1+ 0.125 * n2 + 0.0625 * n3;
fbm = (clamp(fbm, _Emptiness, _Sharpness) - _Emptiness)/(_Sharpness - _Emptiness);
//光线穿透云层半透
fixed4 ray = fixed4(0.0, 0.2, 0.4, 0.6);
fixed amount = dot(max(fbm - ray, 0), fixed4(0.25, 0.25, 0.25, 0.25));
col.rgb = amount + 2.0 * (1.0 - amount) * 0.4;
col.a = amount * 1.5;
half4 tex2 = texCUBE (_Tex2, i.texcoord1);
return tex2*(1-col.a) + col*col.a * _CloudColor;
}
ENDCG
}
}
Fallback Off
}