Shader "CrispyPin/Sunset Environment (Dynamic)" { Properties { [Header(Sky)] _SkyCol ("Sky color", Color) = (0.22, 0.23, 0.58, 1.0) _HorizonTint ("Horizon tint", Range(0, 1)) = 0.1 [Header(Sun)] _SunCol ("Sun color", Color) = (1.0, 0.65, 0.05, 1.0) _SunAngle ("Sun angle", Range(0, 6.28)) = 0 _SunRadius ("Sun radius", Range(0, 0.3)) = 0.06 _SunCutoff ("Sun cutoff", Range(0, 0.5)) = 0.08 [Header(Star Layout)] [NoScaleOffset] _MainTex ("Noise source", 2D) = "white" {} _StarDensity ("Star density", Range(4, 50)) = 20 _StarRandom ("Star randomness", Range(0, 1)) = 0.85 [Header(Star)] _StarsMissing ("Stars missing", Range(0, 1)) = 0.75 _StarSize ("Star size", Range(0, 0.1)) = 0.06 _StarSizeRandom ("Star size randomness", Range(0, 1)) = 0.5 _StarTint ("Star tint", Range(0, 1)) = 0.4 [Header(Water)] _WaterCol ("Water color", Color) = (0.03, 0.08, 0.12, 1.0) _WaveStrength ("Wave scale", Range(0, 1)) = 1 [NoScaleOffset] _WaterSurface ("Surface Normal", 2D) = "white" {} [Header(Debug)] _Grid ("Grid visibility", Range(0, 1)) = 0 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Cull back Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #define PI 3.1416f #define WHITE fixed4(1, 1, 1, 1) #define UP float3(0, 1, 0) struct appdata { float4 vertex : POSITION; }; struct v2f { float4 vertex : SV_POSITION; float3 cam_pos : TEXCOORD0; float3 hit_pos : TEXCOORD1; }; sampler2D _MainTex; fixed4 _SkyCol; float _HorizonTint; float _StarsMissing; float _StarDensity; float _StarRandom; float _StarSize; float _StarSizeRandom; float _StarTint; fixed4 _SunCol; float _SunAngle; float _SunRadius; float _SunCutoff; sampler2D _WaterSurface; fixed4 _WaterCol; float _WaveStrength; float _Grid; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.cam_pos = _WorldSpaceCameraPos; o.hit_pos = mul(unity_ObjectToWorld, v.vertex); return o; } fixed3 get_water_normal(float2 pos) { float3 normal = 0.0; float t1 = _Time.x * 0.18; normal += (tex2D(_WaterSurface, pos * 1.04 + float2(t1, t1 * 0.5)) - 0.5); float t2 = _Time.x * 0.37; normal += (tex2D(_WaterSurface, pos * 0.276 + float2(t2 * 0.8, t2)) - 0.5); float t3 = _Time.x * 0.08; normal += (tex2D(_WaterSurface, pos * 0.07 + float2(t3 * 0.8, -t3)) - 0.5); return normalize(normal.zxy); } float smin(float a, float b, float k) { float h = max(k - abs(a-b), 0) / k; return min(a, b) - h*h*h*k * 1/6.0; } float smax(float a, float b, float k) { float h = max(k - abs(a - b), 0) / k; return max(a, b) + h*h*h*k * 1/6.0; } fixed4 frag(v2f i) : SV_Target { float water_mod = 0.0; float water_reflection = 0.0; float3 real_dir = normalize(i.hit_pos - i.cam_pos); float3 dir = real_dir; float real_y = asin(dir.y); if (real_y < 0.0) { // distort to look like water reflection float3 object_pos = mul(unity_ObjectToWorld, float4(0, 0, 0, 1)); float3 camera_local_pos = i.cam_pos - object_pos; float3 surface_pos = float3 ( camera_local_pos.x - camera_local_pos.y / (real_dir.y / real_dir.x), 0, camera_local_pos.z - camera_local_pos.y / (real_dir.y / real_dir.z) ); float3 water_normal = get_water_normal(surface_pos.xz); water_normal = lerp(UP, water_normal, _WaveStrength); dir = reflect(dir, water_normal); water_mod = dot(dir, water_normal); water_reflection = 1.0; } float y = abs(real_y); dir.y = abs(dir.y); float phi = atan2(dir.x, dir.z); /// sky float factor = smoothstep(0.0, 0.5, dir.y + 0.2); factor = min(factor, 1.0); fixed4 horizon_col = lerp(_SkyCol, _SunCol, _HorizonTint); fixed4 col = lerp(horizon_col, _SkyCol, factor); /// stars float2 cells = float2(-1, floor(_StarDensity)); float cell_x_base = floor(cells.y * PI); float celly = y * cells.y; // cells per ring depend on y pos, to reduce warping around the poles: cells.x = max(floor(cos(floor(celly)/_StarDensity) * cell_x_base), 3); float cellx = (phi / PI * cells.x); float2 pos = float2(cellx, celly);// cell-space pos of this fragment float2 cell_pos = float2(floor(cellx), floor(celly)); // position of this cell float2 cell_center = cell_pos + float2(0.5, 0.5); float2 star_pos = cell_center + (tex2D(_MainTex, cell_pos / cells + float2(0., 0.1)) - 0.5) * _StarRandom; /// star color float3 r = tex2D(_MainTex, cell_pos / cells); float rnum = frac((r.r + r.g - r.b) * 10); float rnum2 = frac((r.r - r.g + r.b) * 10); float star_size = _StarSize * (rnum * _StarSizeRandom + (1 - _StarSizeRandom)); float distance = length(pos - star_pos); float star_strength = max(min(star_size / distance * 0.5, 1.25) - 0.25, 0); // star glow star_strength *= clamp(sin(y * 2) - 0.1, 0, 1); // fade stars near/under horizon star_strength *= length(r) / 2; // fade stars star_strength *= rnum2 > _StarsMissing; // remove stars fixed3 star_col = lerp(1.0, r, _StarTint); col = lerp(col, fixed4(star_col, 1.0), star_strength); /// debug grid col = lerp(col, WHITE, _Grid * (frac(cellx) < 0.04 || frac(celly) < 0.04)); /// sun float3 sun_dir = float3(sin(_SunAngle), 0.0, cos(_SunAngle)); float alignment = min(acos(dot(dir, sun_dir)), 1); float sun_amount = smax(min(_SunRadius / alignment, 5) - _SunCutoff, 0, 0.15); col = lerp(col, _SunCol, sun_amount); col = lerp(col, _WaterCol, water_mod); /// shiny water // float view_perpendicular = 1 - abs(dot(dir, water_normal)); // float view_perpendicular = 1 - abs(dot(dir, water_normal)); // water_reflection = _SunCol * pow(view_perpendicular, 40); // col += water_reflection *; return col; } ENDCG } } }