Fluid Effects System Beta Overview (Updates Planned)

Fluid System User Manual

This document explains the overall structure of the “Fluid Simulation System” implemented in this project, as well as how to use and configure each node.
It enables the expression of seamless trajectories that cannot be represented with particles.

Sample Project
All the sample effects below are included in the sample project.
After running game_scene with F5,
effects are assigned to ZXCV, ASDF, and QWE. You can verify the assignments in player.tscn.

Script Only
fluid_system_core.zip (68.0 KB)

flame_trail

frost_ball

frost_effect

lightning_strike

poison_tentacle

poison_tentacle_hit

spin_weapon

wind_spell

crystal_spear

dark_spell

fire_ball

flame_spear

  • FluidBufferPool (Autoload): An internal system that reuses GPU buffers to maintain performance. There is no need to place it directly in the scene.
  • Fluid Shaders (inside shaders/fluid/): Shader files that perform actual fluid calculations on the GPU. No editing is required.

Node 1: FluidSimulationController

Role

This is the “heart” of the entire fluid simulation. It manages everything from GPU buffer allocation and fluid calculations to rendering on the screen. You must place exactly one in your scene.

Note: Placing more than one in a scene will allocate buffers for each instance, straining VRAM.

Key Settings

Basic Settings

Item Description Default
auto_fit_to_window Automatically adjusts the simulation area to the window size. If ON, all buffers are reallocated when the window is resized, causing performance spikes. OFF
use_deferred_init Delays initialization to the next frame. If ON, nothing is rendered for the 1 frame immediately after instantiation. Textures referenced within _ready() will appear empty. ON
texture_size Fixed resolution when auto_fit_to_window is OFF. 768×512
sim_area_size When auto_fit_to_window is OFF, this fixes the world space size (in pixels) covered by the fluid. If (0,0), it matches texture_size. Changing texture_size without setting this will misalign the UV positions in FluidEffectNode. (0, 0)

Performance / Quality

Item Description Default
simulation_scale Resolution scale. 1.0 is highest quality but most expensive. 0.5 is recommended. 0.5
pressure_iterations Accuracy of fluid pressure calculations. Higher values look better but increase GPU load. Around 10 is a good guideline. 10
path_bake_resolution Direction texture resolution for effect nodes in Path mode (8–64). Lower values are faster. 16
path_bake_sample_density Number of samples per curve point in Path mode (1–8). 4

Operation Settings

Item Description Default
simulation_active If OFF, completely stops calculations. The visual appearance remains unchanged. ON
auto_sleep_enabled Automatically stops calculations after ink and input cease. Useful for saving performance. ON

Visuals and Glow

Item Description Default
dye_brightness Brightness multiplier for the entire ink. 1.0
dye_glow_mode Glow style. Two types: “Standard Glow” and “Dye Glow”. Standard Glow
dye_glow_boost Glow intensity. Higher values make it appear brighter. 0.0
dye_base_ink_opacity Ink opacity. At 0, only the glow component is visible. 1.0
dye_alpha_gain Amplification multiplier for overall opacity. Use this to make the ink appear denser. 1.0
dye_velocity_visibility_scale Exclusive to “Dye Glow” mode. When dye_base_ink_opacity is less than 1, this determines how strongly ink opacity is increased at locations with high fluid velocity. Higher values make ink appear clearer even with weak movement. 40.0
dye_color_variation_strength Strength of hue fluctuation over time. 0 disables it. 0.0
dye_color_variation_speed Speed at which hue fluctuations change. 1.3
dye_glow_pulse_strength Strength of the pulsing glow effect. 0 disables it. 0.0
dye_glow_pulse_speed Speed of the pulsing effect. 1.6
dye_alpha_cutoff Alpha values below this threshold are cut to full transparency. Prevents garbage pixels. 0.04

Ink Dissipation Settings

Item Description Default
dye_evaporation Speed at which ink gradually fades over time. (Varies)
dye_hard_clear_threshold If ink density falls below this, it is instantly removed. 0.06
decay_distance_factor Factor to accelerate dissipation based on movement distance. Ink disappears smoothly from the tip. 0 disables it. 0.0
decay_velocity_factor Factor to accelerate dissipation based on velocity. Ink scatters when flying vigorously. 0 disables it. 0.0

