Custom GPU Particle System Cant use Alpha?

I have a custom GPU based particle solution Im whipping up for a project and Ive got everything working really well, but now that I added alpha support for color gradients over lifetime everything breaks.

I add “needAlphaBlending: true, needAlphaTesting: true,” or to the “this.mesh.hasVertexAlpha = true;” and get an error that BJS cant find a boundingSphere? Im assuming it needs the spheres to sort but since my particle faces are created on a compute shader that info does not exist?

How do I get my alpha working on the shader without this error dropping?

 // ── Mesh + render material ────────────────────────────────────────────────

    this.mesh = CreatePlane("particleMesh", { size: 1, updatable: true }, this.scene);

    this.mesh.isPickable = false;

    this.mesh.alwaysSelectAsActiveMesh = true;

    // this.mesh.hasVertexAlpha = true;




    // VertexData establishes the index buffer and a dummy position buffer.

    // The dummy position VB is immediately replaced below.

    const vd = new VertexData();

    vd.indices   = buildIndexData(count);

    vd.positions = new Float32Array(totalVerts * 3); // zeros; compute overwrites every frame

    vd.applyToMesh(this.mesh, true);




    // Replace the dummy position VB with the storage-backed output buffer.

    this.mesh.setVerticesBuffer(

      new VertexBuffer(engine, this.outPositionsBuffer.getBuffer(),

        VertexBuffer.PositionKind, false, true, 3, false), false

    );

    this.mesh.setVerticesBuffer(

      new VertexBuffer(engine, this.outScalesBuffer.getBuffer(),

        "particleScale", false, true, 3, false), false

    );

    this.mesh.setVerticesBuffer(

      new VertexBuffer(engine, this.outColorsBuffer.getBuffer(),

        "particleColor", false, true, 4, false), false

    );

    // Static quadCorner buffer — written once, never changes.

    this.mesh.setVerticesBuffer(

      new VertexBuffer(engine, buildCornerData(count), "quadCorner", false, false, 2, false), false

    );

This is how I setup the buffers.

And this is how I handle them in the compute shader.

// Colour over lifetime.

  let colt = sampleGrad(tc);

  var fc: vec4f;

  if (params.colorMode == 0u) { fc = p.spawnColor * colt; }

  else { fc = clamp(p.spawnColor + colt, vec4f(0.0), vec4f(1.0)); }


  // Write simulation state back.

  particles[i] = p;




  // Write 6 vertex entries for this particle.

  for (var v = 0u; v < 6u; v++) {

    let vi = i * 6u + v;

    let pb = vi * 3u;

    outPositions[pb]      = p.pos.x;

    outPositions[pb + 1u] = p.pos.y;

    outPositions[pb + 2u] = p.pos.z;

    let sb = vi * 3u;

    outScales[sb] = fs; outScales[sb + 1u] = fs; outScales[sb + 2u] = fs;

    let cb = vi * 4u;

    outColors[cb]      = fc.r; outColors[cb + 1u] = fc.g;

    outColors[cb + 2u] = fc.b; outColors[cb + 3u] = fc.a;

  }

Is there something Im doing wrong that is causing the boundingSphere error?

Should I be doing the alpha differently?

The crazy part is I can see in the debugger that it should not be undefined:

It’s hard to tell without a repro in the Playground.

What’s undefined is subMesh.getBoundingInfo(). Try to call subMesh.refreshBoundingInfo() on your mesh(es) and see if this helps (but I’m not sure why you would need to do that…). If you can step inside the subMesh.getBoundingInfo() call with the debugger, it should give some clues on what the problem could be.

Ok if you go to line 413 and uncomment the needsAlphaBlending you sill see the error.
I tried to force the bounding info on the sub mesh but still no luck!

Line 356 is where the mesh is created. Originally I was just doing a new Mesh but switched it to a CreatePlane to see if that would fix it but still no dice.

CreatePlane creates a mesh with 4 vertices, but you then update the mesh so that it has 6. This means that the system now thinks there could be multiple submeshes rather than just one, which means that instead of delegating getBoundingInfo to the mesh, it will use SubMesh._boundingInfo instead. But this variable is undefined because it hasn’t been created yet.

    mesh.subMeshes.forEach((subMesh)=>{
        subMesh.refreshBoundingInfo()
    })

is the fix, but it must be done after you updated the mesh with the new vertex buffers:

1 Like

Ohhh ok I did not even consider that I did 6 instead of 4 because the compute shader would still need to write 6 entries into the per-vertex storage buffers, but would need to map those 6 slots back to the 4 canonical vertices which seems like more work for less.

But in doing so did not even think about the fact it might have a second submesh.

I appreciate you a ton! Thanks.