reckfellENGINE

2D particle material: motion and visibility bounds

Separate emitter, simulation and drawing settings and configure conservative effect bounds.

On this page

Separate three configuration groups

GroupLocationExamples
Lifecycle and spaceGpuParticles2DAmount, Lifetime, OneShot, LocalCoords and seed
Motion and particle propertiesProcessMaterialDirection, Spread, InitialVelocityMin/Max, Gravity and Color
AppearanceTexture and Material on the CanvasItemParticle texture and its drawing material

ParticleProcessMaterial handles simulation. CanvasItemMaterial is a different drawing resource; do not use it in place of ProcessMaterial. A custom particle shader requires an appropriate ShaderMaterial and separate verification.

See the CPU/GPU guide for complete run steps and Particle2DExample.cs. The following file contains the full preset, including a CPU variant with similar initial parameters.

Particle2DPreset.cs
C#
using System;
using Reckfell;

public static class Particle2DPreset
{
    private static void Validate(int count)
    {
        if (count < 1 || count > 2048)
            throw new ArgumentOutOfRangeException(nameof(count));
    }

    public static ParticleProcessMaterial Motion() => new()
    {
        ParticleFlagDisableZ = true,
        Direction = new Vector3(0, -1, 0),
        Spread = 30,
        InitialVelocityMin = 60,
        InitialVelocityMax = 100,
        Gravity = new Vector3(0, 90, 0),
        Color = new Color(0.55f, 0.72f, 1)
    };

    public static GpuParticles2D Gpu(int count, bool oneShot, bool local)
    {
        Validate(count);
        return new GpuParticles2D
        {
            Emitting = false,
            Amount = count,
            Lifetime = 2,
            OneShot = oneShot,
            Explosiveness = oneShot ? 1 : 0,
            LocalCoords = local,
            UseFixedSeed = true,
            Seed = 42,
            FixedFps = 60,
            ProcessMaterial = Motion(),
            Texture = Texture(),
            VisibilityRect = new Rect2(-140, -120, 280, 320)
        };
    }

    public static CpuParticles2D Cpu(int count, bool oneShot, bool local)
    {
        Validate(count);
        return new CpuParticles2D
        {
            Emitting = false,
            Amount = count,
            Lifetime = 2,
            OneShot = oneShot,
            Explosiveness = oneShot ? 1 : 0,
            LocalCoords = local,
            UseFixedSeed = true,
            Seed = 42,
            FixedFps = 60,
            Direction = Vector2.Up,
            Spread = 30,
            InitialVelocityMin = 60,
            InitialVelocityMax = 100,
            Gravity = new Vector2(0, 90),
            Color = new Color(0.55f, 0.72f, 1),
            Texture = Texture()
        };
    }

    private static ImageTexture Texture()
    {
        using var image = Image.CreateEmpty(8, 8, false, Image.Format.Rgba8);
        image.Fill(Colors.Transparent);
        for (int y = 0; y < 8; y++)
        for (int x = 0; x < 8; x++)
            if (new Vector2(x - 3.5f, y - 3.5f).LengthSquared() <= 12)
                image.SetPixel(x, y, Colors.White);
        return ImageTexture.CreateFromImage(image);
    }
}

Configure direction and acceleration

Positive Y points down in 2D. Direction=(0,-1,0) emits upward, Spread=30 varies direction, InitialVelocityMin=60 and Max=100 select initial speed, and Gravity=(0,90,0) accelerates downward so particles eventually return.

The GPU material uses Vector3 even for this two-dimensional effect. ParticleFlagDisableZ=true constrains movement to XY. CpuParticles2D instead exposes Vector2 Direction and Gravity on the entity itself.

Speed and acceleration are different quantities. Do not multiply preset values by delta before assignment; simulation accounts for elapsed time. Some parameters are selected at birth, so Restart after changing initial conditions for a comparable preview.

Avoid implicit resource adaptation

A new ParticleProcessMaterial has 3D-oriented gravity (0,-9.8,0). In the current implementation, assigning that material to GpuParticles2D with DisableZ off enables the flag and changes gravity to (0,98,0). This is conditional adaptation, not a rule applied to every arbitrary material.

A shared resource is edited in place, potentially changing another emitter's settings. The preset assigns DisableZ and Gravity explicitly before attaching the material. Use independent resources or deliberate duplication for independent settings.

Calculate VisibilityRect

VisibilityRect is used for culling the whole GPU effect. It does not select spawn locations, contain particles or create a physics boundary. An undersized rectangle can hide an effect even while some particles should be visible on screen.

This preset uses Lifetime=2, initial speed at most 100, spread up to 30°, downward acceleration 90 and an 8×8 texture. For a stationary emitter at unit scale, conservative estimates are:

  • X extent: 100 × sin(30°) × 2 + 4 = 104 on either side;
  • minimum Y is at least −100² / (2 × 90) − 4, approximately −60;
  • maximum Y is at most 90 × 2² / 2 + 4 = 184, ignoring the upward initial velocity.

VisibilityRect=(-140,-120,280,320) spans X from −140 to 140 and Y from −120 to 200. It is a budget for this preset, not a universal material formula. Recalculate for different lifetime, acceleration, size, scale, additional forces or rapid emitter movement. Account especially for world-space particles left behind with LocalCoords=false: their emitter can move far away.

Current OpenGL CaptureRect limitation

In the real run, GpuParticles2D.CaptureRect() returned an empty rectangle with GPU-buffer-read errors despite visible 2D particles. The Compatibility implementation reads this path as ParticleInstanceData3D. This remains a recorded issue in the verified build rather than a successful bounds calculation.

The example therefore supplies VisibilityRect explicitly instead of relying on CaptureRect for automatic configuration. Do not interpret this call's empty result as no live particles. Reliability of this readback was not separately verified on other backends.

Tune without losing the cause

First hold Amount, Lifetime, seed and space constant. Then change one group at a time: direction/speed, gravity, appearance or bounds. Compare after Restart at equal observation times. FixedFps controls the simulation step rather than guaranteeing the window's display frame rate.

If an effect disappears, check lifecycle and visibility before changing material and trajectory. Increasing light Energy or CanvasItem.Modulate does not provide a missing ProcessMaterial or repair undersized bounds.

Lifecycle and complete level · GpuParticles2D reference

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.