OpenGL - How to create Order Independent transparency?
I've been working on a game engine for educational purposes and I came across this issue I cannot seem to find an answer for:
Alpha channel only works for objects that have already been drawn before the object that has the alpha channel (For example: in a scene with 3 objects, let's say a cat, a dog and a bottle(transparent). both the cat and the dog are behind the bottle; the dog is drawn first, the bottle second, the cat third. only the dog will be seen through the bottle).
Here's a picture of this issue:
I used C++ for the engine, Win32 API for the editor and GLSL for shading:
// some code here
vec4 alpha = texture2D(diffuse, texCoord0).aaaa;
vec4 negalpha = alpha * vec4(-1,-1,-1,1) + vec4(1,1,1,0);
vec4 textureComponentAlpha = alpha*textureComponent+negalpha*vec4(1,1,1,0);//(texture2D ( diffuse, texCoord0 ) ).aaaa;
gl_FragColor = (textureComponentAlpha + vec4(additiveComponent.xyz, 0)) * vec4(lightingComponent.xyz, 1);
In C++:
glEnable(GL_ALPHA_TEST);
glDepthFunc(GL_EQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
I assume it has something to do with the way the alpha test is made, or something like that.
Could anyone help me fix this, please?
I am using something similar to that answer linked by @RetoKoradi comment but I got double layered transparent models with textures (glass with both inner and outer surface) with fully solid machinery and stuff around.
For such scenes I am using also multi pass approach and the Z-sorting is done by sequence of setting front face.
- render all solid objects
-
render all transparent objects
This is the tricky part first I set
glGetIntegerv(GL_DEPTH_FUNC,&depth_funct); glDepthFunc(GL_ALWAYS); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_CULL_FACE);
I got the geometry layers stored separately (inner outer) so The Z-sorting is done like this:
- Render outer layer back faces with
glFrontFace(GL_CW);
- Render inner layer back faces with
glFrontFace(GL_CW);
- Render inner layer front faces with
glFrontFace(GL_CCW);
- Render outer layer front faces with
glFrontFace(GL_CCW);
And lastly restore
glDisable(GL_BLEND); glDepthFunc(depth_funct);
- Render outer layer back faces with
render all solid objects again
It is far from perfect but enough for my purposes it looks like this:
I cannot encourage you enough to have a look at this NVidia paper and the related blog post by Morgan McGuire.
This is pretty easy to implement and has great results overall.
Im not entirely sure this will help your situation, but do you have blending and alpha enabled? As in :
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);