Transparency rendering is a huge topic in 3D development. A great deal of effort has been put into finding a perfect solution to the problem of correctly displayed transparency.
The most common but most bad solution is transparency sorting. Delphi FMX uses this algorithm, by sorting elements in z-order to camera position.
Take a further read at: https://www.khronos.org/opengl/wiki/Transparency_Sorting
The result sometimes is correct, but in more complex scenery mostly incorrect, which some of you already found out by using multiple components of a TTextLayer3D. FMX renders artifacts or even hidden objects, if elements order is not correct, especially for intersected elements.
Many other methods also have their difficulties in incorrectness, performance-costs, memory-usage or complexicity:
- Depth Peeling by A-Buffer
- Depth Peeling by linked lists
- Moment-Based OIT
With v0.8.1.x we implemented weighted blended order-independent transparency.
This solution is more complex but leads to much better results, without any performance costs. In basically it renders all opaque objects at first. Afterwards it renders all translucent objects into a buffer by a specific algorithm. In the end all is merged together into the final image.
By implementing this method some significant changes have been made to Gorilla3D and to the usage of 3D elements. FMX already provides the “Opaque” property, but was not really used until now.
When building apps with transparent elements you now have to take care of the “Opaque” property. If you expect an object to be transparent (by color or by opacity value), you have to set Opaque to false. Is an object not transparent, you should leave Opaque to true. The “Opaque” property decides if an object is selected for opaque or translucent rendering inside of the rendering pipeline.
Weighted Blended Order-Independent Transparency is fast in rendering and leads to good results without any performance costs. In deed it's a bit faster than by transparency sorting, but due to management overhead the results are quite even. As this is a stochastic algorithm, the limitations are crucial.
Weighted Blended Order-Independent Transparency do not know zero transparency colors. This means, if you expect a nearly not-transparent object to be rendered, it may lead to overlay problems. Declare an object as “Opaque := false” when you deal with an opacity/alpha value of less than 0.75.
Weighted Blended Order-Independent Transparency is only available for OpenGL v4.2+ and OpenGL es v3.2+. Therefor on Windows platform everything should work fine. This limitation may lead to difficulties on Android platform. Since OpenGL es 3.2+ is only available since Android 5, we have to configure the NDK to a minimum API level of 21! On Delphi 10.3.3 you don't have to change anything since it is configured to API level 22 by default. But for older versions we have to change it. In the end this will lead to a minimum version of Android 5. Older version will not work with your app anymore!
Gorilla3D components are all able to handle the weighted blended order-independent transparency rendering, but Delphi FMX objects are not!
Because there is no general way of intersecting FMX 3D components in rendering, we have to add to some code to each translucent FMX 3D component used.
uses FMX.Types3D, FMX.Objects3D; type TMyCube = class(TCube) protected procedure Render(); override; end; implementation procedure TMyCube.Render(); begin // if WBOIT rendering is used and we have an opaque object, we need to // disable ZWrite but allow DepthTests -> this is not possible by FMX if (not Opaque) and (ZWrite) then begin Context.SetContextState(TContextState.csZWriteOff); Context.SetContextState(TContextState.csZTestOn); end; inherited; end;
For many 3D FMX components we provide alternatives, also for layers:
- TGorillaTextLayer3D (also optimized for android platform)
Besides component's setting you'll need a material that outputs all necessary image information for compositing.
Any extended material of TGorillaDefaultMaterial is able to write that data to the bound framebuffer object.
You can of course write your own shader. But you'll need to write the compressed fragment color (RGBA) and the alpha value (R8) to separated Render targets.
Next step: 2D FMX components