feat(environment): add painterly skies and living meadows
This commit is contained in:
@@ -1,42 +1,81 @@
|
||||
shader_type spatial;
|
||||
render_mode blend_mix, depth_prepass_alpha, cull_disabled, diffuse_burley, specular_schlick_ggx;
|
||||
|
||||
uniform float wave_strength : hint_range(0.0, 0.3) = 0.055;
|
||||
uniform float wave_strength : hint_range(0.0, 0.3) = 0.025;
|
||||
uniform float wave_speed : hint_range(0.0, 3.0) = 0.72;
|
||||
uniform float flow_speed : hint_range(0.0, 2.0) = 0.46;
|
||||
uniform vec3 deep_color : source_color = vec3(0.03, 0.39, 0.45);
|
||||
uniform vec3 shallow_color : source_color = vec3(0.07, 0.67, 0.64);
|
||||
uniform vec3 sunlit_color : source_color = vec3(0.55, 0.95, 0.78);
|
||||
uniform vec3 foam_color : source_color = vec3(0.82, 0.94, 0.84);
|
||||
uniform float flow_speed : hint_range(0.0, 2.0) = 0.28;
|
||||
uniform bool pool_surface = false;
|
||||
uniform float pool_outlet_z = -20.0;
|
||||
uniform vec3 deep_color : source_color = vec3(0.035, 0.34, 0.54);
|
||||
uniform vec3 shallow_color : source_color = vec3(0.12, 0.65, 0.69);
|
||||
uniform vec3 sunlit_color : source_color = vec3(0.57, 0.83, 0.88);
|
||||
uniform vec3 foam_color : source_color = vec3(0.9, 0.96, 0.91);
|
||||
|
||||
varying vec3 water_position;
|
||||
|
||||
|
||||
float painted_noise(vec2 p) {
|
||||
vec2 cell = floor(p);
|
||||
vec2 blend = fract(p);
|
||||
blend = blend * blend * (3.0 - 2.0 * blend);
|
||||
vec4 corners = fract(sin(vec4(
|
||||
dot(cell, vec2(127.1, 311.7)),
|
||||
dot(cell + vec2(1.0, 0.0), vec2(127.1, 311.7)),
|
||||
dot(cell + vec2(0.0, 1.0), vec2(127.1, 311.7)),
|
||||
dot(cell + vec2(1.0), vec2(127.1, 311.7))
|
||||
)) * 43758.5453);
|
||||
return mix(mix(corners.x, corners.y, blend.x), mix(corners.z, corners.w, blend.x), blend.y);
|
||||
}
|
||||
|
||||
|
||||
void vertex() {
|
||||
float broad_wave = sin(VERTEX.x * 0.42 + VERTEX.z * 0.18 + TIME * wave_speed);
|
||||
float crossing_wave = cos(VERTEX.x * 0.7 - VERTEX.z * 0.31 + TIME * wave_speed * 0.73);
|
||||
// World coordinates keep the pool and both ribbons at the same ripple scale.
|
||||
water_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||
float broad_wave = sin(water_position.x * 0.42 + water_position.z * 0.18 + TIME * wave_speed);
|
||||
float crossing_wave = cos(water_position.x * 0.7 - water_position.z * 0.31 + TIME * wave_speed * 0.73);
|
||||
VERTEX.y += (broad_wave + crossing_wave * 0.45) * wave_strength;
|
||||
}
|
||||
|
||||
|
||||
void fragment() {
|
||||
vec2 flowing_uv = UV * vec2(7.0, 10.0);
|
||||
flowing_uv.y -= TIME * flow_speed;
|
||||
float ribbon_a = sin(flowing_uv.y + sin(flowing_uv.x * 0.72) * 1.25) * 0.5 + 0.5;
|
||||
float ribbon_b = sin(flowing_uv.y * 1.7 - flowing_uv.x * 0.55 + TIME * 0.23) * 0.5 + 0.5;
|
||||
float quiet_ripple = smoothstep(0.72, 0.98, ribbon_a * 0.62 + ribbon_b * 0.38);
|
||||
float fresnel = pow(1.0 - clamp(dot(normalize(NORMAL), normalize(VIEW)), 0.0, 1.0), 2.4);
|
||||
float bank_distance = min(UV.x, 1.0 - UV.x);
|
||||
float bank_foam = 1.0 - smoothstep(0.0, 0.07, bank_distance);
|
||||
bank_foam *= 0.72 + sin(UV.y * 52.0 + TIME * 0.35) * 0.12;
|
||||
|
||||
vec3 water_color = mix(deep_color, shallow_color, ribbon_a * 0.2 + 0.48);
|
||||
water_color = mix(water_color, sunlit_color, fresnel * 0.42);
|
||||
water_color = mix(water_color, foam_color, quiet_ripple * 0.05);
|
||||
water_color = mix(water_color, foam_color, bank_foam * 0.3);
|
||||
// The ribbon owns the outlet so two transparent surfaces never overlap.
|
||||
if (pool_surface && water_position.z >= pool_outlet_z) {
|
||||
discard;
|
||||
}
|
||||
vec2 flow = water_position.xz - vec2(0.0, TIME * flow_speed);
|
||||
float broad_patch = painted_noise(flow * vec2(0.18, 0.3));
|
||||
float small_patch = painted_noise(flow * vec2(0.64, 0.85));
|
||||
float ripple_phase = flow.y * 3.2 + sin(flow.x * 0.83) * 1.2 + small_patch * 0.8;
|
||||
float ribbon = sin(ripple_phase);
|
||||
float stroke_width = max(fwidth(ribbon) * 0.7, 0.012);
|
||||
float strokes = smoothstep(0.975 - stroke_width, 0.975 + stroke_width, ribbon);
|
||||
strokes *= smoothstep(0.58, 0.8, painted_noise(flow * vec2(1.1, 1.8))) * 0.16;
|
||||
strokes *= 1.0 - smoothstep(0.28, 0.8, fwidth(ripple_phase));
|
||||
vec3 ripple_normal = normalize(vec3(
|
||||
cos(flow.x * 0.83 + flow.y * 0.37 + broad_patch * 6.0) * 0.006,
|
||||
1.0,
|
||||
cos(ripple_phase + small_patch * 5.0) * 0.008
|
||||
));
|
||||
NORMAL = normalize((VIEW_MATRIX * vec4(ripple_normal, 0.0)).xyz);
|
||||
float fresnel = pow(1.0 - clamp(dot(NORMAL, normalize(VIEW)), 0.0, 1.0), 2.6);
|
||||
// Painted sky patches need no screen/depth texture and work in Compatibility.
|
||||
vec3 world_view = normalize((INV_VIEW_MATRIX * vec4(VIEW, 0.0)).xyz);
|
||||
vec3 reflection = reflect(-world_view, ripple_normal);
|
||||
vec2 sky_uv = reflection.xz / max(reflection.y + 0.35, 0.25);
|
||||
float clouds = painted_noise(sky_uv * 2.0 + vec2(0.7, 2.4));
|
||||
clouds = smoothstep(0.49, 0.77, clouds + painted_noise(sky_uv * 4.5) * 0.18);
|
||||
float bank_distance = min(UV.x, 1.0 - UV.x) * 2.0;
|
||||
if (pool_surface) {
|
||||
bank_distance = 1.0 - length(UV * 2.0 - 1.0);
|
||||
}
|
||||
float bank_foam = (1.0 - smoothstep(0.01, 0.045, bank_distance));
|
||||
bank_foam *= smoothstep(0.4, 0.75, small_patch) * 0.48;
|
||||
vec3 water_color = mix(deep_color, shallow_color, 0.19 + broad_patch * 0.2);
|
||||
water_color = mix(water_color, sunlit_color, clouds * (0.13 + fresnel * 0.35));
|
||||
water_color = mix(water_color, foam_color, strokes + bank_foam);
|
||||
|
||||
ALBEDO = water_color;
|
||||
ROUGHNESS = mix(0.34, 0.5, ribbon_b);
|
||||
SPECULAR = 0.38;
|
||||
EMISSION = water_color * 0.12 + sunlit_color * (quiet_ripple * 0.05 + fresnel * 0.03);
|
||||
EMISSION += foam_color * bank_foam * 0.025;
|
||||
ALPHA = mix(0.94, 0.99, fresnel);
|
||||
ROUGHNESS = 0.38 + broad_patch * 0.08;
|
||||
SPECULAR = 0.14;
|
||||
ALPHA = smoothstep(0.0, 0.018, bank_distance) * 0.97;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user