Fabric API

Fabric API

106M Downloads

[fabric-renderer-api] Mesh with a BlendMode of TRANSLUCENT is hiding crumbling particles

natanfudge opened this issue · 16 comments

commented

For example this mesh (sorry for Kotlin)

        private fun hologramCubeMesh(): Mesh {
            val baseColor = 0xFF_FF_FF_FF.toInt()
            val renderer = RendererAccess.INSTANCE.renderer
            val mb = renderer.meshBuilder()
            val qe = mb.emitter
            val mat = renderer.materialFinder().blendMode(0, BlendMode.TRANSLUCENT).find()
            val atlas = MinecraftClient.getInstance().getSpriteAtlas(PlayerContainer.field_21668)
            val spriteBase = atlas.apply(Texture)
            qe.material(mat).square(Direction.UP, 0f, 0f, 1f, 1f, 0f)
                    .spriteBake(0, spriteBase, MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_NORMALIZED)
                    .spriteColor(0, baseColor, baseColor, baseColor, baseColor).emit()
            qe.material(mat).square(Direction.DOWN, 0f, 0f, 1f, 1f, 0f)
                    .spriteBake(0, spriteBase, MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_NORMALIZED)
                    .spriteColor(0, baseColor, baseColor, baseColor, baseColor).emit()
            qe.material(mat).square(Direction.EAST, 0f, 0f, 1f, 1f, 0f)
                    .spriteBake(0, spriteBase, MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_NORMALIZED)
                    .spriteColor(0, baseColor, baseColor, baseColor, baseColor).emit()
            qe.material(mat).square(Direction.WEST, 0f, 0f, 1f, 1f, 0f)
                    .spriteBake(0, spriteBase, MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_NORMALIZED)
                    .spriteColor(0, baseColor, baseColor, baseColor, baseColor).emit()
            qe.material(mat).square(Direction.NORTH, 0f, 0f, 1f, 1f, 0f)
                    .spriteBake(0, spriteBase, MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_NORMALIZED)
                    .spriteColor(0, baseColor, baseColor, baseColor, baseColor).emit()
            qe.material(mat).square(Direction.SOUTH, 0f, 0f, 1f, 1f, 0f)
                    .spriteBake(0, spriteBase, MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_NORMALIZED)
                    .spriteColor(0, baseColor, baseColor, baseColor, baseColor).emit()
            return mb.build()
        }

If you place a block behind the block that uses the mesh and break it, you won't be able to see the particles.

commented

Glass is cutout. Stained glass is translucent.

commented

Think this can be closed now.

commented

Let me test this on a mesh with cutout.

commented

If I switch BlendMode.TRANSLUCENT to BlendMode.CUTOUT it turns invisible, is that right?
image

commented

It depends. When CUTOUT is used, pixels from the texture will only be rendered if the pixel's alpha value is > 0.5. If your texture is designed for translucency (alpha < 0.5) then this is a correct render.

Mojang may fix the breaking particle issue, or they may not. Translucent rendering is tricky because it generally requires that quads be depth-sorted from the perspective of the viewer, which changes rapidly. This is feasible for static terrain quads, but for things like particles it can be prohibitive.

There are various tricks for dealing with it that don't require exotic algorithms but they all have trade-offs.

commented

There has to be some workaround, because my mod emits particles INSIDE the holograms, and if I make it translucent you can't see the particles...

commented

I can relate. I had the same issue issue in 1.14 for the Alchemical crafting blocks in DoomTree and eventually I resorted to using cutout particles.

Mojang doesn’t have good choices here. If translucent block quads update the depth buffer then translucent particles will always render behind terrain. (Seems to be what happens now). If they don’t update the depth buffer then translucent particles will always render in front of terrain.

If they don’t update the depth buffer for translucent terrain then it comes down to render order. If they render terrain first, then particles are always in front. If they render particles first, then particles are always in back.

If they depth sort the particles each frame and then interleave the rendering of terrain and particles according to depth, then performance suffers. More esoteric algorithms may be available but likely aren’t suitable or would be difficult to adapt to such a dynamic game with its unique run constraints.

Cutout particles don’t have this problem because they render before translucent and update the depth buffer. Translucent quads pixels “behind” the depth buffer are culled.

commented

Writing to the depth buffer from non-opaque draws is always wrong, it doesn't fix anything outside some corner cases. It generally leads to worse results as more opaque objects are likely to follow.

Fixing or changing this seems out of fabric-api's scope though, if it persists and someone actually confirmed it is happening, we may want to consider offering a blend layer without depth writes.

commented

Correct or not, it's what Mojang does. I was guessing before, but confirmed it just now:
image

Appears depth mask is also enabled for translucent terrain.

This is definitely out of API scope. A blend layer without depth writes would unfortunately solve nothing - unless something much more involved was also done. Even if the existing terrain and particles were changed to use the "corrected" material, that would simply mean that whatever renders last goes on top. Terrain quads would still be OK relative to themselves but translucent particles would always be either in front of or in back of terrain and their own draw order would be non-deterministic unless they are also sorted each frame.

There's no fix for this that isn't monstrously ambitious.

commented

As an aside, Mojang gets away with this cheat by tightly controlling the draw order of opaque vs translucent polygons. All solid and cutout quads are drawn first, and only then are translucent terrain and particles drawn. This is done in back-to-front order by render chunk. It's been that way for as long as I can remember.

commented

This appears to be a vanilla bug. Same thing happens with vanilla stained glass without API loaded.

commented

Oh, I tested it on glass and assumed it wasn’t.

commented

try in pre2 @natanfudge ?

commented

Is this still an issue?

commented

Should be closed IMO.

Note the fabulous mode introduced in 1.16 mostly fixes this. (And was, indeed "monstrously ambitious".)

Translucent layers do still update the depth buffer (and must, given how their rendering works) and afaik particles or translucent entities behind translucent terrain will still be hidden if fabulous mode is off.

commented

Closing for reason grondag has specified above.