Repository: celyk/GPUTrail Branch: main Commit: 00a764775941 Files: 16 Total size: 21.8 KB Directory structure: gitextract_2dp5sfum/ ├── .gitattributes ├── .github/ │ └── FUNDING.yml ├── GPUTrail3D.gd ├── Godot.gitignore ├── LICENSE ├── README.md ├── defaults/ │ ├── curve.tres │ └── texture.tres ├── gizmos/ │ └── gizmo.gd ├── plugin.cfg ├── plugin.gd └── shaders/ ├── custom_example_alpha_erosion.gdshader ├── custom_example_blank.gdshader ├── gputrail_lib.gdshaderinc ├── trail.gdshader └── trail_draw_pass.gdshader ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: celyk tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry polar: # Replace with a single Polar username buy_me_a_coffee: # Replace with a single Buy Me a Coffee username thanks_dev: # Replace with a single thanks.dev username custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] ================================================ FILE: GPUTrail3D.gd ================================================ @tool @icon("bounce.svg") class_name GPUTrail3D extends GPUParticles3D ## [br]A node for creating a ribbon trail effect. ## [br][color=purple]Made by celyk[/color] ## @tutorial(celyk's repo): https://github.com/celyk/godot-useful-stuff ## ## This node serves as an alternative to CPU based trails.[br] # TODO: # Add flipbook support # Hide the actual GPUParticles3D node # Restructure code, use enums for flags # Add more polygons, make trail smoother # Add an acceleration parameter # Port to Godot 3.5 # Port to 2D # Allow custom material # PUBLIC ## 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 @export_category("Color / Texture") ## The main texture of the trail.[br] ## [br]Set [member vertical_texture] to adjust for orientation[br] ## ## [br]Enable [member use_red_as_alpha] to use the red color channel as alpha @export var texture : Texture : set = _set_texture ## A mask texture, used to modify the alpha of trail @export var mask : Texture : set = _set_mask ## A float value from 0.0 to 1.0 for determing how intense the mask texture is @export var mask_strength : float = 1.0 : set = _set_mask_strength ## Scolls the texture by applying an offset to the UV @export var scroll : Vector2 : set = _set_scroll ## A color ramp for modulating the color along the length of the trail @export var color_ramp : GradientTexture1D : set = _set_color_ramp ## A curve for modulating the width along the length of the trail @export var curve : CurveTexture : set = _set_curve ## Set [member vertical_texture] to adjust for orientation @export var vertical_texture := false : set = _set_vertical_texture ## 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 @export_category("Mesh tweaks") ## Makes trail face camera. I haven't finished this yet @export var billboard := false : set = _set_billboard ## Enable to improve the mapping of [member texture] to the trail @export var dewiggle := true : set = _set_dewiggle ## Enable to improve the mapping of [member texture] to the trail @export var clip_overlaps := true : set = _set_clip_overlaps ## Enable [member snap_to_transform] to snap the start of the trail to the nodes position. This may not be noticeable unless you ## have changed [member fixed_fps], which you can use to optimize the trail @export var snap_to_transform := false : set = _set_snap_to_transform # PRIVATE const _DEFAULT_TEXTURE = "defaults/texture.tres" const _DEFAULT_CURVE = "defaults/curve.tres" var _defaults_have_been_set = false func _get_property_list(): return [{"name": "_defaults_have_been_set","type": TYPE_BOOL,"usage": PROPERTY_USAGE_NO_EDITOR}] func _ready(): if not _defaults_have_been_set: _defaults_have_been_set = true amount = length lifetime = length explosiveness = 1 # emits all particles at once # the main fps is default fixed_fps = int( DisplayServer.screen_get_refresh_rate(DisplayServer.MAIN_WINDOW_ID) ) if DisplayServer.screen_get_refresh_rate(DisplayServer.MAIN_WINDOW_ID) < 0.0: push_warning("Could not find screen refresh rate. Using fixed_fps = 60") fixed_fps = 60 process_material = ShaderMaterial.new() process_material.shader = preload("shaders/trail.gdshader") draw_pass_1 = QuadMesh.new() draw_pass_1.material = ShaderMaterial.new() draw_pass_1.material.shader = preload("shaders/trail_draw_pass.gdshader") color_ramp = preload(_DEFAULT_TEXTURE).duplicate(true) curve = preload(_DEFAULT_CURVE).duplicate(true) draw_pass_1.material.resource_local_to_scene = true length = length vertical_texture = vertical_texture use_red_as_alpha = use_red_as_alpha billboard = billboard dewiggle = dewiggle clip_overlaps = clip_overlaps snap_to_transform = snap_to_transform func _set_length(value): if value is int: # length is being set length = value length = max(length, 1) length_seconds = float(length) / get_fixed_fps() elif value is float: # length_seconds is being set length = int(value * get_fixed_fps()) length = max(length, 1) length_seconds = float(length) / get_fixed_fps() if _defaults_have_been_set: amount = length lifetime = length restart() func _set_texture(value): texture = value _uv_offset = Vector2(0,0) # Reset the scroll when a new texture is assigned if value: draw_pass_1.material.set_shader_parameter("tex", texture) else: draw_pass_1.material.set_shader_parameter("tex", preload(_DEFAULT_TEXTURE)) func _set_mask(value): mask = value if value: draw_pass_1.material.set_shader_parameter("mask", mask) else: draw_pass_1.material.set_shader_parameter("mask", null) func _set_mask_strength(value): mask_strength = clamp(value,0.0,1.0) if value: draw_pass_1.material.set_shader_parameter("mask_strength", mask_strength) else: draw_pass_1.material.set_shader_parameter("mask_strength", 1.0) func _set_scroll(value): scroll = value func _set_color_ramp(value): color_ramp = value draw_pass_1.material.set_shader_parameter("color_ramp", color_ramp) func _set_curve(value): curve = value if value: draw_pass_1.material.set_shader_parameter("curve", curve) else: draw_pass_1.material.set_shader_parameter("curve", preload(_DEFAULT_CURVE)) func _set_vertical_texture(value): vertical_texture = value _flags = _set_flag(_flags,0,value) draw_pass_1.material.set_shader_parameter("flags", _flags) func _set_use_red_as_alpha(value): use_red_as_alpha = value _flags = _set_flag(_flags,1,value) draw_pass_1.material.set_shader_parameter("flags", _flags) func _set_billboard(value): billboard = value _flags = _set_flag(_flags,2,value) draw_pass_1.material.set_shader_parameter("flags", _flags) if value && _defaults_have_been_set: _update_billboard_transform( global_transform.basis[0] ) restart() func _set_dewiggle(value): dewiggle = value _flags = _set_flag(_flags,3,value) draw_pass_1.material.set_shader_parameter("flags", _flags) func _set_snap_to_transform(value): snap_to_transform = value _flags = _set_flag(_flags,4,value) draw_pass_1.material.set_shader_parameter("flags", _flags) func _set_clip_overlaps(value): clip_overlaps = value _flags = _set_flag(_flags,5,value) draw_pass_1.material.set_shader_parameter("flags", _flags) @onready var _old_pos : Vector3 = global_position @onready var _billboard_transform : Transform3D = global_transform var _uv_offset : Vector2 func _process(delta): if(snap_to_transform): draw_pass_1.material.set_shader_parameter("emmission_transform", global_transform) # Handle UV scrolling _uv_offset += scroll * delta _uv_offset = _uv_offset.posmod(1.0) draw_pass_1.material.set_shader_parameter("uv_offset", _uv_offset) await RenderingServer.frame_pre_draw if(billboard): var delta_position = global_position - _old_pos if delta_position: var tangent = global_transform.basis[1].length() * (delta_position).normalized() _update_billboard_transform(tangent) RenderingServer.instance_set_transform(get_instance(), _billboard_transform) _old_pos = global_position func _update_billboard_transform(tangent : Vector3): _billboard_transform = global_transform var p : Vector3 = _billboard_transform.basis[1] var x : Vector3 = tangent var angle : float = p.angle_to(x) var rotation_axis : Vector3 = p.cross(x).normalized() if rotation_axis != Vector3(): _billboard_transform.basis = _billboard_transform.basis.rotated(rotation_axis,angle) _billboard_transform.basis = _billboard_transform.basis.scaled(Vector3(0.5,0.5,0.5)) _billboard_transform.origin += _billboard_transform.basis[1] var _flags = 0 func _set_flag(i, idx : int, value : bool): return (i & ~(1 << idx)) | (int(value) << idx) ================================================ FILE: Godot.gitignore ================================================ # Godot 4+ specific ignores .godot/ # Godot-specific ignores .import/ export.cfg export_presets.cfg # Imported translations (automatically generated from CSV files) *.translation # Mono-specific ignores .mono/ data_*/ mono_crash.*.json ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2023 celyk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # GPUTrail GPUTrail is a GPU-based trail plugin for Godot 4, offering an efficient alternative to CPU-based trails for creating ribbon trail effects in your games and applications. ![heart](https://github.com/celyk/GPUTrail/assets/50609684/a190fee3-682b-42b9-9bef-cd49a5e3b99c) ## Features - GPU-accelerated trail rendering for improved performance - Customizable trail length, texture, and color - Support for color ramps and width curves - Options for texture orientation and alpha channel handling - Billboard mode for camera-facing trails - Dewiggle and clip overlaps features for improved trail appearance ## Installation 1. Clone or download this repository 2. Copy the `addons/GPUTrail` folder into your Godot project's `addons` folder 3. Enable the plugin in your project settings: Project -> Project Settings -> Plugins -> GPUTrail ## Usage 1. Add a new `GPUTrail3D` node to your scene 2. Customize the trail properties in the Inspector panel 3. Attach the `GPUTrail3D` node to the object you want to trail ## Properties - `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 - `billboard`: Make the trail face the camera (experimental) - `dewiggle`: Improve texture mapping to the trail - `clip_overlaps`: Prevent trail self-intersectionis - `snap_to_transform`: Snap the trail start to the node's position, and regardless of the particles own framerate ## Example ```gdscript var trail = GPUTrail3D.new() trail.length = 100 trail.texture = preload("res://trail_texture.png") add_child(trail) ``` ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Acknowledgements - Tutorial by Le Lu: [YouTube Video](https://www.youtube.com/watch?v=0VsEfP4XFCM) ## TODO - Add flipbook support - Hide the actual GPUParticles3D node - Restructure code, use enums for flags - Add more polygons, make trail smoother - Add an acceleration parameter - Port to Godot 3.5 - Port to 2D - Allow custom material ================================================ FILE: defaults/curve.tres ================================================ [gd_resource type="CurveTexture" load_steps=2 format=3 uid="uid://ct31fhxvcragr"] [sub_resource type="Curve" id="Curve_7ufs5"] bake_resolution = 16 _data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.1), 0.0, 0.0, 0, 0] point_count = 2 [resource] curve = SubResource("Curve_7ufs5") ================================================ FILE: defaults/texture.tres ================================================ [gd_resource type="GradientTexture1D" load_steps=2 format=3 uid="uid://crk6pkb7e5rwc"] [sub_resource type="Gradient" id="Gradient_nk704"] colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0) [resource] gradient = SubResource("Gradient_nk704") ================================================ FILE: gizmos/gizmo.gd ================================================ @tool extends EditorNode3DGizmoPlugin var editor_plugin : EditorPlugin func _init(_editor_plugin:EditorPlugin): editor_plugin = _editor_plugin create_material("main", Color(1,1,1), false, true, true) func _has_gizmo(node): return node is GPUTrail3D # show gizmo name in visibility list func _get_gizmo_name(): return "GPUTrail3DGizmo" func _redraw(gizmo): gizmo.clear() var node3d : Node3D = gizmo.get_node_3d() var lines = PackedVector3Array() lines.push_back(Vector3(0,1,0)) lines.push_back(Vector3(0,-1,0)) gizmo.add_lines(lines, get_material("main", gizmo), false, Color(1,1,1,1)) ================================================ FILE: plugin.cfg ================================================ [plugin] name="GPUTrail" description="temporary desc" author="celyk" version="0.1" script="plugin.gd" ================================================ FILE: plugin.gd ================================================ @tool extends EditorPlugin const MyCustomGizmoPlugin = preload("gizmos/gizmo.gd") var gizmo_plugin = MyCustomGizmoPlugin.new(self) func _enter_tree(): # Initialization of the plugin goes here. # Add the new type with a name, a parent type, a script and an icon. add_custom_type("GPUTrail3D", "GPUParticles3D", preload("GPUTrail3D.gd"), preload("bounce.svg")) add_node_3d_gizmo_plugin(gizmo_plugin) func _exit_tree(): # Clean-up of the plugin goes here. # Always remember to remove it from the engine when deactivated. remove_custom_type("GPUTrail3D") remove_node_3d_gizmo_plugin(gizmo_plugin) ================================================ FILE: shaders/custom_example_alpha_erosion.gdshader ================================================ shader_type spatial; #define GPU_TRAIL #include "res://addons/GPUTrail/shaders/gputrail_lib.gdshaderinc" varying vec2 trail_uv; void vertex(){ PREPARE_TRAIL(); // Save the trail UV coordaintes for later trail_uv = UV; // Scroll textures slowly along the length of the trail //UV.x -= fract(TIME*.4); } void fragment(){ PREPARE_TRAIL_TEXTURES(); // Alpha erosion ALPHA = max(ALPHA - trail_uv.x, 0.0); } ================================================ FILE: shaders/custom_example_blank.gdshader ================================================ shader_type spatial; #define GPU_TRAIL #include "res://addons/GPUTrail/shaders/gputrail_lib.gdshaderinc" varying vec2 trail_uv; void vertex(){ PREPARE_TRAIL(); } void fragment(){ PREPARE_TRAIL_TEXTURES(); } ================================================ FILE: shaders/gputrail_lib.gdshaderinc ================================================ #ifdef GPU_TRAIL //#define GPU_TRAIL // TODO make optional render_mode unshaded,world_vertex_coords,cull_disabled; uniform sampler2D tex : repeat_enable, source_color, hint_default_white; 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; uniform mat4 emmission_transform = mat4(1); uniform int flags = 0; /*uniform bool vertical_texture = false; uniform bool use_red_as_alpha = false; uniform bool billboard = false; uniform bool dewiggle = false; uniform bool snap_to_transform = false;*/ #define vertical_texture bool(flags & 1) #define use_red_as_alpha bool(flags & 2) #define billboard bool(flags & 4) #define dewiggle bool(flags & 8) #define snap_to_transform bool(flags & 16) #define clip_overlaps bool(flags & 32) varying float scale_interp; varying vec2 clip; varying vec2 mesh_uv; void missing_parens(){} #define PREPARE_TRAIL { \ mesh_uv = UV; \ \ mat4 my_model_matrix = MODEL_MATRIX; \ if(snap_to_transform && INSTANCE_CUSTOM.w==2.0){ \ my_model_matrix[1] = emmission_transform * vec4(0,1,0,1); \ my_model_matrix[2] = emmission_transform * vec4(0,-1,0,1); \ } \ \ if(billboard){ \ vec3 t0 = my_model_matrix[0].xyz-my_model_matrix[3].xyz; \ vec3 t1 = my_model_matrix[1].xyz-my_model_matrix[2].xyz; \ \ vec3 up0 = length(t0)*normalize( \ cross( \ my_model_matrix[3].xyz-INV_VIEW_MATRIX[3].xyz, \ t0)); \ vec3 up1 = length(t1)*normalize( \ cross( \ my_model_matrix[2].xyz-INV_VIEW_MATRIX[3].xyz, \ t1)); \ \ my_model_matrix[0] = my_model_matrix[3]; \ my_model_matrix[1] = my_model_matrix[2]; \ \ my_model_matrix[0].xyz += up0; \ my_model_matrix[3].xyz -= up0; \ \ my_model_matrix[1].xyz += up1; \ my_model_matrix[2].xyz -= up1; \ } \ \ vec3 a = mix(my_model_matrix[1].xyz,my_model_matrix[0].xyz,UV.x); \ vec3 b = mix(my_model_matrix[2].xyz,my_model_matrix[3].xyz,UV.x); \ \ UV.x = (UV.x + INSTANCE_CUSTOM.w-1.0 - 2.0)/(INSTANCE_CUSTOM.z-1.0); \ \ \ float h = textureLod(curve, vec2(UV.x), 0.0).x; \ \ VERTEX = mix(a,b,(UV.y-0.5)*h + 0.5); \ \ if(dewiggle){ \ scale_interp = h; \ UV *= scale_interp; \ } \ \ \ 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)); \ } missing_parens #define PREPARE_TRAIL_TEXTURES { \ vec2 clip0 = clip; \ float ababab = clip0.x*clip0.y; \ \ if(clip_overlaps && ababab < 0.0) { \ if(abs(mesh_uv.x-0.5)<0.5) \ discard; \ } \ \ vec2 base_uv = UV; \ \ if(dewiggle){ \ base_uv /= scale_interp; \ } \ \ vec2 raw_uv = base_uv; \ \ base_uv -= uv_offset; \ \ if(vertical_texture){ \ base_uv = base_uv.yx; \ } \ \ vec4 T = textureLod(tex, base_uv, 0.0); \ ALBEDO = T.rgb; \ ALPHA = T.a; \ \ if(use_red_as_alpha){ \ ALBEDO = vec3(1); \ ALPHA = T.r; \ } \ \ T = textureLod(color_ramp, raw_uv, 0.0); \ ALBEDO *= T.rgb; \ ALPHA *= T.a; \ } missing_parens #endif /*GPU_TRAIL*/ ================================================ FILE: shaders/trail.gdshader ================================================ shader_type particles; render_mode keep_data,disable_force,disable_velocity; void process() { // 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; TRANSFORM[2] = b; } CUSTOM.w++; } ================================================ FILE: shaders/trail_draw_pass.gdshader ================================================ shader_type spatial; 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 vec2 uv_offset = vec2(0); uniform sampler2D color_ramp : repeat_disable, source_color, hint_default_white; uniform sampler2D curve : repeat_disable, hint_default_white; uniform mat4 emmission_transform = mat4(1); uniform int flags = 0; /*uniform bool vertical_texture = false; uniform bool use_red_as_alpha = false; uniform bool billboard = false; uniform bool dewiggle = false; uniform bool snap_to_transform = false;*/ #define vertical_texture bool(flags & 1) #define use_red_as_alpha bool(flags & 2) #define billboard bool(flags & 4) #define dewiggle bool(flags & 8) #define snap_to_transform bool(flags & 16) #define clip_overlaps bool(flags & 32) varying float scale_interp; varying vec2 clip; varying vec2 mesh_uv; void vertex(){ mesh_uv = UV; mat4 my_model_matrix = MODEL_MATRIX; if(snap_to_transform && INSTANCE_CUSTOM.w==2.0){ my_model_matrix[1] = emmission_transform * vec4(0,1,0,1); my_model_matrix[2] = emmission_transform * vec4(0,-1,0,1); } if(billboard){ vec3 t0 = my_model_matrix[0].xyz-my_model_matrix[3].xyz; vec3 t1 = my_model_matrix[1].xyz-my_model_matrix[2].xyz; //vec3 up1 = up0; vec3 up0 = length(t0)*normalize( cross( my_model_matrix[3].xyz-INV_VIEW_MATRIX[3].xyz, //-INV_VIEW_MATRIX[2].xyz, t0)); vec3 up1 = length(t1)*normalize( cross( my_model_matrix[2].xyz-INV_VIEW_MATRIX[3].xyz, //-INV_VIEW_MATRIX[2].xyz, t1)); my_model_matrix[0] = my_model_matrix[3]; my_model_matrix[1] = my_model_matrix[2]; my_model_matrix[0].xyz += up0; my_model_matrix[3].xyz -= up0; my_model_matrix[1].xyz += up1; my_model_matrix[2].xyz -= up1; } vec3 a = mix(my_model_matrix[1].xyz,my_model_matrix[0].xyz,UV.x); vec3 b = mix(my_model_matrix[2].xyz,my_model_matrix[3].xyz,UV.x); UV.x = (UV.x + INSTANCE_CUSTOM.w-1.0 - 2.0)/(INSTANCE_CUSTOM.z-1.0); float h = textureLod(curve, vec2(UV.x), 0.0).x;//h=1.0; VERTEX = mix(a,b,(UV.y-0.5)*h + 0.5); if(dewiggle){ scale_interp = h; UV *= scale_interp; } 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)); } void fragment(){ //if(billboard && !FRONT_FACING) discard; vec2 clip0 = clip; float ababab = clip0.x*clip0.y; //ababab += dFdx(ababab) + dFdy(ababab); //clip0 -= fwidth(clip0); if(clip_overlaps && ababab < 0.0) { if(abs(mesh_uv.x-0.5)<0.5) discard; } vec2 base_uv = UV; if(dewiggle){ base_uv /= scale_interp; } vec2 raw_uv = base_uv; // Handle UV scrolling base_uv -= uv_offset; if(vertical_texture){ base_uv = base_uv.yx; } vec4 T = textureLod(tex, base_uv, 0.0); ALBEDO = T.rgb; ALPHA = T.a; if(use_red_as_alpha){ ALBEDO = vec3(1); ALPHA = T.r; } T = textureLod(color_ramp, raw_uv, 0.0); ALBEDO *= T.rgb; ALPHA *= T.a; vec4 M = textureLod(mask, base_uv, 0.0); ALPHA *= (M.r * mask_strength); //ALBEDO = vec3(UV,0); if((base_uv.x < .01) || (.99 < base_uv.x)){ //ALBEDO = vec3(1,0,1); } }