From 9de230eb5f96bbfbb129258aafe316667d13cf6f Mon Sep 17 00:00:00 2001 From: mikeysax Date: Tue, 16 Dec 2025 07:22:28 -0500 Subject: [PATCH 1/6] Added ability to activate and deactivate trails. Added ability to fade on activation or deactivation over time. Added independent fade curve parameters to control the alpha of a particle over it's lifetime. --- GPUTrail3D.gd | 64 ++++++++++++++++++++++++++++++++ shaders/trail.gdshader | 22 +++++++---- shaders/trail_draw_pass.gdshader | 21 ++++++++--- 3 files changed, 94 insertions(+), 13 deletions(-) diff --git a/GPUTrail3D.gd b/GPUTrail3D.gd index 242f93a..bf178d8 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,23 @@ 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 +@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 +@export var fade_in_alpha : float = 1.0 : set = _set_fade_in_alpha + +## Fade Away 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 +@export var fade_out_alpha : float = 0.0 : set = _set_fade_out_alpha + @export_category("Mesh tweaks") @@ -115,6 +136,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 +210,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/shaders/trail.gdshader b/shaders/trail.gdshader index df38745..320161b 100644 --- a/shaders/trail.gdshader +++ b/shaders/trail.gdshader @@ -2,37 +2,43 @@ shader_type particles; render_mode keep_data,disable_force,disable_velocity; - +uniform bool active = true; void process() { + if(active) { + ACTIVE = true; + } else { + ACTIVE = false; + } + // 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..ea1bd8d 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_black; +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; } From 24056dfff88f66e55b3e1210d2e96dd08df29e5b Mon Sep 17 00:00:00 2001 From: mikeysax Date: Tue, 16 Dec 2025 07:24:59 -0500 Subject: [PATCH 2/6] Updated readme with new active, fade curve, fade curve intensity, and remainder of the fade in and fade out params. --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 026cd64..3bfd26d 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,20 @@ 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 - `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 From 9f65ee5196fc2d01ea242e16d265ccc57f2d2b1a Mon Sep 17 00:00:00 2001 From: mikeysax Date: Wed, 17 Dec 2025 06:38:11 -0500 Subject: [PATCH 3/6] Fixed comment typo for Fade Out description. Added additional parameter description for the Godot Editor when looking at the Trail in the inspector. --- GPUTrail3D.gd | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPUTrail3D.gd b/GPUTrail3D.gd index bf178d8..0e93cee 100644 --- a/GPUTrail3D.gd +++ b/GPUTrail3D.gd @@ -64,14 +64,17 @@ class_name GPUTrail3D extends GPUParticles3D @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 Away Seconds is how many seconds it takes to fade out the trail if active is set to false +## 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 From a7b83ab4578802458ebab41426ff19d45cf44eaa Mon Sep 17 00:00:00 2001 From: mikeysax Date: Wed, 24 Dec 2025 06:55:59 -0500 Subject: [PATCH 4/6] Added missing mask and mask_strength properties to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3bfd26d..1a2f37f 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ GPUTrail is a GPU-based trail plugin for Godot 4, offering an efficient alternat - `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 From c15469dd22c02317255627e8d79ea67d5f0fc12a Mon Sep 17 00:00:00 2001 From: mikeysax Date: Fri, 26 Dec 2025 06:38:05 -0500 Subject: [PATCH 5/6] Removed redundant conditional in trail shader for setting ACTIVE. --- shaders/trail.gdshader | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/shaders/trail.gdshader b/shaders/trail.gdshader index 320161b..18c9275 100644 --- a/shaders/trail.gdshader +++ b/shaders/trail.gdshader @@ -5,11 +5,7 @@ render_mode keep_data,disable_force,disable_velocity; uniform bool active = true; void process() { - if(active) { - ACTIVE = true; - } else { - ACTIVE = false; - } + ACTIVE = active; // CUSTOM.w tracks the particles place in the trail, in range (0..LIFETIME] // requires that LIFETIME = number of particles From 1305923a48d9df5301cfa924e56735c751aa1ffc Mon Sep 17 00:00:00 2001 From: mikeysax Date: Wed, 4 Feb 2026 12:11:23 -0500 Subject: [PATCH 6/6] Modified fade_curve hint to hint_default_white --- shaders/trail_draw_pass.gdshader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shaders/trail_draw_pass.gdshader b/shaders/trail_draw_pass.gdshader index ea1bd8d..1353cdb 100644 --- a/shaders/trail_draw_pass.gdshader +++ b/shaders/trail_draw_pass.gdshader @@ -5,7 +5,7 @@ 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_black; +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);