reckfellENGINE

Create a 3D GPU particle effect

A working C# burst: materials, geometry, triggering and visibility diagnosis.

On this page

A GPU particle effect needs three separate pieces: an emitter (GpuParticles3D in C#), a material that simulates particle behavior, and geometry/materials that draw each particle. An emitting checkbox alone does not create visible geometry.

Create the effect in the editor

  1. Add a GPUParticles3D Entity to the 3D scene.
  2. Under Process Material, create a ParticleProcessMaterial. Start with a clear Direction, modest initial velocity and deliberate Gravity; do not tune several forces at once.
  3. Under Draw Passes, assign a Mesh to Pass 1, for example a small sphere for a functional test. Assign that mesh a visible surface material.
  4. Put the emitter in front of the active Camera3D. For a lit surface material, provide suitable lighting; for a visibility test, an unshaded surface removes that variable.
  5. Set a Visibility AABB that covers the whole effect, including moving particles and mesh size. This is a culling bound, not a collision box.
  6. Enable emission for a continuous effect, or enable One Shot and trigger a restart for a burst.

Check the active renderer and target device. The example below is executed in Forward+/Vulkan on Windows; it is not proof of every GPU/backend's behavior. Choosing GPU particles does not guarantee a performance improvement for every small effect.

Run a complete C# burst

Save this helper in your C# project. It returns a configured emitter without adding it to the tree:

C#
using Reckfell;

public static class ParticleBurst
{
    // A functional burst. Replace its geometry/material with your effect assets.
    // Add to the tree, then call Restart() to trigger it.
    public static GpuParticles3D Create()
    {
        var movement = new ParticleProcessMaterial
        {
            Direction = Vector3.Up,
            Spread = 25f,
            Gravity = Vector3.Zero,
            InitialVelocityMin = 0.6f,
            InitialVelocityMax = 0.6f,
        };
        var surface = new StandardMaterial3D
        {
            ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded,
            AlbedoColor = new Color(1f, 0.4f, 0.1f),
        };
        var mesh = new SphereMesh { Radius = 0.06f, Height = 0.12f, Material = surface };
        return new GpuParticles3D
        {
            Emitting = false,
            OneShot = true,
            Amount = 24,
            Lifetime = 0.75,
            Explosiveness = 1f,
            LocalCoords = true,
            UseFixedSeed = true,
            Seed = 42,
            ProcessMaterial = movement,
            DrawPass1 = mesh,
            VisibilityAabb = new Aabb(new Vector3(-2, -2, -2), new Vector3(4, 4, 4)),
        };
    }
}

From your existing Entity, call var burst = ParticleBurst.Create();, then AddChild(burst); and burst.Restart();. Place that Entity where the effect should begin. The example starts emission explicitly, uses a repeatable seed and produces a short orange burst. Its spheres are functional geometry, not finished smoke, vegetation or a photorealistic effect. Replace the draw asset/material for your actual art direction.

The process material controls motion; the sphere's surface material controls its visible color/shading. Changing the process material is not a substitute for assigning a draw mesh. Conversely, a draw mesh does not supply gravity or velocity simulation.

Stop, pause and retrigger are different

ActionEffect
Emitting = falseStop creating new particles. Existing particles can remain visible until they expire.
SpeedScale = 0Pause ordinary simulation progression; existing geometry can still be drawn. Moving a local-space emitter can still move its visible particles.
Restart()Clear/restart the cycle and enable emission. Suitable for explicitly retriggering a burst, including before the previous burst finished.
Wait for FinishedObserve completion of a one-shot cycle. It is not a completion signal for every continuous emitter stopped manually.

For an explosive one-shot, Emitting can already be false while particles remain alive. Do not use it as “nothing visible remains”. Connect Finished before triggering when completion matters. Repeatedly assigning Emitting true during an active one-shot is not equivalent to Restart and can cancel its pending completion notification in this implementation.

UseFixedSeed = true preserves the chosen Seed across the example's restart overloads. Restart(keepSeed: true) also preserves the current seed. A seed alone is not a promise of identical simulation across all drivers, time steps or engine builds.

1.0.0 timing limitation: after a long SpeedScale = 0 pause and resuming to 1, the tested one-shot can emit Finished while GPU particles are still visible. The scene timer multiplies accumulated elapsed time by the current speed scale; it is not a GPU-expiry fence. Do not recycle a time-scaled effect from this signal alone. Keeping a simple one-shot at fixed speed avoids this particular pause/resume case; validate a separate lifecycle policy when changing simulation time.

Choose the coordinate space

With LocalCoords = true, existing particles follow the emitter transform. Use it for an effect attached to a moving object. With false, spawned particles occupy world space while the emitter can move on, useful for a trail left behind. Configure the intended space before starting; changing it on a running effect is not an automatic visual-space conversion workflow.

The local GPU test pauses simulation, moves the emitter, and confirms both cases from rendered pixels. A paused particle system is therefore not necessarily a screen-frozen image when its emitter or camera moves.

Diagnose invisible particles

SymptomCheck first
No particles ever appearProcessMaterial, Draw Pass 1, mesh size, camera/layers, update timing and emission trigger.
Simulation runs but nothing drawsThe draw mesh and its surface material; removing DrawPass1 hides the tested effect without being a simulation stop command.
Effect disappears near the edge of viewVisibilityAabb must cover its full motion envelope; an offscreen bound can cull particles that would otherwise be onscreen.
Smoke looks like opaque cardsSurface transparency and texture alpha; process material is not the drawing material.
Process color does not affect the meshCheck that the surface material uses particle vertex color, for example Vertex Color → Use As Albedo in the standard material.
Burst will not retrigger as expectedUse Restart explicitly; distinguish an inactive cycle from an Emitting getter during a live cycle.
A moving emitter drags an intended trailCheck LocalCoords.

For an estimated bound, use the editor's generation tool or CaptureAabb() while the intended motion is actually running, then validate worst-case travel. A current-frame capture is not a bound for every future velocity, spawn shape or trail. Do not use an enormous AABB as a permanent fix: it prevents useful culling.

CPU particles use a different simulation path and a different feature set. Treat conversion as a separate effect-validation task; a successful conversion does not prove identical visuals, timing or performance. Advanced trails, collision, turbulence and sub-emitters have their own setup requirements.

The native evidence covers actual GPU pixels, burst completion/restart, emission stop, pause, coordinate spaces, bounds and draw-pass presence. No beauty illustration, CPU conversion, advanced particle features, performance budget or full export/device matrix is claimed here. See emitter properties for timing and cost controls.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.