202 lines
5.7 KiB
GDScript
202 lines
5.7 KiB
GDScript
@tool
|
|
extends Node3D
|
|
class_name VFXController
|
|
|
|
## Works only in the editor. By default works like "emitting" on particles. When one_shot is enabled works as a button.
|
|
@export var preview : bool = true:
|
|
set(value):
|
|
if Engine.is_editor_hint():
|
|
if one_shot && value == true:
|
|
play()
|
|
else:
|
|
preview = value
|
|
if value == true:
|
|
play()
|
|
|
|
@export var one_shot : bool = false:
|
|
set(value):
|
|
if Engine.is_editor_hint():
|
|
one_shot = value
|
|
preview = false
|
|
|
|
@export var autoplay : bool = true
|
|
|
|
@export_group("General")
|
|
@export var local_coords : bool = false:
|
|
set(value):
|
|
local_coords = value
|
|
for p in _get_particles(): if is_instance_valid(p): p.local_coords = value
|
|
@export_range(0, 10, 0.01) var speed_scale : float = 1.0:
|
|
set(value):
|
|
speed_scale = value
|
|
_set_shader_params("time_scale", speed_scale)
|
|
_get_anim().speed_scale = value
|
|
for p in _get_particles(): if is_instance_valid(p): p.speed_scale = value
|
|
|
|
@export_group("Colors")
|
|
@export var primary_color : Color:
|
|
set(value):
|
|
primary_color = value
|
|
_set_shader_params("primary_color", primary_color)
|
|
@export var secondary_color : Color:
|
|
set(value):
|
|
secondary_color = value
|
|
_set_shader_params("secondary_color", secondary_color)
|
|
@export var tertiary_color : Color:
|
|
set(value):
|
|
tertiary_color = value
|
|
_set_shader_params("tertiary_color", tertiary_color)
|
|
|
|
@export_group("Light")
|
|
@export var light_enable : bool = true:
|
|
set(value):
|
|
light_enable = value
|
|
_set_light_prop("visible", value)
|
|
@export var light_color : Color:
|
|
set(value):
|
|
light_color = value
|
|
_set_light_prop("light_color", value)
|
|
@export var light_energy : float = 4.0:
|
|
set(value):
|
|
light_energy = value
|
|
_set_light_prop("base_energy", value)
|
|
@export var light_indirect_energy : float = 1.0:
|
|
set(value):
|
|
light_indirect_energy = value
|
|
_set_light_prop("light_indirect_energy", value)
|
|
@export var light_volumetric_fog_energy : float = 1.0:
|
|
set(value):
|
|
light_volumetric_fog_energy = value
|
|
_set_light_prop("light_volumetric_fog_energy", value)
|
|
|
|
@export_group("Proximity Fade")
|
|
@export var proximity_fade : bool = false:
|
|
set(value):
|
|
proximity_fade = value
|
|
_set_shader_params("proximity_fade", proximity_fade)
|
|
@export var proximity_fade_distance : float = 1.0:
|
|
set(value):
|
|
proximity_fade_distance = value
|
|
_set_shader_params("proximity_fade_distance", proximity_fade_distance)
|
|
|
|
|
|
@export_group("LODs")
|
|
enum Alpha_Mode {
|
|
## Smooth transparency. Most performance intensive
|
|
SMOOTH,
|
|
## Displays transparency with a dithering pattern. Less performance intensive
|
|
DITHER,
|
|
## Hard cut alpha. Like "Alpha Scissor" in [b]SpatialMaterial[/b]. Least performance intensive
|
|
CUT,
|
|
## Uses dithering and hard cut to achieve better results
|
|
HYBRID
|
|
}
|
|
## Specifies how to handle [b]transparency[/b] within shaders.
|
|
@export var alpha_mode : Alpha_Mode = Alpha_Mode.SMOOTH:
|
|
set(value):
|
|
alpha_mode = value
|
|
_set_shader_params("alpha_mode", alpha_mode)
|
|
@export_range(0.0,1.0,0.01) var alpha_cutoff : float = 0.02:
|
|
set(value):
|
|
alpha_cutoff = value
|
|
_set_shader_params("alpha_cutoff", alpha_cutoff)
|
|
@export_range(0.0,1.0,0.01) var dither_cutoff : float = 0.8:
|
|
set(value):
|
|
dither_cutoff = value
|
|
_set_shader_params("dither_cutoff", dither_cutoff)
|
|
## Specify resolution of meshes.
|
|
## [br][br]
|
|
## [b]SphereMesh:[/b] Sets [code]radial_segments[/code] to the [b]value[/b] and
|
|
## [code]rings[/code] to [b]half the value[/b]
|
|
## [br][br]
|
|
## [b]CylinderMesh:[/b] Sets [code]radial_segments[/code] to the [b]value[/b]
|
|
## [br][br]
|
|
## [b]PlaneMesh:[/b] Sets [code]subdivide_width[/code] and [code]subdivide_depth[/code] to the [b]value[/b]
|
|
@export var mesh_resolutions : int = 32:
|
|
set(value):
|
|
mesh_resolutions = value
|
|
_set_mesh_resolutions(mesh_resolutions)
|
|
|
|
var particles : Array[GPUParticles3D] = []
|
|
|
|
func _ready() -> void:
|
|
if Engine.is_editor_hint():
|
|
return
|
|
|
|
if autoplay: play()
|
|
|
|
func _enter_tree() -> void:
|
|
if autoplay: preview = true
|
|
|
|
func play():
|
|
var anim : AnimationPlayer = _get_anim()
|
|
_reset_particles()
|
|
if !one_shot:
|
|
anim.play("main")
|
|
anim.seek(0.0)
|
|
await _get_anim().animation_finished
|
|
if Engine.is_editor_hint() && !preview:
|
|
return
|
|
play()
|
|
else:
|
|
if anim.has_animation("oneshot"):
|
|
anim.play("oneshot")
|
|
else:
|
|
anim.play("main")
|
|
|
|
## Util
|
|
func _get_anim() -> AnimationPlayer:
|
|
return get_node("AnimationPlayer")
|
|
|
|
func _get_particles() -> Array[GPUParticles3D]:
|
|
var result : Array[GPUParticles3D] = []
|
|
for p in get_children():
|
|
if p is GPUParticles3D:
|
|
result.append(p)
|
|
return result
|
|
|
|
func _get_meshinstances() -> Array[MeshInstance3D]:
|
|
var result : Array[MeshInstance3D] = []
|
|
for m in get_children():
|
|
if m is MeshInstance3D:
|
|
result.append(m)
|
|
return result
|
|
|
|
func _get_meshes() -> Array[Mesh]:
|
|
var result : Array[Mesh]
|
|
for p in _get_particles(): if is_instance_valid(p):
|
|
result.append(p.draw_pass_1)
|
|
for m in _get_meshinstances(): if is_instance_valid(m):
|
|
result.append(m.mesh)
|
|
return result
|
|
|
|
func _set_light_prop(pname : String, value) -> void:
|
|
var light = get_node_or_null("Light")
|
|
if light != null:
|
|
light.set(pname, value)
|
|
|
|
func _reset_particles():
|
|
for p in _get_particles():
|
|
p.restart()
|
|
|
|
func _set_shader_params(name : String, value) -> void:
|
|
for p in _get_particles():
|
|
if is_instance_valid(p):
|
|
if p.material_override is ShaderMaterial:
|
|
p.material_override.set("shader_parameter/" + name, value)
|
|
for m in _get_meshinstances():
|
|
if is_instance_valid(m):
|
|
if m.material_override is ShaderMaterial:
|
|
m.material_override.set("shader_parameter/" + name, value)
|
|
|
|
func _set_mesh_resolutions(value : int) -> void:
|
|
for m in _get_meshes(): if is_instance_valid(m):
|
|
if m is SphereMesh:
|
|
m.radial_segments = value
|
|
m.rings = value/2
|
|
if m is CylinderMesh:
|
|
m.radial_segments = value
|
|
if m is PlaneMesh:
|
|
m.subdivide_width = value
|
|
m.subdivide_depth = value
|