Fluid Physics Settings

Item Description Default
viscosity Viscosity. Higher values result in thicker, more syrupy fluids. 0.18
curl_strength Strength of curl enhancement. Higher values create more complex swirls. 28.0
curl_idle_scale How much to maintain swirls when there is no input (0.0–1.0). 0.08
idle_velocity_damping Fade-out rate of flow when there is no input. 1.0 means no damping. 0.975
max_velocity Upper limit for flow velocity. 2.4
velocity_floor Velocities below this value are forcibly treated as zero. Used to improve calculation stability. 0.006
pressure_dissipation Pressure dissipation rate. Lowering it reduces repulsion. 0.999

Detailed Velocity Addition Control

Usually, no changes are needed. Use this when you want to fine-tune brush tracking feel or spray momentum.

Item Description Default
input_velocity_cap_scale Upper limit multiplier for ink velocity during brush movement. Higher values allow faster tracking to the brush but make it clump more easily. 10.0
input_velocity_add_scale Base multiplier for ink velocity addition during brush movement. 1.0
outflow_velocity_cap_scale Upper limit multiplier for ink velocity during spray/blowing out. 2.5
outflow_velocity_add_scale Base multiplier for ink velocity addition during spray/blowing out. 0.8

Node 2: FluidBrushNode

Role

This node injects “ink” into the fluid. You can set position, shape, color, intensity, etc. Place it as a sibling node to FluidSimulationController (under the same parent). You can place multiple brushes for one simulation.

Note: It will not be recognized if placed as a child or grandchild of the FSC. Always place it as a sibling (under the same parent).

Key Settings

Basic Settings

Item Description Default
emit_mode Determines where ink is injected. Mouse: Mouse pointer position / NodeCenter: This node’s position / TargetNode: Follows another node’s position Mouse
emit_trigger Timing for injection. Click: Only on click / Always: Always inject (ink continues to flow even when stationary) / Signal: Only when emit_once() is called Always
emit_target_path Path to the node to follow in TargetNode mode. -

Brush Shape

Item Description Default
brush_shape Basic brush shape. Circle: Circular / Ellipse: Elliptical / Texture: Shape of the specified texture / GlobalTexture: Uses the entire image of a separately specified Viewport as the brush / NodeCapture: Copies the visual of another specified node to use as the brush Circle
brush_texture Texture used as the brush shape in Texture or Ellipse modes. -

GlobalTexture Only

Item Description
global_texture_viewport_path Path to the SubViewport to capture (automatically resolved during game execution).
global_texture_include_hidden Whether to include hidden nodes in the capture.
global_texture_use_content_motion Whether to feed motion within the Viewport as force to the fluid.

NodeCapture Only

Item Description
target_node_include_hidden Whether to capture and reflect the target node in the fluid even if it is hidden.
target_node_respect_clip Whether to reproduce the clip boundary if clip_children is set on an ancestor of the source node. If false, the entire node is captured.

Brush Deformation / Angle

Item Description Default
input_radius Brush radius (relative ratio to the overall simulation resolution, 0.0–1.0). 0.035
brush_texture_size_mode Resolution determination mode for texture brushes. Radius: Determines size from the input_radius ratio / OriginalPixels: Draws using the original texture’s pixel dimensions Radius
brush_texture_pixel_scale Additional multiplier in OriginalPixels mode (1.0 is 1:1). 1.0
brush_texture_rotation_degrees Basic rotation angle (in degrees) of the brush (texture). 0.0
brush_rotation_source Source for the brush rotation angle. Fixed: Only the basic rotation angle above / ThisNode: Adds this node’s own rotation / NodeCapture: Adds the rotation of the target node / RotationNode: Adds rotation from the specified node below Fixed
brush_rotation_node_path Path to the rotation angle node to reference in RotationNode mode. -
pivot_follow_visual_center In NodeCapture mode, whether to follow based on the visual center (e.g., sprite offset) of the target node. If ON, UVs link appropriately during rotation. OFF
brush_flip_h Flips the brush texture horizontally. OFF
brush_flip_v Flips the brush texture vertically. OFF

