Jump to content

Transparency using multiplicative blending


Recommended Posts

Hi forum,


i want to use order independent transparency (OIT)  by using the "multiplicative blending" approach outlined in this article.



Out of the box Babylon.js already supports the "sorting approach", by implementing the third rendering step documented here: (http://doc.babylonjs.com/tutorials/Transparency_and_How_Meshes_Are_Rendered).


But this will not work for overlapping meshes (which I need). In addition the multiplicative approach does not need the sorting step.


I believe, that "injecting" an additional  step after rendering sorted alpha blended meshes and before rendering sprites would be a solution. My question are:

  • Does this approach make sense in the Babylon world?
  • And if so, how could  I implement it without changing Babylon itself




Link to comment
Share on other sites

After looking at the source code, I believe Babylon is almost there!

What we want to do is: render  meshes after the opaque ones and with depth testing turned on, depth writing turned off and ALPHA_MULTIPLY as blending mode. That means:

  • create a mesh with Mesh.renderingGroupId = 3
  • create a material with Material.alphaMode=ALPHA_MULTIPLY and Material.disableDepthWrite=true

  • use this material for the mesh

could already do the trick and bypass the unwanted sorting step. (if the mesh does not end up in the array of transparent submeshes). I will give this a try, and see what happens.



If that does not work out one solution would be to:

  • Invent an new material class (ie LightAttenuationMaterial) or addtional properties in StandardMaterial as a flag to use the corresponing meshes in a new submesh category
  • Invent a new internal submesh category for use in RenderingGroup.render.
  • During scene traversal add meshes with the new material (or properties) in the new submesh category
  • In RengeringGroup.render draw the meshes in the new submesh category but without sorting by distance
Link to comment
Share on other sites

Unfortunately it does not work out. But I just don't know why. I have prepared a playground scene: http://www.babylonjs-playground.com/#1WIGS8#3


I can see:

  • The short cylinder is somewhat transparent against the long cylinder, but not against the ground. (Turn around a bit to see). The long cylinder is not transparent at all.
  • it is quit unclear to me, whether blending is correctly enabled. Both meshes use the same material, but behave different!
  • Uncommenting the "hasVertexAlpha" lines brings back transparency but only because the "transparent submeshes" in RenderingGroup.render and the sorting step in again.

I will try another idea:

  • Add a "disableDethSorting" property to StandardMaterial
  • Derive a new class from StandardMaterial, that always returns true from needsAlphaBlending() and sets the new property from above to true.
  • Tweak the RenderingGroup.render function to omit the sorting step, if the new property is set.

If that works out better, maybe that is the way to go

Link to comment
Share on other sites

Just changed the playground again and followed your advice.



The result is not physically correct or something but quite convincing and works our reasonable fast. Due to the way how  rendering currently works, is is not possible to bypass the (unnecessary) sorting step.


In "Three.JS" you can use the same setup with multiplicative blending and not  sorting anything in the renderer.

(Use "sortObject=false" on the renderer object,  use "renderOrder=???" on the meshes. enable blending,  disable depth writes and you are set. I have tested it and it works well!)

In theory this will give ThreeJS  a performance advantage over BABYLON, but that needs confirmation. Maybe the ThreeJS way of thinking, is an idea for a future BABYLON version.


In any way thanks for all support. Have a nice Christmas and a Happy New Year!

Link to comment
Share on other sites

For your example to be more realistic, you should disable back face culling: http://www.babylonjs-playground.com/#1WIGS8#7

This makes sense as both sides of the objects would retain a fraction of the light that goes through. That is assuming you want your objects to have a "tainted glass" sort of material, such as in the article you linked in the OP.

Also, sorting has absolutely no influence in this scene as we're using the multiply blend mode. Let's call A the color of the background, B the color of the wide cylinder and C the color of the narrow one. We have A x B x C = A x C x B.


Anyway, I'd be curious to see the end result you're looking for :)

Link to comment
Share on other sites

Thank you for the tip. Looks really good to me and maybe "TaintedGlassMaterial" could be a nice name for a future BABYLON class. I am totally happy with the results right now.


For the sorting: that is exactly the point I wanted to bring home!


Sorting is not necessary for multiplicative blending, because the blending operation is commutative.


In the rendering code below (taken from babylon-2.2) the steps for calculating the bounding box, camera distance and sorting could be totally avoided, if we could somehow hint the engine, that we are using some form of commutative blending function. If the number of meshes drawn with commutative blending is large, one could earn a real performance gain.

            // Transparent            if (this._transparentSubMeshes.length) {                // Sorting                for (subIndex = 0; subIndex < this._transparentSubMeshes.length; subIndex++) {                    submesh = this._transparentSubMeshes.data[subIndex];                    submesh._alphaIndex = submesh.getMesh().alphaIndex;                    submesh._distanceToCamera = submesh.getBoundingInfo().boundingSphere.centerWorld.subtract(this._scene.activeCamera.globalPosition).length();                }                var sortedArray = this._transparentSubMeshes.data.slice(0, this._transparentSubMeshes.length);                sortedArray.sort(function (a,  {                    // Alpha index first                    if (a._alphaIndex > b._alphaIndex) {                        return 1;                    }                    if (a._alphaIndex < b._alphaIndex) {                        return -1;                    }                    // Then distance to camera                    if (a._distanceToCamera < b._distanceToCamera) {                        return 1;                    }                    if (a._distanceToCamera > b._distanceToCamera) {                        return -1;                    }                    return 0;                });                // Rendering                                for (subIndex = 0; subIndex < sortedArray.length; subIndex++) {                    submesh = sortedArray[subIndex];                    submesh.render(true);                }
Link to comment
Share on other sites

r u use threejs before that? 

Not until the day before yesterday, You gave me a hint to try  :)


What I see, is that ThreeJS basically follows the same procedure for rendering. Draw opaque objects first and then the transparent objects. It implements the same sorting by camera distance or  some user defined index stuff.


But ThreeJS allows to disable the sorting step (which is not necessary for commutative blending functions)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...