ThreeJS and the transparent problem

There’s no satisfactory answer here yet (only workarounds that disable critical parts of the regular rendering abilities of the scene, which causes there to be other issues)

I’m not sure what a satisfactory answer would be – there are only workarounds. There is no magic answer that makes transparent rendering just work in every scenario. It’s a difficult problem that you have to work within the limitations of the graphics API to achieve – even on with newer DirectX and OpenGL versions it’s still an issue (though newer raytracing APIs may change this). The only best answer is artistry and to select a combination of “hacks” that work best for your scenario. This is what modern games have to do, as well.

Here are some of the techniques available to render transparency some of which require more effort than others within three.js.

  • Use alphaTest to clip transparent textures. You won’t be able to achieve partial transparency here.
  • Render transparent objects with depth write enabled which will lead to the background clipping you’re seeing.
  • Render transparent objects with no depth write and back to front sorting. This is the most common approach but can result in objects “flipping” order when moving the camera which can be undesireable.
  • Render partial transparency with a dither pattern while still writing to depth. This is also called “screendoor transparency”. Transparent objects will render on top of eachother coherently but the dither pattern may be undesirable. Performance may also be affected negatively.
  • Weighted, blended order independent transparency seems to an approach that takes some weighted average of transparent pixels but again it won’t give you the correct overlap look. But it will avoid “popping” as you move the camera.
  • Depth peeling will give you correct transparency but is performance intensive and requires rendering all the transparent objects in the scene multiple times to properly blend all layers of transparency.
  • Per fragment sorted transparency will give you correct transparency but again is performance intensive and may not even be feasible using current WebGL APIs. This involves creating a linked list of every transparent color and depth at every pixel and sorting them front to back before blending them for the final color.

I’m sure there are other approaches but the point is there’s a lot of options and there’s not one well accepted approach for rendering transparency correctly. You really just have to pick what works for your use case.

9 Likes