Reputation: 185
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?
Upvotes: 15
Views: 13256
Reputation: 21291
The method to get correct transparency of rendered objects independently from the order in which they are drawn is named Order Independent Transparency (OIT).
There is a great presentation from Nvidia summarizing the latest solutions in this area: Order Independent Transparency In OpenGL 4.x
"OpenGL 4.x" in the title is not accidental, because only in OpenGL 4.2 core appears Atomic Counters, which are important for OIT implementation.
One of the algorithms of OIT is as follows:
A simple alternative to OIT is to discard every second (odd) fragment in a fragment shader:
if (onlyOddFragments && ((int(gl_FragCoord.x) + int(gl_FragCoord.y)) % 2) == 1)
discard;
So you will see the objects farther from the camera in the discarded fragments. If multisample antialiasing (MSAA) is activated, then no checkboard pattern is visible even in lowest resolution.
Here is a video comparing the standard transparency approach where all triangles are output simply in order, as well as two above approaches. The implementation can be found in some open-source GitHub projects, e.g. here.
Upvotes: 2
Reputation: 51
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);
Upvotes: 2
Reputation: 2524
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.
Upvotes: 9
Reputation: 51845
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 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:
glFrontFace(GL_CW);
glFrontFace(GL_CW);
glFrontFace(GL_CCW);
glFrontFace(GL_CCW);
And lastly restore
glDisable(GL_BLEND);
glDepthFunc(depth_funct);
render all solid objects again
It is far from perfect but enough for my purposes it looks like this:
Upvotes: 21