Order Independant Transparency
The Issue
Section titled “The Issue”If you play a bit with translucent contraptions, you might encounter the following scenario:
Yay, it works !
Boo, it doesn’t work !
The issue arises because translucent geometries are not sorted: the red glass is rendered first, followed by the blue glass. This works in the first scenario because the red glass is behind the blue glass, but it fails in the second scenario as the red glass occludes the blue glass.
The typical solution to this issue is to sort geometries back-to-front relative to the camera, which is the method used by Iris. However, Flywheel does not sort translucent geometries. Instead, it uses Order Independent Transparency (OIT), which, as the name suggests, does not require geometries to be ordered on the CPU first.
By default, OIT is disabled and translucent geometries are rendered in whatever order (this is our current situation). To enable it, we must create the colorwheel.properties
file and add the following line:
oit = true
This will enable OIT for both the gbuffers
and shadow
render passes. If we reload, we now have:
It’s even worse than before !
If you recall the OIT explanation, it is mentioned that, by default, all buffers are treated as frontmost. This means that only the translucent fragments closest to the camera will be rendered, which is our current situation. We now need to properly configure the OIT.
Gbuffers
Section titled “Gbuffers”Let’s do the inventory of our colortex
used in clrwl_gbuffers
with their alpha value:
colortex0
:RGB16
, blending enabled, alpha may vary.colortex1
:RGBA8
, blending enabled, alpha set to 1.0.colortex2
:RGBA8
, blending enabled, alpha set to 1.0.
The frontmost
mode has to be used in two cases:
- When the alpha value is always 1.0 (the fragment is opaque).
- When the buffer written to has its blending disabled.
For non opaque fragment with blending enabled, we have to assign a coefficient buffer to generate and use the appropriate transmittance-over-depth function.
In summary:
colortex0
is non opaque with blending enabled: declare and assign a coefficient buffer.colortex1
andcolortex2
are opaques: set them tofrontmost
.
We can also assign more suitable image formats to colortex1
and colortex2
than the default RGBA16F
, as we don’t need the default 16-bit precision.
oit = true
oit.gbuffers.coefficientRanks = 3
oit.gbuffers.colortex0 = 0
oit.gbuffers.colortex1 = frontmostoit.gbuffers.colortex1.format = RGBA8
oit.gbuffers.colortex2 = frontmostoit.gbuffers.colortex2.format = RGBA8
Shadow
Section titled “Shadow”The easiest way to handle shadows is to set all buffers to frontmost. This will match current behavior (as blending is disabled in the shadow pass by default), and the shadow color will be determined by the geometry closest to the sun/moon. This will also require less GPU work and less GPU memory compared to a fully utilized OIT.
oit.shadow.shadowcolor0 = frontmostoit.shadow.shadowcolor0.format = RGBA8
#version 330 compatibility
uniform sampler2D gtexture;
in vec2 texcoord;in vec4 glcolor;
/* RENDERTARGETS: 0 */layout(location = 0) out vec4 color;
void main() { color = texture(gtexture, texcoord); vec2 lmcoord; float ao; vec4 overlayColor;
clrwl_computeFragment(color, color, lmcoord, ao, overlayColor);}