Brush Mask

Filters which parts of the brush are “active” using texture information.

Item Description Default
brush_mask_source Type of information used for mask judgment. Alpha: Alpha value / Luminance: Luminance / Color Range: Proximity to specified color / Saturation: Saturation Alpha
mask_invert Inverts the mask (swaps black and white). OFF
mask_threshold Thin masks below this value are treated as fully transparent (applies to all modes). 0.0
mask_softness Smoothness of the mask’s boundary. 0 is sharp, 1 is a smooth fade (applies to all modes). 0.1
mask_target_color Cutout reference color in Color Range mode. Red
mask_color_tolerance Exclusive to Color Range. How much deviation from the target color is allowed (smaller is stricter). 0.3

Color / Stamp

Item Description Default
emit_dye Whether to inject dye (ink image). If false, it becomes a transparent brush that only generates “force to move the fluid (Force)”. ON
inject_color_mode Method for determining the injected color. Solid: Solid color (uses input_color) / Gradient: Applies gradient texture / BrushTexture: Uses the brush texture’s own color as is Solid
input_color Base color of the injected dye. Bluish white
inject_strength “Density” of a single injection stamp. Higher values make the color appear clearer and stronger. 1.0
uniform_paint Ignores the brush shape’s alpha gradient and paints the inside of the brush uniformly with inject_strength. In BrushTexture mode, the color also becomes uniform (white). OFF
inject_blend Blending method with existing dye. 0.0 is complete overwrite, 1.0 is complete addition (colors blow out to white). 0.35
edge_hardness Sharpness of the brush’s outer edge. Higher values result in sharper boundaries. 1.25
ink_edge_bleed Strength with which the new ink’s edge bleeds when drawing over existing ink. 0.0=none, 1.0=maximum. Does not affect areas without existing ink. 0.0

Gradient Only (Only valid when inject_color_mode is Gradient)

Item Description Default
gradient_mode Shape of gradient application. Radial (radial) or Linear (linear). Radial
gradient_texture Texture used for the gradient (e.g., ColorRamp image). -
gradient_rotation_degrees Rotation angle (in degrees) serving as the gradient’s reference. 0.0
gradient_rotation_source Source for obtaining the gradient rotation angle (same options as brush_rotation_source). Fixed
gradient_rotation_node_path Path to reference if RotationNode is selected. -

Movement / Force

Item Description Default
force_scale Multiplier converting brush movement amount into Force to move the fluid. Higher values cause the fluid to be pulled more strongly when the brush is moved. 85.0
spread_force_reference Reference value for correction where ink spreads more as brush input velocity increases. If 0, it is automatically calculated based on spray_force_limit. 0.0
spread_force_to_advection_scale Multiplier to make dye advection (flowing movement) spread more according to Force. Higher values cause ink to scatter more when the brush is moved quickly. 0.0 disables it. 1.0
spread_force_to_diffusion_scale Multiplier to strengthen dye diffusion (bleeding) according to Force. Higher values cause ink to blur more when the brush is moved quickly. 0.0 disables it. 0.0

Injection / Spray

Item Description Default
spray_direction_mode Method for determining spray direction. Motion: Direction of mouse or node movement / Fixed: Fixed vector below / ToTarget: Towards a specific node / Velocity: Direction calculated from node’s movement velocity Motion
spray_profile Spray shape. Cone: Spreads in a fan shape / Parallel: Moves straight in parallel Cone
spray_fixed_direction Fixed vector in Fixed mode. Right
spray_target_path Path to the target node to move towards in ToTarget mode. -
spray_spread_degrees Spread angle (in degrees) for Cone mode. 180 is omnidirectional (circle). 85.0
spray_force Base strength of the injection. If 0, no spray effect occurs in the direction of movement (only simple movement tracking). 0.0
spray_force_limit Upper limit for spray force. Prevents fluid breakdown. 0.25
spray_outflow_strength Strength of the radial force pushing outward from the center of the brush. 0.0
spray_velocity_scale How much to add the node’s own movement velocity to the spray force. 1.0 is complete multiplication. 0.0
spray_keep_last_direction_when_idle In Motion or Velocity mode, whether to continue spraying in the last spray direction even when movement stops. ON

