extends Node3D @export_group("Animation") @export var life_time: float = 8.0 @export var fade_in_time: float = 4.0 @export var max_base_alpha: float = 1.0 var _visual_scale: Vector3 = Vector3.ONE var _visual_rotation_degrees: Vector3 = Vector3.ZERO var _mesh_base_position: Vector3 = Vector3.ZERO var _mesh_base_rotation_degrees: Vector3 = Vector3.ZERO var _mesh_base_scale: Vector3 = Vector3.ONE @onready var godrays_mesh: MeshInstance3D = $GodRays func _ready(): _mesh_base_position = godrays_mesh.position _mesh_base_rotation_degrees = godrays_mesh.rotation_degrees _mesh_base_scale = godrays_mesh.scale _apply_visual_transform() var mat: ShaderMaterial = godrays_mesh.get_active_material(0).duplicate() godrays_mesh.set_surface_override_material(0, mat) #set alpha to 0 before first frame to avoid "pop" mat.set_shader_parameter("base_alpha", 0.0) orient_to_camera() animate_godray(mat) func _process(_delta: float) -> void: orient_to_camera() func set_visual_rotation_degrees(value: Vector3) -> void: _visual_rotation_degrees = value if is_node_ready(): _apply_visual_transform() func set_visual_scale(value: Vector3) -> void: _visual_scale = value if is_node_ready(): _apply_visual_transform() func orient_to_camera() -> void: var current_camera: Camera3D = get_viewport().get_camera_3d() if current_camera == null or not is_instance_valid(current_camera): return var look_direction: Vector3 = current_camera.global_basis.z if look_direction.is_zero_approx(): return # Use the camera orientation instead of its position so every godray keeps # the same diagonal on screen, even when multiple rays are visible together. look_at(global_position + look_direction, current_camera.global_basis.y, true) func _apply_visual_transform() -> void: godrays_mesh.position = _mesh_base_position godrays_mesh.rotation_degrees = _mesh_base_rotation_degrees + _visual_rotation_degrees godrays_mesh.scale = Vector3( _mesh_base_scale.x * _visual_scale.x, _mesh_base_scale.y * _visual_scale.y, _mesh_base_scale.z * _visual_scale.z ) func animate_godray(mat: ShaderMaterial): var tween_alpha = create_tween() tween_alpha.tween_property(mat, "shader_parameter/base_alpha", max_base_alpha, fade_in_time).from(0.0) var tween_intensity = create_tween() #tween from 1.0 to 2.0 tween_intensity.tween_property(mat, "shader_parameter/intensity_multiplier", 0.2, life_time * 0.3).from(1.0) #tween to 0.5 tween_intensity.tween_property(mat, "shader_parameter/intensity_multiplier", 0.5, life_time * 0.3) #tween to 0.0 tween_intensity.tween_property(mat, "shader_parameter/intensity_multiplier", 0.0, life_time * 0.4) tween_intensity.tween_callback(queue_free) var tween_edge = create_tween() tween_edge.tween_property(mat, "shader_parameter/edge_fade_power", 0.5, life_time * 0.5).from(2.0) tween_edge.tween_property(mat, "shader_parameter/edge_fade_power", 2.0, life_time * 0.5)