PDA

View Full Version : [GLSL 130] Why I don't have the excepted final color in my shader ?



Lolilolight
03-09-2015, 07:33 AM
Hi everyone!

My plateform (Ubuntu 14.4 LTS 64 bits) only support opengl 3.0 and GLSL 130, I can't use pixel linked list from opengl 450.

I'm trying to find an alternative so :

Here is the technique which I use :

I clear an FBO with a clear color, at each time I draw something, I get the texture. I also use an FBO with transparent color, and I get a second texture. (for the depthbuffer)

In the first texture I save the color of each fragment and in the second texture I save the depth and the alpha of each fragment. (You'll see why further)

The first object is drawn with the classical blending equation so :

Blending : clear color (0, 0, 0, 1)

FB color : (0, 0, 0, 1)
DB z : 0
a : 0
Current Color : (1, 0, 0, 0.5)
Current z : 0
a = 0.5

Final color = (1, 0, 0, 0.5) * 0.5 + (0, 0, 0, 1) * (1 - 0.5) = (0.5, 0, 0, 0.75)

FB color is the color written in the first texture, DB z and a are the depth and the alpha written in the second texture, Current Color and Current z and a are the color, the z and the alpha of what I'm curretly drawing.

So the equation is SRCCOLOR * SRCALPHA + DSTCOLOR * (1 - SRCALPHA)

I need to change the blending equation, if the object I draw is behind the object which is already drawn, so in this case the bleding equation is

DSTCOLOR * DSTALPHA + SRCCOLOR * (1 - DSTALPHA)

So dstalpha is the alpha of the fragment which has been drawn previously, I give the same color in the two cases so it doesn't matter is an object is behind or before another one, in other worlds, the order in which I draw my objects doesn't matter.

Case 1 : (The object which is drawn is behind the object to draw.)

FB color : (1, 0, 0, 0.75)
DB z : 0
DB a : 0.5
Current Color : (1, 1, 0, 0.5)
Current z : 1
a : 0.5

Final color : (1, 1, 0, 0.5) * 0.5 + (1, 0, 0, 0.75) * (1 - 0.5) = (1, 0.5, 0, 0.652)

---------------------------------------------------------------------------

Cas 2 : (The object which is drawn is before the object I draw.)

FB color : (1, 0, 0, 0.75)
DB z : 1
DB a : 0.5
Current Color : (1, 1, 0, 0.5)
Current z : 0
a : 0.5

Final color : (1, 1, 0, 0.5) * 0.5 + (1, 0, 0, 0.75) * (1 - 0.5) = (1,0.5, 0, 0, 625)

So I desactivated the opengl blending and I've written this two shader (he one to generate the first texture, and the second to generate the second and the final texture that I draw on the window)

The vertex shader is very simple and is the same for both textures.



#version 130
out mat4 projMat;
void main () {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_FrontColor = gl_Color;
projMat = gl_ProjectionMatrix;
};


The fragment shader for the first texture is :



#version 130 \n
uniform sampler2D depthBuffer;
uniform sampler2D texture;
uniform vec3 resolution;"
uniform float haveTexture;
in mat4 projMat;
void main () {
vec2 position = ( gl_FragCoord.xy / resolution.xy );
vec4 color = texture2D(depthBuffer, position);
vec4 pixel = (haveTexture==1) ? gl_Color * texture2D(texture, gl_TexCoord[0].xy) : gl_Color;
float z = (gl_FragCoord.w != 1.f) ? (inverse(projMat) * vec4(0, 0, 0, gl_FragCoord.w)).w : gl_FragCoord.z;
vec4 colors[2];
colors[1] = vec4(z, pixel.a, z, pixel.a);
colors[0] = vec4(z, pixel.a, color.b, color.a);
bool b = (z >= color.z && pixel.a >= color.a);
gl_FragColor = colors[int(b)];
}


And the one for the second texture is :



#version 130 \n
uniform sampler2D depthBuffer;
uniform sampler2D frameBuffer;
uniform sampler2D texture;
uniform vec3 resolution;
uniform float haveTexture;
in mat4 projMat;
void main () {
vec2 position = ( gl_FragCoord.xy / resolution.xy );
vec4 depth = texture2D(depthBuffer, position);
vec4 color = texture2D(frameBuffer, position);
vec4 pixel = (haveTexture==1) ? gl_Color * texture2D(texture, gl_TexCoord[0].xy) : gl_Color;
float z = (gl_FragCoord.w != 1.f) ? (inverse(projMat) * vec4(0, 0, 0, gl_FragCoord.w)).w : gl_FragCoord.z;
vec4 colors[2];
colors[1] = pixel * pixel.a + color * (1 - pixel.a);
colors[0] = color * depth.g + pixel * (1 - depth.g);
bool b = (z >= depth.r);
gl_FragColor = colors[int(b)];


I avoid to use an if structure for optimization purposes.

My code simply draw two rectangles (a semi-transparent red one and a semi-transparent yellow one) on the textures with the shaders.



currentStates.shader = frameBufferGenerator;
frameBuffer->draw(m_instances[i]->getVertexArray(), currentStates);
frameBuffer->display();
currentStates.shader = depthBufferGenerator;
depthBuffer->draw(m_instances[i]->getVertexArray(), currentStates);
depthBuffer->display();


But the result I get is not the result that I expected.

The alpha blending is not performed. :/

Here is what I have :

1664

Why the blending isn't applied in my fragment shader ?

Thanks for help.

Lolilolight
03-09-2015, 07:45 AM
Erf I've found why, this is because, I draw every vertices of each quads at once for optimization purpose, so I need to find another solution, if anyone have an idea.

Lolilolight
03-09-2015, 08:47 AM
Now I draw the rectangles one by one and it works, but the number of draw call increase so the FPS decrease and I've a FPS between 15-20 instead of an FPS between 25-30.

The only solution that I've is to read/write fragments at the same time, so, I don't have to wait that the rectangle is drawn to get fragments colors and depth in the buffer but I don't thing this is possible. :/

GClements
03-10-2015, 07:09 AM
The only solution that I've is to read/write fragments at the same time, so, I don't have to wait that the rectangle is drawn to get fragments colors and depth in the buffer but I don't thing this is possible.
Not with OpenGL 3.x. You can do it with image load/store, but that requires OpenGL 4.2.

Lolilolight
03-11-2015, 04:29 AM
Arf..., ok, so I haven't any choise, I have to draw the faces of my object one by one.

It's slower but at least it works with order independant transparency.