135 lines
3.5 KiB
Plaintext
135 lines
3.5 KiB
Plaintext
shader_type spatial;
|
|
|
|
render_mode unshaded, fog_disabled, depth_draw_never, cull_disabled, blend_mix;
|
|
|
|
const int MAX_LIGHTS = 256;
|
|
|
|
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear;
|
|
uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;
|
|
|
|
// Camera matrices — set from GDScript.
|
|
uniform mat4 inv_projection;
|
|
uniform mat4 inv_view;
|
|
|
|
// Fog
|
|
uniform vec3 fog_color : source_color = vec3(0.55, 0.65, 0.75);
|
|
uniform float fog_density : hint_range(0.0, 10.0) = 0.5;
|
|
uniform float fog_height_falloff : hint_range(0.0, 10.0) = 0.15;
|
|
|
|
// Light scattering
|
|
uniform int light_count = 0;
|
|
uniform vec3 light_positions[MAX_LIGHTS];
|
|
uniform vec4 light_colors[MAX_LIGHTS];
|
|
uniform float light_energies[MAX_LIGHTS];
|
|
uniform float light_ranges[MAX_LIGHTS];
|
|
|
|
uniform float scattering : hint_range(0.0, 2.0) = 0.5;
|
|
uniform float scattering_power : hint_range(0.1, 32.0) = 8.0;
|
|
|
|
uniform int steps : hint_range(8, 64) = 32;
|
|
|
|
vec3 reconstruct_view_position(vec2 uv, float depth) {
|
|
vec3 ndc = vec3(uv * 2.0 - 1.0, depth);
|
|
|
|
vec4 view_pos = inv_projection * vec4(ndc, 1.0);
|
|
view_pos.xyz /= view_pos.w;
|
|
|
|
return view_pos.xyz;
|
|
}
|
|
|
|
void fragment() {
|
|
vec2 screen_uv = SCREEN_UV;
|
|
|
|
vec4 scene = texture(screen_texture, screen_uv);
|
|
float depth = texture(depth_texture, screen_uv).r;
|
|
|
|
vec3 ray_end_view =
|
|
reconstruct_view_position(screen_uv, depth);
|
|
|
|
vec3 camera_position =
|
|
(inv_view * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
|
|
|
vec3 ray_end =
|
|
(inv_view * vec4(ray_end_view, 1.0)).xyz;
|
|
|
|
vec3 ray_vector = ray_end - camera_position;
|
|
float ray_length = length(ray_vector);
|
|
|
|
vec3 ray_dir = normalize(ray_vector);
|
|
|
|
float step_length = ray_length / float(steps);
|
|
|
|
vec3 accumulated = vec3(0.0);
|
|
float transmittance = 1.0;
|
|
|
|
for (int i = 0; i < steps; i++) {
|
|
float t = (float(i) + 0.5) / float(steps);
|
|
|
|
vec3 world_position =
|
|
camera_position +
|
|
ray_dir * (ray_length * t);
|
|
|
|
float height_density =
|
|
exp(-world_position.y * fog_height_falloff);
|
|
|
|
float density =
|
|
fog_density * height_density;
|
|
|
|
vec3 light_scattering = vec3(0.0);
|
|
|
|
for (int l = 0; l < MAX_LIGHTS; l++) {
|
|
if (l >= light_count)
|
|
break;
|
|
|
|
vec3 to_light =
|
|
light_positions[l] - world_position;
|
|
|
|
float light_distance = length(to_light);
|
|
|
|
if (light_distance <= 0.001)
|
|
continue;
|
|
|
|
vec3 light_dir =
|
|
to_light / light_distance;
|
|
|
|
float attenuation =
|
|
1.0 - smoothstep(
|
|
0.0,
|
|
light_ranges[l],
|
|
light_distance
|
|
);
|
|
|
|
attenuation /=
|
|
1.0 + light_distance * light_distance * 0.01;
|
|
|
|
float phase =
|
|
pow(
|
|
max(dot(-ray_dir, light_dir), 0.0),
|
|
scattering_power
|
|
);
|
|
|
|
light_scattering +=
|
|
light_colors[l].rgb *
|
|
light_energies[l] *
|
|
attenuation *
|
|
phase *
|
|
scattering;
|
|
}
|
|
|
|
float absorption =
|
|
exp(-density * step_length * 10.0);
|
|
|
|
accumulated +=
|
|
(fog_color + light_scattering) *
|
|
(1.0 - absorption) *
|
|
transmittance;
|
|
|
|
transmittance *= absorption;
|
|
}
|
|
|
|
ALBEDO =
|
|
scene.rgb * transmittance +
|
|
accumulated;
|
|
|
|
ALPHA = 1.0;
|
|
} |