Start dynamic sky
This commit is contained in:
220
dynamic-sky/scripts/shadow_proxy_system.gd
Normal file
220
dynamic-sky/scripts/shadow_proxy_system.gd
Normal file
@@ -0,0 +1,220 @@
|
||||
@tool
|
||||
class_name ShadowProxySystem
|
||||
extends Node3D
|
||||
|
||||
@export_group("Shadow Settings")
|
||||
@export var enabled: bool = true:
|
||||
set(value):
|
||||
enabled = value
|
||||
if _shadow_mesh:
|
||||
_shadow_mesh.visible = enabled
|
||||
|
||||
@export var shadow_texture: Texture2D:
|
||||
set(value):
|
||||
shadow_texture = value
|
||||
_update_shadow_texture()
|
||||
|
||||
@export var shadow_opacity: float = 0.3:
|
||||
set(value):
|
||||
shadow_opacity = clampf(value, 0.0, 1.0)
|
||||
_update_shadow_material()
|
||||
|
||||
@export var shadow_color: Color = Color(0.0, 0.0, 0.1):
|
||||
set(value):
|
||||
shadow_color = value
|
||||
_update_shadow_material()
|
||||
|
||||
@export_group("Movement")
|
||||
@export var flow_direction: Vector2 = Vector2(1.0, 0.0)
|
||||
@export var flow_speed: float = 5.0
|
||||
@export var sync_with_clouds: bool = true
|
||||
|
||||
@export_group("Projection")
|
||||
@export var projection_size: float = 500.0:
|
||||
set(value):
|
||||
projection_size = value
|
||||
_update_projection_size()
|
||||
|
||||
@export var projection_height: float = 0.1
|
||||
@export var tiling: Vector2 = Vector2(2.0, 2.0):
|
||||
set(value):
|
||||
tiling = value
|
||||
_update_shadow_material()
|
||||
|
||||
@export_group("Blur")
|
||||
@export var blur_enabled: bool = true
|
||||
@export var blur_amount: float = 0.5:
|
||||
set(value):
|
||||
blur_amount = clampf(value, 0.0, 1.0)
|
||||
_update_shadow_material()
|
||||
|
||||
@export_group("Performance")
|
||||
@export var follow_camera: bool = true
|
||||
@export var update_distance: float = 50.0
|
||||
|
||||
var _shadow_mesh: MeshInstance3D
|
||||
var _shadow_material: ShaderMaterial
|
||||
var _uv_offset: Vector2 = Vector2.ZERO
|
||||
var _last_camera_position: Vector3 = Vector3.ZERO
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_create_shadow_mesh()
|
||||
_create_shadow_material()
|
||||
_update_shadow_material()
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not enabled:
|
||||
return
|
||||
|
||||
_update_flow(delta)
|
||||
|
||||
if follow_camera:
|
||||
_follow_camera()
|
||||
|
||||
|
||||
func _create_shadow_mesh() -> void:
|
||||
if _shadow_mesh:
|
||||
_shadow_mesh.queue_free()
|
||||
|
||||
_shadow_mesh = MeshInstance3D.new()
|
||||
_shadow_mesh.name = "CloudShadowMesh"
|
||||
|
||||
var plane := PlaneMesh.new()
|
||||
plane.size = Vector2(projection_size, projection_size)
|
||||
_shadow_mesh.mesh = plane
|
||||
|
||||
_shadow_mesh.position.y = projection_height
|
||||
_shadow_mesh.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
|
||||
add_child(_shadow_mesh)
|
||||
|
||||
|
||||
func _create_shadow_material() -> void:
|
||||
_shadow_material = ShaderMaterial.new()
|
||||
_shadow_material.shader = _get_shadow_shader()
|
||||
|
||||
if _shadow_mesh:
|
||||
_shadow_mesh.material_override = _shadow_material
|
||||
|
||||
|
||||
func _get_shadow_shader() -> Shader:
|
||||
var shader := Shader.new()
|
||||
shader.code = """
|
||||
shader_type spatial;
|
||||
render_mode unshaded, depth_draw_opaque, cull_disabled, shadows_disabled;
|
||||
|
||||
uniform sampler2D shadow_texture : source_color, filter_linear_mipmap, repeat_enable;
|
||||
uniform vec4 shadow_color : source_color = vec4(0.0, 0.0, 0.1, 1.0);
|
||||
uniform float opacity = 0.3;
|
||||
uniform vec2 tiling = vec2(2.0, 2.0);
|
||||
uniform vec2 uv_offset = vec2(0.0, 0.0);
|
||||
uniform float blur_amount = 0.5;
|
||||
uniform float edge_fade = 0.1;
|
||||
|
||||
varying vec2 world_uv;
|
||||
|
||||
void vertex() {
|
||||
world_uv = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xz;
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
vec2 uv = world_uv * tiling * 0.001 + uv_offset;
|
||||
|
||||
vec4 shadow_sample;
|
||||
if (blur_amount > 0.01) {
|
||||
float blur = blur_amount * 0.01;
|
||||
shadow_sample = texture(shadow_texture, uv) * 0.25;
|
||||
shadow_sample += texture(shadow_texture, uv + vec2(blur, 0.0)) * 0.125;
|
||||
shadow_sample += texture(shadow_texture, uv - vec2(blur, 0.0)) * 0.125;
|
||||
shadow_sample += texture(shadow_texture, uv + vec2(0.0, blur)) * 0.125;
|
||||
shadow_sample += texture(shadow_texture, uv - vec2(0.0, blur)) * 0.125;
|
||||
shadow_sample += texture(shadow_texture, uv + vec2(blur, blur)) * 0.0625;
|
||||
shadow_sample += texture(shadow_texture, uv - vec2(blur, blur)) * 0.0625;
|
||||
shadow_sample += texture(shadow_texture, uv + vec2(blur, -blur)) * 0.0625;
|
||||
shadow_sample += texture(shadow_texture, uv + vec2(-blur, blur)) * 0.0625;
|
||||
} else {
|
||||
shadow_sample = texture(shadow_texture, uv);
|
||||
}
|
||||
|
||||
float shadow_value = shadow_sample.r;
|
||||
|
||||
vec2 local_uv = fract(world_uv * 0.001);
|
||||
float edge = smoothstep(0.0, edge_fade, local_uv.x);
|
||||
edge *= smoothstep(0.0, edge_fade, local_uv.y);
|
||||
edge *= smoothstep(0.0, edge_fade, 1.0 - local_uv.x);
|
||||
edge *= smoothstep(0.0, edge_fade, 1.0 - local_uv.y);
|
||||
|
||||
ALBEDO = shadow_color.rgb;
|
||||
ALPHA = shadow_value * opacity * edge;
|
||||
}
|
||||
"""
|
||||
return shader
|
||||
|
||||
|
||||
func _update_shadow_material() -> void:
|
||||
if _shadow_material == null:
|
||||
return
|
||||
|
||||
_shadow_material.set_shader_parameter("shadow_color", shadow_color)
|
||||
_shadow_material.set_shader_parameter("opacity", shadow_opacity)
|
||||
_shadow_material.set_shader_parameter("tiling", tiling)
|
||||
_shadow_material.set_shader_parameter("blur_amount", blur_amount if blur_enabled else 0.0)
|
||||
|
||||
|
||||
func _update_shadow_texture() -> void:
|
||||
if _shadow_material and shadow_texture:
|
||||
_shadow_material.set_shader_parameter("shadow_texture", shadow_texture)
|
||||
|
||||
|
||||
func _update_projection_size() -> void:
|
||||
if _shadow_mesh and _shadow_mesh.mesh is PlaneMesh:
|
||||
var plane := _shadow_mesh.mesh as PlaneMesh
|
||||
plane.size = Vector2(projection_size, projection_size)
|
||||
|
||||
|
||||
func _update_flow(delta: float) -> void:
|
||||
_uv_offset += flow_direction * flow_speed * delta * 0.001
|
||||
_uv_offset.x = fmod(_uv_offset.x, 1.0)
|
||||
_uv_offset.y = fmod(_uv_offset.y, 1.0)
|
||||
|
||||
if _shadow_material:
|
||||
_shadow_material.set_shader_parameter("uv_offset", _uv_offset)
|
||||
|
||||
|
||||
func _follow_camera() -> void:
|
||||
var camera := get_viewport().get_camera_3d()
|
||||
if camera == null:
|
||||
return
|
||||
|
||||
var camera_pos := camera.global_position
|
||||
var distance := camera_pos.distance_to(_last_camera_position)
|
||||
|
||||
if distance >= update_distance:
|
||||
_last_camera_position = camera_pos
|
||||
global_position.x = camera_pos.x
|
||||
global_position.z = camera_pos.z
|
||||
|
||||
|
||||
func set_flow(direction: Vector2, speed: float) -> void:
|
||||
flow_direction = direction.normalized()
|
||||
flow_speed = speed
|
||||
|
||||
|
||||
func set_shadow_appearance(color: Color, opacity_value: float, blur: float) -> void:
|
||||
shadow_color = color
|
||||
shadow_opacity = opacity_value
|
||||
blur_amount = blur
|
||||
_update_shadow_material()
|
||||
|
||||
|
||||
func sync_with_cloud_system(cloud_system: CloudSystem2D) -> void:
|
||||
if sync_with_clouds and cloud_system:
|
||||
flow_direction = cloud_system.global_wind_direction
|
||||
flow_speed = cloud_system.global_wind_speed * 5.0
|
||||
|
||||
|
||||
func set_cloud_coverage(coverage: float) -> void:
|
||||
shadow_opacity = coverage * 0.5
|
||||
_update_shadow_material()
|
||||
Reference in New Issue
Block a user