@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 _moon_direction: Vector3 = Vector3(0.0, -1.0, 0.0) var _moon_color: Color = Color(0.9, 0.92, 1.0) var _moon_intensity: float = 0.0 var _moon_size: float = 0.03 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 vec3 moon_direction = vec3(0.0, -1.0, 0.0); uniform vec4 moon_color : source_color = vec4(0.9, 0.92, 1.0, 1.0); uniform float moon_intensity = 0.0; uniform float moon_size = 0.03; 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; } if (moon_intensity > 0.0 && moon_direction.y > 0.0) { vec3 moon_dir = normalize(moon_direction); float moon_dot = dot(dir, moon_dir); float disc = smoothstep(1.0 - moon_size, 1.0 - moon_size * 0.6, moon_dot); float glow = pow(max(0.0, moon_dot), 32.0) * 0.15; color += moon_color.rgb * disc * moon_intensity + moon_color.rgb * glow * moon_intensity * 0.5; } 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) _sky_material.set_shader_parameter("moon_direction", _moon_direction) _sky_material.set_shader_parameter("moon_color", _moon_color) _sky_material.set_shader_parameter("moon_intensity", _moon_intensity) _sky_material.set_shader_parameter("moon_size", _moon_size) 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_moon(direction: Vector3, color: Color, intensity: float, size: float = 0.03) -> void: _moon_direction = direction.normalized() _moon_color = color _moon_intensity = intensity _moon_size = size _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)