Transparent mesh material with (needAlphaBlending=true) miss depth rendering order with particles

Hello,

I create a particle (white square texture) that should be nearer to the camera than a plain mesh (Sprite - ./assets/background.png node), but the particle renders behind the mesh.

Some idea why is this happening?

Camera position: -380, 0, 0.001
Camera target: 1, 0, 0
Particle position: 0, 0, -10
Mesh position: 1000, 0, 90

Link to the test: Khanon.js 04 Loading 2D sprites and particles
Ctrl + Alt + Shift + I → Info of the scene.

The mesh’s texture is rendered by a custom shader material, in case that can be the reason.
Am I missing some transformation in the material?

BABYLON.Effect.ShadersStore[`spriteMesh${this.idShader}VertexShader`] = `
    precision highp float;
    attribute vec3 position;
    attribute vec2 uv;
    uniform mat4 worldViewProjection;
    varying vec2 vUv;

    void main() {
        vec4 p = vec4(position, 1.);
        gl_Position = worldViewProjection * p;
        vUv = uv;
    }
`
    BABYLON.Effect.ShadersStore[`spriteMesh${this.idShader}FragmentShader`] = `
    precision highp float;
    varying vec2 vUv;
    uniform sampler2D textureSampler;
    uniform int frame;
    uniform float alpha;

    void main() {
        int uOffset = frame % ${this.numCols};
        int vOffset = frame / ${this.numCols};
        vec2 computedUV = vec2(vUv.x * ${this.propCol.toPrecision(7)} + float(uOffset) * ${this.propCol.toPrecision(7)}, vUv.y * ${this.propRow.toPrecision(7)} + float(vOffset) * ${this.propRow.toPrecision(7)});
        vec4 color = texture2D(textureSampler, computedUV);
        gl_FragColor = vec4(color.rgb, alpha * color.a);
    }
`

const shaderMaterial = new BABYLON.ShaderMaterial(`spriteMaterial-${this.name}`, this.babylon.scene, `spriteMesh${this.idShader}`, {
      attributes: ['position', 'uv'],
      uniforms: ['worldViewProjection'],
      samplers: ['textureSampler'],
      needAlphaBlending: true
    })

Hello @Khanon , maybe your custom shader is breaking some depth check…
Could you setup a repro on a playground so that we can have a look ? :slight_smile:

1 Like

Your meshes (materials) are transparent, and transparent objects are rendered last, after the particle systems.

I think you set needAlphaBlending:true to the shader materials? As your meshes don’t seem to be transparent, you should remove this setting. If the materials must be transparent, you can set the renderingGroupId property of the particle system to 1, so that it is drawn after the transparent meshes.

2 Likes

You are absolutelly right, it is the needAlphaBlending:true property.

I can handle it now, I change the post title to something more explanatory about what have caused the issue.

Thanks!!

needAlphaBlending needs to be true to allow drawing .pngs on the mesh and respect the alpha channel.

I will have to set the renderingGroupId of particles to a high value by default, so particles will be always drawn after the mesh sprites.

This isn’t an optiaml solution because particles wont have a proper deph distribution, but I don’t figure out a better way to do it :frowning:

If I don’t set needAlphaBlending to true, the material textures are rendered like this:

instead of this:

renderingGroupId is the only solution?

This is a problem in the engine :frowning:

All sprite meshes need to support alpha blending to allow .png textures with alpha channel.

Setting a renderingGroupId high value by default for particles will drive to wrong depth distribution in many cases.

Forcing the user to set the renderingGroupId for all the created particles is complex to implement in a game with tons of elements.

Is there something I can do with the shader material or whatever to have a proper depth distribution using transparent meshes and particles?

Particles are not sorted, it would take too much time, and a particle system is rendered as a single draw call, for performance reason too. So, it’s not possible to interleave the rendering of meshes/sprites with the rendering of the particles of a particle system. You can only decide to render sprites/meshes before/after the particle systems by using the renderingGroupId property of meshes/spritees/particle systems.

Transparent objects (meshes, sprites, particles) do not write in the depth buffer, so they do not occlude themselves and they are all blended up. Drawing them in the wrong depth order is often not very visible, but of course it depends on your scene. Unfortunately, this is something we can’t do much about; it’s a well-known problem with transparent objects.

2 Likes

Following what @Evgeni_Popov said, here is a PG to run some occlusion tests with transparent mesh + particles :

Screencast from 14-03-2025 16:08:18

1 Like

Thanks for your time explaining it.

rederingGroupId will be a required property in particles definition.

  • For 3D games the user can set rederingGroupId=0 and ignore it.

  • For 2D games the user will be required to set the rederingGroupId to a value higher than the sprite behind it (normally the whole scene).