270 lines
8.6 KiB
GLSL
270 lines
8.6 KiB
GLSL
Shader "CrispyPin/Spinny_Sunset"
|
|
{
|
|
Properties
|
|
{
|
|
[Header(Raymarcher Properties)]
|
|
_MaxSteps ("Max steps", Integer) = 128
|
|
_MaxDist ("Max distance", Float) = 128
|
|
_SurfDist ("Surface distance threshold", Range(0.0001, 0.05)) = 0.001
|
|
[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]
|
|
_NoiseTex ("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)]
|
|
_HeightOffset ("Height offset", Range(-10, 10)) = -0.5
|
|
_WaterCol ("Water color", Color) = (0.03, 0.08, 0.12, 1.0)
|
|
_WaveStrength ("Wave scale", Range(0, 1)) = 1
|
|
_WaveSpeed ("Wave speed", Range(0, 5)) = 1
|
|
[NoScaleOffset]
|
|
_WaterNormal ("Surface Normal", 2D) = "white" {}
|
|
[Header(Debug)]
|
|
_Grid ("Grid visibility", Range(0, 1)) = 0
|
|
|
|
}
|
|
SubShader
|
|
{
|
|
Tags { "RenderType"="Opaque" }
|
|
LOD 100
|
|
Cull front
|
|
|
|
Pass
|
|
{
|
|
CGPROGRAM
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
|
|
|
|
int _MaxSteps;
|
|
float _MaxDist;
|
|
float _SurfDist;
|
|
#define MAX_STEPS 512
|
|
#define MAX_DIST _MaxDist
|
|
#define SURF_DIST _SurfDist
|
|
|
|
#define LIGHT_FN lighting
|
|
#define SCENE_FN main
|
|
#define REFLECTIONS 2
|
|
#define SCENE_SCALE 0.025
|
|
#define LIMIT_DEPTH_TO_MESH
|
|
|
|
#include "lib/libgarbage.cginc"
|
|
|
|
#define PI 3.1416f
|
|
#define WHITE 1
|
|
#define UP float3(0, 1, 0)
|
|
|
|
sampler2D _NoiseTex;
|
|
float3 _SkyCol;
|
|
float _HorizonTint;
|
|
|
|
float _StarsMissing;
|
|
float _StarDensity;
|
|
float _StarRandom;
|
|
|
|
float _StarSize;
|
|
float _StarSizeRandom;
|
|
float _StarTint;
|
|
|
|
float3 _SunCol;
|
|
float _SunAngle;
|
|
float _SunRadius;
|
|
float _SunCutoff;
|
|
|
|
sampler2D _WaterNormal;
|
|
// sampler2D _WaterHeight;
|
|
// sampler2D _WaterAO;
|
|
float3 _WaterCol;
|
|
float _HeightOffset;
|
|
float _WaveStrength;
|
|
float _WaveSpeed;
|
|
|
|
float _Grid;
|
|
|
|
float3 get_water_normal(float2 pos) {
|
|
pos *= 0.5;
|
|
float time = _Time.x * _WaveSpeed + 5; // offset is to make it look better at frame 0
|
|
float t1 = time * 0.18;
|
|
float3 normal = (tex2D(_WaterNormal, pos + float2(t1, -t1 * 0.5)) - 0.5) * 0.5;
|
|
float t2 = time * 0.37;
|
|
normal += (tex2D(_WaterNormal, pos * 0.276 + float2(t2 * 0.8, t2)) - 0.5);
|
|
float t3 = time * 0.08;
|
|
normal += (tex2D(_WaterNormal, pos * 0.07 + float2(t3 * 0.8, -t3)) - 0.5);
|
|
// normal = normalize(normal.zxy); // normal map import settings
|
|
normal = normalize(normal.rbg) * float3(-1, 1, -1); // standard import settings
|
|
|
|
// normal = normalize(normal);
|
|
|
|
// return UP;
|
|
return lerp(UP, normal, _WaveStrength);
|
|
}
|
|
|
|
|
|
float3 sun(float3 base_col, float3 dir, float3 sun_dir) {
|
|
float alignment = min(acos(dot(dir, sun_dir)), 1);
|
|
float sun_amount = smax(min(_SunRadius / alignment, 5) - _SunCutoff, 0, 0.15);
|
|
return lerp(base_col, _SunCol, sun_amount);
|
|
}
|
|
|
|
float3 sky(float3 dir, float3 sun_dir) {
|
|
float theta = atan2(dir.x, dir.z); // latitude
|
|
float phi = asin(dir.y); // longitude
|
|
/// background
|
|
float factor = smoothstep(0, 0.5, dir.y + 0.2);
|
|
float3 horizon_col = lerp(_SkyCol, _SunCol, _HorizonTint);
|
|
float3 col = lerp(horizon_col, _SkyCol, factor);
|
|
|
|
/// stars
|
|
float2 cells = float2(-1, floor(_StarDensity));
|
|
float cell_x_base = floor(cells.y * PI);
|
|
float celly = phi * cells.y;
|
|
// cells per ring depend on y pos, to reduce warping around the poles:
|
|
cells.x = floor(cos(floor(celly) / _StarDensity) * cell_x_base);
|
|
float cellx = (theta / PI * cells.x);
|
|
|
|
float2 pos = float2(cellx, celly); // cell-space pos of this pixel
|
|
float2 cell_pos = float2(floor(cellx), floor(celly)); // position of this cell
|
|
float2 cell_center = cell_pos + 0.5;
|
|
|
|
float2 star_pos = cell_center + (tex2D(_NoiseTex, cell_pos / cells + float2(0, 0.1)) - 0.5) * _StarRandom;
|
|
|
|
/// star color
|
|
float3 r = tex2D(_NoiseTex, 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(phi * 2) - 0.1, 0, 1); // fade stars near/under horizon
|
|
star_strength *= length(r) / 2; // fade stars
|
|
star_strength *= rnum2 > _StarsMissing; // remove stars
|
|
|
|
float3 star_col = lerp(WHITE, r, _StarTint);
|
|
|
|
col = lerp(col, star_col, star_strength);
|
|
|
|
col = sun(col, dir, sun_dir);
|
|
/// debug grid
|
|
col = lerp(col, WHITE, _Grid * (
|
|
pow(frac( cellx), 20) +
|
|
pow(frac( celly), 20) +
|
|
pow(frac(-cellx), 20) +
|
|
pow(frac(-celly), 20)
|
|
));
|
|
|
|
return col;
|
|
}
|
|
|
|
float3 sunset_env(float3 dir, float3 ray_origin) {
|
|
ray_origin = 0;
|
|
|
|
// float3 horizon_col = lerp(_SkyCol, _SunCol, _HorizonTint);
|
|
float3 origin = mul(unity_ObjectToWorld, float4(0, 0, 0, 1));
|
|
origin = 0;
|
|
float3 sun_dir = float3(sin(_SunAngle), 0.0, cos(_SunAngle));
|
|
|
|
float3 col;
|
|
|
|
if (dir.y < 0) {
|
|
origin.y += _HeightOffset;
|
|
float3 camera_local_pos = ray_origin;
|
|
camera_local_pos.y = max(camera_local_pos.y, 0.01); // don't allow looking under water surface; it renders backwards.
|
|
float3 surface_pos = float3 (
|
|
camera_local_pos.x - camera_local_pos.y / (dir.y / dir.x),
|
|
0,
|
|
camera_local_pos.z - camera_local_pos.y / (dir.y / dir.z)
|
|
);
|
|
float3 water_normal = get_water_normal(surface_pos.xz);
|
|
|
|
float3 reflected_dir = reflect(dir, water_normal);
|
|
float3 sky_reflection = sky(reflected_dir, sun_dir) ;
|
|
|
|
float3 water_col = lerp(_SkyCol, _SunCol, 0.01) * _WaterCol;
|
|
float3 refracted_dir = normalize(refract(dir, water_normal, 1/1.333));
|
|
float subsurf = (refracted_dir.y + 1);
|
|
|
|
col = water_col * max(subsurf * 12 - 2, 0.7);
|
|
|
|
float diffuse = max(dot(sun_dir, water_normal), 0);
|
|
col += water_col * _SunCol * diffuse * 10;
|
|
|
|
// float3 water_ao = get_ao(surface_pos.xz);
|
|
// col = water_col * lerp(0.1, water_ao, _WaveStrength) * 7;
|
|
|
|
float hit_angle = dot(dir, -water_normal);
|
|
col = lerp(sky_reflection, col, hit_angle);
|
|
|
|
// col = sky_reflection;
|
|
// col *= pow(dot(UP, water_normal), 512); // EVIL in the water
|
|
// col = pow((tex2D(_WaterNormal, surface_pos.xz).zxy), 2);
|
|
// col = tex2D(_WaterAO, surface_pos.xz);
|
|
|
|
// float distance = length(surface_pos - camera_local_pos);
|
|
// float fog_factor = smoothstep(10, 70, distance) * 0.4;
|
|
// col = lerp(col, horizon_col, fog_factor);
|
|
}
|
|
else {
|
|
col = sky(dir, sun_dir);
|
|
}
|
|
return pow(col, 1/2.2);
|
|
}
|
|
|
|
SurfacePoint main(float3 p) {
|
|
Material grass = mat(float3(0.26, 0.73, 0.35), 1);
|
|
Material dirt = mat(float3(0.73, 0.48, 0.26), 0);
|
|
Material metal = mat(1, 1);
|
|
Material blue = mat(float3(0.73, 0.8, 1), 0);
|
|
|
|
SurfacePoint d = mPlaneY(p, 0, grass);
|
|
d = qIntersect(d, mSphere(p, 9, dirt), 0.5);
|
|
d = qUnion(d, mSphere(p - float3(0, 2, 0), 2, metal));
|
|
d = qUnion(d, mTorus(rotX(p, _Time * 40 + UNITY_PI / 2), 5, 0.5, blue), 0.5);
|
|
d = qUnion(d, mTorus(rotZ(p, _Time * 40 + UNITY_PI / 2), 5, 0.5, blue), 0.5);
|
|
d = qUnion(d, mTorus(rotX(p, _Time * 40), 5, 0.5, blue), 0.5);
|
|
d = qUnion(d, mTorus(rotZ(p, _Time * 40), 5, 0.5, blue), 0.5);
|
|
// small spheres
|
|
float3 p2 = abs(rotY(p, -20 * _Time)) - float3(1.5, sin(_Time.y * 5) + 1, 1.5);
|
|
d = qUnion(d, mSphere(p2, 0.7, metal), 0.2);
|
|
|
|
// Material water = mat(float3(0.12, 0.15, 0.19), 1);
|
|
// float h = 0;// sin(p.x + sin(p.z * 2+ _Time.y) * 0.3);
|
|
// h *= 0.1;
|
|
// h = - 2;
|
|
// d = qUnion(d, mPlaneY(p, h - snoise(p / 10 + _Time.xyz * 0.2) * 0.2, water));
|
|
// float3 p3 = repXZ(p, 20, 20);
|
|
// d = qUnion(d, mSphere(p3 - float3(snoise(p), -5, 1), 8, water), 3);
|
|
// d = qUnion(d, mSphere(p3 - float3(3, h - 1.5, 2 + sin(p.x / 20)*3), 4, water), 3);
|
|
return d;
|
|
}
|
|
|
|
float3 lighting(Ray ray) {
|
|
if (ray.missed) {
|
|
return sunset_env(ray.dir, ray.start / SCENE_SCALE);
|
|
}
|
|
|
|
float3 sun_dir = normalize(float3(0, 1, 10));
|
|
float3 light = lSun(ray.normal, sun_dir);
|
|
light *= lShadow(ray.hit_pos + ray.normal * SURF_DIST, sun_dir, 50);
|
|
light += lSky(ray.normal);
|
|
return light;
|
|
}
|
|
ENDCG
|
|
}
|
|
}
|
|
}
|