diff --git a/GPUTrail3D.gd b/GPUTrail3D.gd index 242f93a..0e93cee 100644 --- a/GPUTrail3D.gd +++ b/GPUTrail3D.gd @@ -20,6 +20,10 @@ class_name GPUTrail3D extends GPUParticles3D # PUBLIC +## Active determines if the trails render or not +@export var active := true : set = _set_active + +@export_category("Length") ## Length is the number of steps in the trail @export var length : int = 100 : set = _set_length @export var length_seconds : float : set = _set_length @@ -53,6 +57,26 @@ class_name GPUTrail3D extends GPUParticles3D ## Enable [member use_red_as_alpha] to use the red color channel of [member texture] as alpha @export var use_red_as_alpha := false : set = _set_use_red_as_alpha +## An independent alpha value to control total trail transparency. Is also modified if using Fade In Seconds or Fade Out Seconds +@export var alpha : float = 1.0 : set = _set_alpha + + +@export_category("Fade") +## Fade Curve is a texture that is used to determine the alpha of the trail over it's lifetime +@export var fade_curve : CurveTexture : set = _set_fade_curve +## Fade Curve Intensity is a value used to modify the strength of the Fade Curve +@export var fade_curve_intensity: float = 1.0 : set = _set_fade_curve_intensity + +## Fade In Seconds is how many seconds it takes to fade in the trail if active is set to true +@export var fade_in_seconds : float = 0.0 : set = _set_fade_in_seconds +## Fade In Alpha is the Alpha value that the whole trail will go to. The alpha value is also a parameter on the trail +@export var fade_in_alpha : float = 1.0 : set = _set_fade_in_alpha + +## Fade Out Seconds is how many seconds it takes to fade out the trail if active is set to false +@export var fade_out_seconds : float = 0.0 : set = _set_fade_out_seconds +## Fade Out Alpha is the Alpha value that the whole trail will go to. The alpha value is also a parameter on the trail +@export var fade_out_alpha : float = 0.0 : set = _set_fade_out_alpha + @export_category("Mesh tweaks") @@ -115,6 +139,34 @@ func _ready(): clip_overlaps = clip_overlaps snap_to_transform = snap_to_transform +func _set_active(value): + active = value + if active and fade_in_seconds > 0.0: + process_material.set_shader_parameter("active", active) + restart() + var tween: Tween = create_tween() + tween.tween_property(self, "alpha", fade_in_alpha, fade_in_seconds) + elif not active and fade_out_seconds > 0.0: + var tween: Tween = create_tween() + tween.tween_property(self, "alpha", fade_out_alpha, fade_out_seconds) + tween.tween_callback(func(): process_material.set_shader_parameter("active", active)) + else: + process_material.set_shader_parameter("active", active) + _set_alpha(fade_in_alpha) + restart() + +func _set_fade_in_seconds(value): + fade_in_seconds = value + +func _set_fade_out_seconds(value): + fade_out_seconds = value + +func _set_fade_in_alpha(value): + fade_in_alpha = value + +func _set_fade_out_alpha(value): + fade_out_alpha = value + func _set_length(value): if value is int: # length is being set length = value @@ -161,6 +213,21 @@ func _set_curve(value): draw_pass_1.material.set_shader_parameter("curve", curve) else: draw_pass_1.material.set_shader_parameter("curve", preload(_DEFAULT_CURVE)) +func _set_alpha(value): + alpha = clamp(value,0.0,1.0) + if value: + draw_pass_1.material.set_shader_parameter("alpha", value) + else: + draw_pass_1.material.set_shader_parameter("alpha", 1.0) +func _set_fade_curve(value): + fade_curve = value + draw_pass_1.material.set_shader_parameter("fade_curve", fade_curve) +func _set_fade_curve_intensity(value): + fade_curve_intensity = clamp(value,0.0,10.0) + if value: + draw_pass_1.material.set_shader_parameter("fade_curve_intensity", value) + else: + draw_pass_1.material.set_shader_parameter("fade_curve_intensity", 1.0) func _set_vertical_texture(value): vertical_texture = value _flags = _set_flag(_flags,0,value) diff --git a/README.md b/README.md index 026cd64..1a2f37f 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,22 @@ GPUTrail is a GPU-based trail plugin for Godot 4, offering an efficient alternat 3. Attach the `GPUTrail3D` node to the object you want to trail ## Properties - +- `active`: Turn on or off the trail - `length`: Number of steps in the trail - `texture`: Main texture of the trail +- `mask`: A texture used to modify the alpha of trail. Uses the red channel of the texture to determine what is visible. +- `mask_strength`: A float value from 0.0 to 1.0 for determing how intense the mask texture is - `color_ramp`: Color gradient along the trail's length - `curve`: Width modulation along the trail's length - `vertical_texture`: Adjust texture orientation - `use_red_as_alpha`: Use the red channel of the texture as alpha +- `alpha`: Determines the overall alpha value of the trail. Is modified if using fade in and out parameters +- `fade_curve`: Curve to control the alpha along the trail's lifetime +- `fade_curve_intensity`: Value to control the strength of the fade curve value +- `fade_in_seconds`: Value to determine how quickly the whole trail fades in if active is set from false to true +- `fade_in_alpha`: Value to determine what alpha value the whole trail fades to if active is set from false to true +- `fade_out_seconds`: Value to determine how quickly the whole trail fades out if active is set from true to false +- `fade_out_alpha`: Value to determine what alpha value the whole trail fades to if active is set from true to false - `billboard`: Make the trail face the camera (experimental) - `dewiggle`: Improve texture mapping to the trail - `clip_overlaps`: Prevent trail self-intersectionis diff --git a/shaders/trail.gdshader b/shaders/trail.gdshader index df38745..18c9275 100644 --- a/shaders/trail.gdshader +++ b/shaders/trail.gdshader @@ -2,37 +2,39 @@ shader_type particles; render_mode keep_data,disable_force,disable_velocity; - +uniform bool active = true; void process() { + ACTIVE = active; + // CUSTOM.w tracks the particles place in the trail, in range (0..LIFETIME] // requires that LIFETIME = number of particles float amount = LIFETIME; - + vec4 a = EMISSION_TRANSFORM * vec4(0,1,0,1); vec4 b = EMISSION_TRANSFORM * vec4(0,-1,0,1); - + // start if(CUSTOM.w == 0.0){ CUSTOM.w = float(INDEX)+1.0; - + // needed to pass to draw pass CUSTOM.z = amount; - + // needed to initialize in case of CUSTOM.w == 2.0 TRANSFORM = mat4(a,a,b,b); } - + // restart if(CUSTOM.w == amount+1.0){ CUSTOM.w = 1.0; } - + if(CUSTOM.w == 1.0){ // sets the quad to the line to cache this frame, it is not yet visible TRANSFORM = mat4(a,a,b,b); } - + if(CUSTOM.w == 2.0){ // sets the right edge of the quad TRANSFORM[1] = a; diff --git a/shaders/trail_draw_pass.gdshader b/shaders/trail_draw_pass.gdshader index 75aba49..1353cdb 100644 --- a/shaders/trail_draw_pass.gdshader +++ b/shaders/trail_draw_pass.gdshader @@ -5,6 +5,9 @@ render_mode unshaded,world_vertex_coords,cull_disabled; uniform sampler2D tex : repeat_enable, source_color, hint_default_white; uniform sampler2D mask : hint_default_white; uniform float mask_strength = 1.0; +uniform sampler2D fade_curve: repeat_disable, hint_default_white; +uniform float fade_curve_intensity = 1.0; +uniform float alpha = 1.0; uniform vec2 uv_offset = vec2(0); uniform sampler2D color_ramp : repeat_disable, source_color, hint_default_white; uniform sampler2D curve : repeat_disable, hint_default_white; @@ -27,6 +30,7 @@ uniform bool snap_to_transform = false;*/ varying float scale_interp; varying vec2 clip; varying vec2 mesh_uv; +varying float particle_lifetime; void vertex(){ mesh_uv = UV; @@ -76,6 +80,7 @@ void vertex(){ UV *= scale_interp; } + particle_lifetime = INSTANCE_CUSTOM.y; clip.x = dot(VERTEX - INV_VIEW_MATRIX[3].xyz,cross(my_model_matrix[1].xyz - INV_VIEW_MATRIX[3].xyz,my_model_matrix[2].xyz - INV_VIEW_MATRIX[3].xyz)); clip.y = dot(VERTEX - INV_VIEW_MATRIX[3].xyz,cross(my_model_matrix[3].xyz - INV_VIEW_MATRIX[3].xyz,my_model_matrix[0].xyz - INV_VIEW_MATRIX[3].xyz)); @@ -120,16 +125,22 @@ void fragment(){ ALPHA = T.r; } + vec4 F = textureLod(fade_curve, raw_uv, 0.0); + float fade_alpha = F.x * (fade_curve_intensity - (particle_lifetime * fade_curve_intensity)); + ALPHA *= fade_alpha; + T = textureLod(color_ramp, raw_uv, 0.0); + float texture_alpha = T.a; ALBEDO *= T.rgb; - ALPHA *= T.a; - - vec4 M = textureLod(mask, base_uv, 0.0); - ALPHA *= (M.r * mask_strength); + ALPHA *= texture_alpha; - //ALBEDO = vec3(UV,0); + vec4 M = textureLod(mask, raw_uv, 0.0); + float mask_alpha = (M.r * mask_strength); + ALPHA *= mask_alpha; if((base_uv.x < .01) || (.99 < base_uv.x)){ //ALBEDO = vec3(1,0,1); } + + ALPHA *= alpha; }