Files
Trinittu/dynamic-sky/scripts/post_process_controller.gd
2026-02-03 11:26:48 +01:00

311 lines
9.1 KiB
GDScript

@tool
class_name PostProcessController
extends Node
@export_group("Profile")
@export var profile: PostProcessProfile:
set(value):
profile = value
_apply_profile()
@export_group("Environment")
@export var target_environment: Environment
@export_group("Sky Gradient")
@export var sky_top_color: Color = Color(0.2, 0.4, 0.8)
@export var sky_horizon_color: Color = Color(0.6, 0.7, 0.9)
@export var sky_bottom_color: Color = Color(0.4, 0.5, 0.6)
@export var gradient_intensity: float = 1.0
@export_group("Skybox")
@export var skybox_texture: Texture2D:
set(value):
skybox_texture = value
_update_sky_material()
@export var skybox_blend: float = 1.0:
set(value):
skybox_blend = clampf(value, 0.0, 1.0)
_update_sky_material()
@export_group("Fog Shaping")
@export var fog_enabled: bool = true
@export var fog_color: Color = Color(0.7, 0.8, 0.9)
@export var fog_density: float = 0.01
@export var height_fog_enabled: bool = true
@export var height_fog_min: float = 0.0
@export var height_fog_max: float = 100.0
@export var height_fog_curve: float = 1.0
@export_group("Sun Glow")
@export var sun_glow_enabled: bool = true
@export var sun_glow_intensity: float = 0.5
@export var sun_glow_size: float = 0.2
@export var sun_glow_falloff: float = 2.0
@export var sun_glow_color: Color = Color(1.0, 0.95, 0.8)
@export var sun_direction: Vector3 = Vector3(0.0, 1.0, 0.0)
@export_group("Dawn/Dusk Enhancement")
@export var dawn_dusk_enabled: bool = true
@export var dawn_dusk_intensity: float = 0.5
@export var dawn_dusk_blend: float = 0.0
@export_group("Performance")
@export var effects_enabled: bool = true
var _sky_material: ShaderMaterial
var _post_process_quad: MeshInstance3D
func _ready() -> void:
if profile == null:
profile = PostProcessProfile.new()
_apply_profile()
_setup_environment()
func _apply_profile() -> void:
if profile == null:
return
gradient_intensity = profile.gradient_intensity
fog_enabled = profile.fog_enabled
height_fog_enabled = profile.height_fog_enabled
height_fog_min = profile.height_fog_start
height_fog_max = profile.height_fog_end
height_fog_curve = profile.height_fog_curve
sun_glow_enabled = profile.sun_glow_enabled
sun_glow_intensity = profile.sun_glow_intensity
sun_glow_size = profile.sun_glow_size
sun_glow_falloff = profile.sun_glow_falloff
sun_glow_color = profile.sun_glow_color
dawn_dusk_enabled = profile.dawn_dusk_enabled
dawn_dusk_intensity = profile.dawn_dusk_intensity
func _setup_environment() -> void:
if target_environment == null:
return
_update_fog()
_update_sky()
func _update_fog() -> void:
if target_environment == null:
return
target_environment.fog_enabled = fog_enabled and effects_enabled
if fog_enabled:
target_environment.fog_light_color = fog_color
target_environment.fog_density = fog_density
if height_fog_enabled:
target_environment.fog_height = height_fog_min
target_environment.fog_height_density = height_fog_curve * 0.1
func _update_sky() -> void:
if target_environment == null:
return
if target_environment.sky == null:
target_environment.sky = Sky.new()
if target_environment.sky.sky_material == null or not target_environment.sky.sky_material is ShaderMaterial:
_create_sky_material()
_sky_material = target_environment.sky.sky_material as ShaderMaterial
if _sky_material:
_update_sky_material()
func _create_sky_material() -> void:
_sky_material = ShaderMaterial.new()
_sky_material.shader = _get_sky_shader()
if target_environment and target_environment.sky:
target_environment.sky.sky_material = _sky_material
func _get_sky_shader() -> Shader:
var shader := Shader.new()
shader.code = """
shader_type sky;
uniform sampler2D skybox_texture : source_color, filter_linear_mipmap, repeat_enable;
uniform bool skybox_enabled = false;
uniform float skybox_blend = 1.0;
uniform vec4 sky_top_color : source_color = vec4(0.2, 0.4, 0.8, 1.0);
uniform vec4 sky_horizon_color : source_color = vec4(0.6, 0.7, 0.9, 1.0);
uniform vec4 sky_bottom_color : source_color = vec4(0.4, 0.5, 0.6, 1.0);
uniform float gradient_intensity = 1.0;
uniform float horizon_blend = 0.5;
uniform bool sun_glow_enabled = true;
uniform vec3 sun_direction = vec3(0.0, 1.0, 0.0);
uniform vec4 sun_glow_color : source_color = vec4(1.0, 0.95, 0.8, 1.0);
uniform float sun_glow_intensity = 0.5;
uniform float sun_glow_size = 0.2;
uniform float sun_glow_falloff = 2.0;
uniform bool dawn_dusk_enabled = true;
uniform vec4 dawn_dusk_color : source_color = vec4(1.0, 0.6, 0.4, 1.0);
uniform float dawn_dusk_intensity = 0.5;
uniform float dawn_dusk_blend = 0.0;
uniform float stars_visibility = 0.0;
uniform vec4 stars_tint : source_color = vec4(1.0);
float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}
float stars(vec3 dir) {
vec2 uv = dir.xz / (abs(dir.y) + 0.001) * 50.0;
vec2 cell = floor(uv);
vec2 local = fract(uv) - 0.5;
float star = 0.0;
float h = hash(cell);
if (h > 0.97) {
float dist = length(local);
star = smoothstep(0.1, 0.0, dist) * (h - 0.97) / 0.03;
star *= step(0.0, dir.y);
}
return star;
}
vec2 pano_uv(vec3 dir) {
dir = normalize(dir);
float u = atan(dir.x, dir.z) / (2.0 * PI) + 0.5;
float v = acos(clamp(dir.y, -1.0, 1.0)) / PI;
return vec2(u, v);
}
void sky() {
vec3 dir = EYEDIR;
float y = dir.y;
vec3 color;
if (y > 0.0) {
float t = pow(y, horizon_blend);
color = mix(sky_horizon_color.rgb, sky_top_color.rgb, t);
} else {
float t = pow(-y, horizon_blend);
color = mix(sky_horizon_color.rgb, sky_bottom_color.rgb, t);
}
color = mix(vec3(0.5), color, gradient_intensity);
if (skybox_enabled) {
vec3 pano_color = texture(skybox_texture, pano_uv(dir)).rgb;
color = mix(color, pano_color, skybox_blend);
}
if (sun_glow_enabled && sun_direction.y > -0.2) {
float sun_dot = max(0.0, dot(dir, normalize(sun_direction)));
float glow = pow(sun_dot, 1.0 / max(0.001, sun_glow_size));
glow = pow(glow, sun_glow_falloff);
color += sun_glow_color.rgb * glow * sun_glow_intensity;
}
if (dawn_dusk_enabled && dawn_dusk_blend > 0.0) {
float horizon_factor = 1.0 - abs(y);
horizon_factor = pow(horizon_factor, 2.0);
color = mix(color, dawn_dusk_color.rgb, horizon_factor * dawn_dusk_intensity * dawn_dusk_blend);
}
if (stars_visibility > 0.0 && y > 0.0) {
float star_value = stars(dir) * stars_visibility;
color += stars_tint.rgb * star_value;
}
COLOR = color;
}
"""
return shader
func _update_sky_material() -> void:
if _sky_material == null:
return
if skybox_texture:
_sky_material.set_shader_parameter("skybox_enabled", true)
_sky_material.set_shader_parameter("skybox_texture", skybox_texture)
_sky_material.set_shader_parameter("skybox_blend", skybox_blend)
else:
_sky_material.set_shader_parameter("skybox_enabled", false)
_sky_material.set_shader_parameter("skybox_blend", skybox_blend)
_sky_material.set_shader_parameter("sky_top_color", sky_top_color)
_sky_material.set_shader_parameter("sky_horizon_color", sky_horizon_color)
_sky_material.set_shader_parameter("sky_bottom_color", sky_bottom_color)
_sky_material.set_shader_parameter("gradient_intensity", gradient_intensity)
_sky_material.set_shader_parameter("sun_glow_enabled", sun_glow_enabled and effects_enabled)
_sky_material.set_shader_parameter("sun_direction", sun_direction)
_sky_material.set_shader_parameter("sun_glow_color", sun_glow_color)
_sky_material.set_shader_parameter("sun_glow_intensity", sun_glow_intensity)
_sky_material.set_shader_parameter("sun_glow_size", sun_glow_size)
_sky_material.set_shader_parameter("sun_glow_falloff", sun_glow_falloff)
_sky_material.set_shader_parameter("dawn_dusk_enabled", dawn_dusk_enabled and effects_enabled)
_sky_material.set_shader_parameter("dawn_dusk_blend", dawn_dusk_blend)
_sky_material.set_shader_parameter("dawn_dusk_intensity", dawn_dusk_intensity)
func set_sky_colors(top: Color, horizon: Color, bottom: Color) -> void:
sky_top_color = top
sky_horizon_color = horizon
sky_bottom_color = bottom
_update_sky_material()
func set_fog_settings(color: Color, density: float) -> void:
fog_color = color
fog_density = density
_update_fog()
func set_sun_glow(direction: Vector3, color: Color, intensity: float, size: float) -> void:
sun_direction = direction.normalized()
sun_glow_color = color
sun_glow_intensity = intensity
sun_glow_size = size
_update_sky_material()
func set_dawn_dusk_blend(blend: float) -> void:
dawn_dusk_blend = clampf(blend, 0.0, 1.0)
_update_sky_material()
func set_stars_visibility(visibility: float, tint: Color = Color.WHITE) -> void:
if _sky_material:
_sky_material.set_shader_parameter("stars_visibility", visibility)
_sky_material.set_shader_parameter("stars_tint", tint)
func set_effects_enabled(enabled: bool) -> void:
effects_enabled = enabled
_update_fog()
_update_sky_material()
func apply_config(config: SkyConfig) -> void:
sky_top_color = config.sky_top_color
sky_horizon_color = config.sky_horizon_color
sky_bottom_color = config.sky_bottom_color
fog_color = config.fog_color
fog_density = config.fog_density
sun_glow_intensity = config.sun_glow_intensity
sun_glow_size = config.sun_glow_size
gradient_intensity = config.gradient_intensity
_update_fog()
_update_sky_material()
set_stars_visibility(config.stars_visibility, config.stars_tint)