Continuous Drawing

Item Description Default
continuous_ink_mode When moving the mouse quickly or the node moves at high speed, it smoothly interpolates and draws between brush traces. If OFF, traces appear as scattered stamps. ON
continuous_ink_quality Interpolation quality (number of split steps). Higher values are smoother but increase GPU load. 150–200 is recommended. If too large, a large number of splats run in one frame during high-speed movement, clogging the GPU. 150
interpolate_rotation Whether to smoothly interpolate changes in rotation angle or scale when using TargetNode, etc., along the trace. OFF
spray_use_direction_sweep Whether to sweep the spray direction along the trace during continuous drawing. OFF

Physics / Dissipation

These override the corresponding parameters in FluidSimulationController only for injections from this brush. Use this when you want different dissipation behaviors for each brush.

Item Description Default
velocity_dissipation Dissipation frame rate for the velocity field (flowing force). 1.0 means no dissipation; lower values stop the water flow sooner. 0.995
dye_dissipation Fade-out rate for dye (ink image). 1.0 means no dissipation; lower values make ink fade sooner. 0.985
dye_evaporation Forces a reduction in ink density by this value every frame. Used for expressions like water droplets disappearing instantly. 0.12
dye_diffusion Strength of dye diffusion (bleeding). Higher values cause ink contours to blur and spread into the surroundings as if dissolving in water. 0.06

Node 3: FluidEffectNode

Role

This node applies “force” to the fluid. You can specify effects like suction, blowing, and swirls within a range. Place it as a sibling node to FluidSimulationController.

How to set the range: Add a CollisionShape2D as a child of this node, and set a Circle / Rectangle / Capsule Shape there. Checking “Add Collision Shape” in the inspector will automatically create a CircleShape2D with a radius of 50. If no CollisionShape2D exists (except in Path and Texture modes), no effect will occur.

Key Settings

Force Settings

Item Description Default
direction Direction of the force. -1.0: Suction towards center / 1.0: Blowing out from center -1.0 (Suction)
force_mode Force application mode. Radial: Radial from center / Direction: Specified single direction / Path: Flows along Path2D / Texture: Force applied in the direction of texture gradient Radial
direction_vector Direction of the force in Direction mode (direction vector). Upward
path Path to the Path2D used in Path mode. -

Strength

Item Description Default
strength Strength of the force. 1.0
strength_gradient Strength gradient from center to edge. Uniform if not set. -

Swirl Settings

Item Description Default
vortex_strength Strength of the swirl. 0 disables it. 0.0
vortex_direction Rotation direction of the swirl. 1=Counter-clockwise, -1=Clockwise. 1.0
pure_vortex If ON, sets the force towards the center to zero and applies only the swirl. OFF

Display Settings

Item Description Default
enabled If OFF, disables the effects of this node. ON

Node 4: GroupNoiseCaptureViewport

Role

Acquires the “silhouette” of nodes belonging to a specified group (such as character sprites) and generates a texture by carving it with noise. By passing the generated texture to FluidBrushNode’s brush_texture, you can achieve the expression of “ink being injected along the shape of a character.”

Use this for expressions like flames burning up along the shape of the body.

Setup Method

  1. Place the GroupNoiseCaptureViewport node in the scene.

  2. Click the “[Editor] Setup All Child Nodes” button in the inspector. Required child nodes are automatically created.

  3. Enter the group name of the nodes you want to capture in target_group (e.g., "fluid_capture").

  4. Add the sprites you want to capture to that group.

  5. In the FluidBrushNode in the same scene, set brush_shape to GlobalTexture and global_texture_viewport_path to this node’s FinalLayer. Specifying MaskLayer will result in a pure white image because it lacks color information.

