GPUParticle2D as a Sub-Emitter doesn't respect lifetime?

Godot Version

v4.5.1.stable.official [f62fdbde1]

Question

Need help about GPUParticles2D with sub-emitter.

I’m using a sub-emitter to make a pseudo “trail” effect. The main emitter summons 12 particles in a burst, and in the particle shader process() I’ve put an emit_subparticle that summons a new particle that stays at the position of the current particle.

However when testing, it seems like the trail particles stop emitting after a short while. I’ve enlarged the amount on the sub-emitter and the effect was I get a few more loops. My current guess is somehow the sub-emitter is not cleaning up particles and not respecting the lifetime set on it, but I’m still new to particle system in Godot so I’d ask for help to spot any stupid mistakes from me first :slight_smile:

Here’s my main shader:

// main shader
shader_type particles;

const vec4 particle_colors[] = {
    vec4(1.0, 0.0, 0.0, 1),
    vec4(1.0, 0.5, 0.0, 1),
    vec4(1.0, 1.0, 0.0, 1),
    vec4(0.0, 1.0, 0.0, 1),
    vec4(0.0, 0.0, 1.0, 1),
    vec4(1.0, 0.0, 1.0, 1)
};

void start() {
    uint i = INDEX % 12u;
    TRANSFORM[0].x = 0.3;
    TRANSFORM[1].y = 0.25;
    TRANSFORM[3].x = float(i) * 100.0 / 6.0 - 100.0;
    TRANSFORM[3].y = 150.0;
    VELOCITY = vec3(0, -900.0, 0);
    COLOR = particle_colors[i / 2u];
}

void process() {
    COLOR.a -= 1.2 * DELTA;
    emit_subparticle(TRANSFORM, vec3(0.0, 0.0, 0.0), COLOR, CUSTOM, FLAG_EMIT_POSITION | FLAG_EMIT_COLOR | FLAG_EMIT_VELOCITY);
}

// sub-emitter shader
shader_type particles;

void start() {
    TRANSFORM[0].x = 0.2;
    TRANSFORM[1].y = 0.5;
}

void process() {
    COLOR.a -= 2.4 * DELTA;
    TRANSFORM[0].x -= 0.1 * DELTA;
    TRANSFORM[1].y -= 0.1 * DELTA;
}

Please let me know what else kind of information should I share! (Unfortunately can’t upload attachment as a user or I’d post a webm on what it looks like) I have a minimal project set up too in case anyone is interested to run directly, and in case if it is a bug I’m ready to submit to GitHub issues too :slight_smile:

Set things up with process material, convert it to shader and see how the converted shader code does things.

2 Likes

I just learned that there’s a “Convert” that I can view the underlying shader of a ParticleProcessMaterial directly, thank you!

The converted shader manages the ACTIVE builtin of a particle by calculating the lifetime percentage/progress stored in CUSTOM builtin. Once I manually manage ACTIVE in the shader of sub-emitter it seems to properly emit particle without stopping early!

I still don’t quite understand that why I don’t have to manage lifetime in the main shader myself, but I’m glad that I have a reference shader to debug from now on :slight_smile:

FYI, this is my revised shader:

// main shader
shader_type particles;

const vec4 particle_colors[] = {
    vec4(1.0, 0.0, 0.0, 1),
    vec4(1.0, 0.5, 0.0, 1),
    vec4(1.0, 1.0, 0.0, 1),
    vec4(0.0, 1.0, 0.0, 1),
    vec4(0.0, 0.0, 1.0, 1),
    vec4(1.0, 0.0, 1.0, 1)
};

void start() {
    uint i = INDEX % 12u;
    TRANSFORM[0].x = 0.3;
    TRANSFORM[1].y = 0.25;
    TRANSFORM[3].x = float(i) * 100.0 / 6.0 - 100.0;
    TRANSFORM[3].y = 150.0;
    VELOCITY = vec3(0, -900.0, 0);
    COLOR = particle_colors[i / 2u];
}

void process() {
    float alpha = COLOR.a - 1.2 * DELTA;
    if (alpha <= 0.0) {
        COLOR.a = 0.0;
        ACTIVE = false;
    } else {
        COLOR.a = alpha;
        emit_subparticle(TRANSFORM, vec3(0.0, 0.0, 0.0), COLOR, CUSTOM, FLAG_EMIT_POSITION | FLAG_EMIT_COLOR | FLAG_EMIT_VELOCITY);
    }
}

// sub-emitter shader
shader_type particles;

void start() {
    TRANSFORM[0].x = 0.2;
    TRANSFORM[1].y = 0.5;
}

void process() {
    float alpha = COLOR.a - 2.4 * DELTA;
    if (alpha <= 0.0) {
        COLOR.a = 0.0;
        ACTIVE = false;
    } else {
        COLOR.a = alpha;
        TRANSFORM[0].x -= 0.1 * DELTA;
        TRANSFORM[1].y -= 0.1 * DELTA;
    }
}

Better just set ACTIVE = false when the particles are fully transparent!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.