MagicNStuff/source/addons/SunshineClouds2/SunshineCloudsDriver.gd

273 lines
11 KiB
GDScript

@tool
@icon("res://addons/SunshineClouds2/CloudsDriverIcon.svg")
extends Node
class_name SunshineCloudsDriverGD
@export var update_continuously: bool = false:
get:
return update_continuously
set(value):
update_continuously = value
retrieve_texture_data()
@export_tool_button("Generate Clouds Resource", "Add") var generate_action = build_new_clouds
#@export_tool_button("Test Clouds Position Sample", "Add") var position_sample = sample_clouds
@export_group("Compositor Resource")
@export var clouds_resource: SunshineCloudsGD
@export_group("Optional World Environment")
@export var ambience_sample_environment: Environment
@export var use_enviornment_ambience_for_fog: bool = false
@export_group("Light Controls")
@export var tracked_directional_lights: Array[DirectionalLight3D] = []:
get:
return tracked_directional_lights
set(value):
tracked_directional_lights = value
retrieve_texture_data()
@export var tracked_directional_light_shadow_steps: Array[int] = []:
get:
return tracked_directional_light_shadow_steps
set(value):
tracked_directional_light_shadow_steps = value
retrieve_texture_data()
@export var tracked_point_lights: Array[OmniLight3D] = []:
get:
return tracked_point_lights
set(value):
tracked_point_lights = value
retrieve_texture_data()
@export var tracked_point_effectors: Array[SunshineCloudsEffector] = []:
get:
return tracked_point_effectors
set(value):
tracked_point_effectors = value
retrieve_texture_data()
@export var directional_light_power_multiplier: float = 1.0
@export var point_light_power_multiplier: float = 1.0
@export_group("Wind Controls")
@export var origin_offset : Vector3 = Vector3.ZERO
@export var wind_direction: Vector3 = Vector3(1.0, 0.0, 1.0)
@export var extra_large_structures_wind_speed: float = 140.0
@export var large_structures_wind_speed: float = 100.0
@export var medium_structures_wind_speed: float = 40.0
@export var small_structures_wind_speed: float = 12.0
@export_group("Internal Use")
var extra_large_clouds_pos: Vector3 = Vector3.ZERO
var large_clouds_pos: Vector3 = Vector3.ZERO
var medium_clouds_pos: Vector3 = Vector3.ZERO
var small_clouds_pos: Vector3 = Vector3.ZERO
var _extralarge_clouds_domain: float = 0.0
var _large_clouds_domain: float = 0.0
var _medium_clouds_domain: float = 0.0
var _small_clouds_domain: float = 0.0
var _updating_settings: bool = false
func _ready():
if update_continuously:
if clouds_resource == null:
update_continuously = false
return
call_deferred("retrieve_texture_data")
func _process(delta : float):
if clouds_resource != null:
clouds_resource.current_time = wrap(clouds_resource.current_time + delta * clouds_resource.dither_speed, 0.0, clouds_resource.dither_speed * 64.0)
if update_continuously:
_updating_settings = false
extra_large_clouds_pos += wind_direction * extra_large_structures_wind_speed * delta
extra_large_clouds_pos = wrap_vector(extra_large_clouds_pos, _extralarge_clouds_domain)
large_clouds_pos += wind_direction * large_structures_wind_speed * delta
large_clouds_pos = wrap_vector(large_clouds_pos, _large_clouds_domain)
medium_clouds_pos += wind_direction * medium_structures_wind_speed * delta
medium_clouds_pos = wrap_vector(medium_clouds_pos, _medium_clouds_domain)
small_clouds_pos += ((wind_direction * small_structures_wind_speed) + (Vector3.UP * abs(small_structures_wind_speed))) * delta
small_clouds_pos = wrap_vector(small_clouds_pos, _small_clouds_domain)
clouds_resource.origin_offset = origin_offset
clouds_resource.extra_large_scale_clouds_position = origin_offset + extra_large_clouds_pos
clouds_resource.large_scale_clouds_position = origin_offset + large_clouds_pos
clouds_resource.medium_scale_clouds_position = origin_offset + medium_clouds_pos
clouds_resource.detail_clouds_position = origin_offset + small_clouds_pos
clouds_resource.wind_direction = wind_direction
if use_enviornment_ambience_for_fog and ambience_sample_environment != null:
clouds_resource.atmosphere_color = ambience_sample_environment.fog_light_color
clouds_resource.cloud_ambient_color = ambience_sample_environment.fog_light_color
if (tracked_directional_lights.size() * 2.0 != clouds_resource.directional_lights_data.size() \
or tracked_point_lights.size() * 2.0 != clouds_resource.point_lights_data.size()\
or tracked_directional_lights.size() != tracked_directional_light_shadow_steps.size()):
retrieve_texture_data()
return
for i in range(tracked_directional_lights.size()):
if tracked_directional_lights[i] == null:
continue
if direction_light_data_changed(tracked_directional_lights[i], tracked_directional_light_shadow_steps[i], clouds_resource.directional_lights_data[i * 2], clouds_resource.directional_lights_data[i * 2 + 1]):
retrieve_texture_data()
return
for i in range(tracked_point_lights.size()):
if tracked_point_lights[i] == null:
continue
if point_light_data_changed(tracked_point_lights[i], clouds_resource.point_lights_data[i * 2], clouds_resource.point_lights_data[i * 2 + 1]):
retrieve_texture_data()
return
for i in range(tracked_point_effectors.size()):
if tracked_point_effectors[i] == null:
continue
if point_effector_data_changed(tracked_point_effectors[i], clouds_resource.point_effector_data[i * 2], clouds_resource.point_effector_data[i * 2 + 1]):
retrieve_texture_data()
return
else:
update_continuously = false
func sample_clouds():
for i in range(64):
clouds_resource.add_sample(return_data.bind(), Vector3(i * 1000, 6000.0, 0.0))
func return_data(position : Vector3, sampledensity : float):
print(position, " ", sampledensity)
pass
func build_new_clouds():
if (is_inside_tree()):
var env : WorldEnvironment = recursively_find_env(get_tree().root)
if (env):
if not ambience_sample_environment:
ambience_sample_environment = env.environment
var newClouds = SunshineCloudsGD.new()
ResourceSaver.save(newClouds, "res://NewCloudsGD.tres")
clouds_resource = ResourceLoader.load("res://NewCloudsGD.tres")
if not env.compositor:
env.compositor = Compositor.new()
env.compositor.compositor_effects = [clouds_resource]
update_continuously = true
else:
printerr("No world environment found.")
func recursively_find_env(thisNode: Node) -> WorldEnvironment:
for child in thisNode.get_children():
if child is WorldEnvironment:
return child
else:
var result = recursively_find_env(child)
if (result):
return result
return null
func retrieve_texture_data():
if _updating_settings || !is_inside_tree():
return
_updating_settings = true
if clouds_resource != null:
_extralarge_clouds_domain = clouds_resource.extra_large_noise_scale / 2.0
_large_clouds_domain = clouds_resource.large_noise_scale / 2.0
_medium_clouds_domain = clouds_resource.medium_noise_scale / 2.0
_small_clouds_domain = clouds_resource.small_noise_scale / 2.0
clouds_resource.directional_lights_data.clear()
clouds_resource.point_lights_data.clear()
clouds_resource.point_effector_data.clear()
if not tracked_directional_light_shadow_steps:
tracked_directional_light_shadow_steps = []
if tracked_directional_light_shadow_steps.size() < tracked_directional_lights.size():
for i in range(tracked_directional_lights.size() - tracked_directional_light_shadow_steps.size()):
tracked_directional_light_shadow_steps.append(12)
for i in range(tracked_directional_lights.size()):
if tracked_directional_lights[i] != null:
var light = tracked_directional_lights[i]
var look_dir = light.global_transform.basis.z.normalized()
clouds_resource.directional_lights_data.append(Vector4(look_dir.x, look_dir.y, look_dir.z, tracked_directional_light_shadow_steps[i]))
clouds_resource.directional_lights_data.append(Vector4(light.light_color.r, light.light_color.g, light.light_color.b, round(light.light_color.a * light.light_energy * directional_light_power_multiplier * 10.0) / 10.0))
for i in range(tracked_point_lights.size()):
if tracked_point_lights[i] != null:
var light = tracked_point_lights[i]
var light_pos = light.global_position
clouds_resource.point_lights_data.append(Vector4(light_pos.x, light_pos.y, light_pos.z, light.omni_range))
clouds_resource.point_lights_data.append(Vector4(light.light_color.r, light.light_color.g, light.light_color.b, round(light.light_color.a * light.light_energy * point_light_power_multiplier * 10.0) / 10.0))
for i in range(tracked_point_effectors.size()):
if tracked_point_effectors[i] != null:
var node = tracked_point_effectors[i]
var node_pos = node.global_position
clouds_resource.point_effector_data.append(Vector4(node_pos.x, node_pos.y, node_pos.z, node.Radius))
clouds_resource.point_effector_data.append(Vector4(node.Power, 0.0, 0.0, 0.0))
clouds_resource.lights_updated = true
_updating_settings = false
func wrap_vector(target, domain_size):
if target.x > domain_size:
target.x -= domain_size * 2.0
elif target.x < -domain_size:
target.x += domain_size * 2.0
if target.y > domain_size:
target.y -= domain_size * 2.0
elif target.y < -domain_size:
target.y += domain_size * 2.0
if target.z > domain_size:
target.z -= domain_size * 2.0
elif target.z < -domain_size:
target.z += domain_size * 2.0
return target
func direction_light_data_changed(light : DirectionalLight3D, shadowCount : int, dirData : Vector4, colorData : Vector4):
return light.global_transform.basis.z.x != dirData.x \
or light.global_transform.basis.z.y != dirData.y \
or light.global_transform.basis.z.z != dirData.z \
or float(shadowCount) != dirData.w \
or light.light_color.r != colorData.x \
or light.light_color.g != colorData.y \
or light.light_color.b != colorData.z \
or round(light.light_color.a * light.light_energy * directional_light_power_multiplier * 10.0) / 10.0 != round(colorData.w * 10.0) / 10.0
func point_light_data_changed(light : OmniLight3D, dirData : Vector4, colorData : Vector4):
return light.global_position.x != dirData.x \
or light.global_position.y != dirData.y \
or light.global_position.z != dirData.z \
or light.omni_range != dirData.w \
or light.light_color.r != colorData.x \
or light.light_color.g != colorData.y \
or light.light_color.b != colorData.z \
or round(light.light_color.a * light.light_energy * point_light_power_multiplier * 10.0) / 10.0 != round(colorData.w * 10.0) / 10.0
func point_effector_data_changed(node : SunshineCloudsEffector, dirData : Vector4, colorData : Vector4):
return node.global_position.x != dirData.x \
or node.global_position.y != dirData.y \
or node.global_position.z != dirData.z \
or node.Radius != dirData.w \
or node.Power != colorData.x