Key Settings

Capture Settings

Item Description Default
target_group Group name of the nodes to capture. “fluid_capture”
local_scene_only Captures only nodes within the same scene (instance). If OFF, you can capture nodes of the same group across scenes. Use this when applying effects to sprites in other scenes. ON
update_mode Update timing. Always: Updates every frame / Manual: Only when refresh_capture() is called Always
capture_size Capture size (in pixels). Automatic (matches fluid simulation)
auto_align_to_fluid_simulation Automatically aligns the camera and size to the fluid simulation area. ON is recommended. ON
pool_subviewports Pools SubViewports to suppress regeneration spikes. Use this for effects that are frequently generated and destroyed. Turning this ON in persistent scenes (those left on the stage) has no effect. OFF

Noise Mask Settings

Item Description Default
noise_texture Noise texture used to carve the silhouette. Creates a bumpy shape resembling flames. -
tint_color Color multiplication value for the output texture. White
noise_threshold Noise threshold. Darker parts than this value are carved away. Higher values carve more of the silhouette. 0.5
noise_edge_hardness Edge hardness. Closer to 1.0 results in a sharper boundary. 0.1
noise_scroll_speed Speed at which the noise scrolls. Creates the movement of flickering flames. (0, -0.5)
noise_scale Noise UV scale. Higher values make the pattern finer. 1.0

Performance Optimization

FluidBufferPool (Autoload)

Mechanism

This system uses a large number of GPU SubViewports. Normally, allocating GPU buffers every time a node is generated causes stuttering.

FluidBufferPool resides as an Autoload and reuses GPU buffers by keeping them as child nodes, reducing the generation cost for the second and subsequent instances to zero. Even if the effect scene is removed from the tree, the buffers remain in the Pool. When an effect of the same size and iteration count is generated next, the existing buffers are passed directly.

The set of buffers required by one FluidSimulationController is called a BufferSet. The Pool manages BufferSets with “In Use / Free” flags.

  • acquire(): Returns a free BufferSet if available. Otherwise, generates a new one.

  • release(): Returns the BufferSet to “Free”. Does not call queue_free().

  • prewarm(): Pre-generates BufferSets of a specified size as free.

Works Without Autoload

If FluidBufferPool does not exist as an Autoload, each FluidSimulationController and GroupNoiseCaptureViewport switches to a fallback behavior of generating SubViewports as their own child nodes. Performance will drop, but the operation itself is fine.

Settings

Item Description
pool_enabled If false, completely disables the pool. acquire() generates a new one every time, and release() immediately calls queue_free(). Used for baseline measurement when testing pool effects.
auto_scan_dirs List of directories to auto-scan at startup (res:// relative paths). Default is ["res://effects/"]. Recursively scans .tscn files contained here and automatically executes prewarm_from_scene().
prewarm_scenes Manually registers effect scenes (PackedScene) you want to pre-allocate.
prewarm_count How many sets to allocate for each scene. Increase this if multiple are used simultaneously.

Prewarm (Pre-warming) Details

prewarm_from_scene(scene, count)

Analyzes the PackedScene, automatically detects settings for contained FluidSimulationController and GroupNoiseCaptureViewport, and pre-generates necessary buffers. Scenes with auto_fit_to_window ON are calculated from the current window size. If called before the window size is determined (e.g., early in _ready()), buffers will not be allocated with the correct size.

GroupNoiseCaptureViewport instances with pool_subviewports OFF are skipped during scanning. Those with auto_align_to_fluid_simulation ON are automatically aligned to the size of the previously detected FluidSimulationController.

prewarm_gncv(size, group, count)

Pre-generates SubViewport pairs (MaskLayer and FinalLayer) for GroupNoiseCaptureViewport. Automatically called from within prewarm_from_scene.

Pool Capacity Limits

Constant Value Description
MAX_FREE_PER_KEY 8 Upper limit for holding free BufferSets of the same size and iteration count
MAX_FREE_TOTAL 100 Upper limit for holding free BufferSets across all keys

Free BufferSets exceeding the limit are queue_free()ed.


3 Likes