PDA

View Full Version : [GLSL 330] No blending in the fragment shader.



Lolilolight
03-30-2015, 06:03 AM
Hi! Previously I've written a shader for my custom blending algorithm. (For order independant transparency)

The idea is to store the alpha value and the z of the nearest fragment to a texture, and then, I use this texture to apply the blending on the second pass. (I just have to change the blend equation a little when the first object drawn is nearest the next one.)

This works fine with GLSL 130 :



#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[1].a = pixel.a + color.a * (1 - pixel.a);
colors[0] = color * depth.a + pixel * (1 - depth.a);
colors[0].a = color.a + pixel.a * (1 - color.a);
bool b = (z >= depth.b);
gl_FragColor = colors[int(b)];
}


But, with GLSL 330 the blending is not working. (The second semi-transparent object hide the first one : if I draw a red rectangle and then a green rectangle, the color where the two rectangles overlap is green or it should be yellow.)



#version 330 core \n
layout(origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;
uniform sampler2D depthBuffer;
uniform sampler2D frameBuffer;
uniform sampler2D texSampler;
uniform vec3 resolution;
uniform float haveTexture;
in vec2 texCoords;
in vec4 f_color;
out vec4 fragColor;
in mat4 projMat;
void main () {
vec2 position = ( gl_FragCoord.xy / resolution.xy );
vec4 depth = texture(depthBuffer, position);
vec4 color = texture(frameBuffer, position);
vec4 pixel = (haveTexture == 1) ? texture(texSampler, texCoords.xy) * f_color : f_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[1].a = pixel.a + color.a * (1 - pixel.a);
colors[0] = color * depth.a + pixel * (1 - depth.a);
colors[0].a = color.a + pixel.a * (1 - color.a);
bool b = (z >= depth.b);
gl_FragColor = colors[int(b)];
};
}

Alfonse Reinheart
03-30-2015, 09:04 AM
vec4 pixel = (haveTexture==1) ? gl_Color * texture2D(texture, gl_TexCoord[0].xy) : gl_Color;

This texture lookup happens in non-uniform control flow (https://www.opengl.org/wiki/Sampler_%28GLSL%29#Non-uniform_flow_control). That leads to undefined behavior.

You need to do the texture access outside of a condition. Or you need to get derivatives outside of the condition, then use the textureGrad function inside of the condition.

Lolilolight
03-30-2015, 10:16 AM
Ok I've tried to make the texture access outside the condition but it doens't solve the problem. :/



#version 330 core \n
layout(origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;
uniform sampler2D depthBuffer;
uniform sampler2D frameBuffer;
uniform sampler2D texSampler;
uniform vec3 resolution;
uniform float haveTexture;
in vec2 texCoords;
in vec4 f_color;
in mat4 projMat;
void main () {
vec2 position = ( gl_FragCoord.xy / resolution.xy );
vec4 previous_depth_alpha = texture(depthBuffer, position);
vec4 previous_color = texture(frameBuffer, position);
vec4 texel = texture(texSampler, texCoords.xy);
vec4 current_color = (haveTexture == 1) ? texel * f_color : f_color;
float current_depth = (gl_FragCoord.w != 1.f) ? (inverse(projMat) * vec4(0, 0, 0, gl_FragCoord.w)).w : gl_FragCoord.z;
vec4 colors[2];
colors[1] = current_color * current_color.a + previous_color * (1 - current_color.a);
colors[1].a = current_color.a + previous_color.a * (1 - current_color.a);
colors[0] = previous_color * previous_depth_alpha.a + current_color * (1 - previous_depth_alpha.a);
colors[0].a = previous_color.a + previous_depth_alpha.a * (1 - previous_color.a);
bool b = (current_depth >= previous_depth_alpha.z);
gl_FragColor = colors[int(b)];
}

Lolilolight
03-30-2015, 10:31 AM
I've also tried to get rid of the condition like this.



vec4 texel = texture(texSampler, texCoords.xy);
vec4 colors[2];
colors[1] = texel * f_color;
colors[0] = f_color;
bool b = (haveTexture == 1);
vec4 current_color = colors[int(b)];


But it doesn't solve the problem too. :/

GClements
03-30-2015, 11:51 AM
vec4 pixel = (haveTexture==1) ? gl_Color * texture2D(texture, gl_TexCoord[0].xy) : gl_Color;

This texture lookup happens in non-uniform control flow (https://www.opengl.org/wiki/Sampler_%28GLSL%29#Non-uniform_flow_control).

haveTexture is a uniform.

mhagain
03-30-2015, 01:22 PM
haveTexture is a uniform.

That's not what non-uniform flow control means.

GClements
03-30-2015, 02:14 PM
That's not what non-uniform flow control means.
Then the GLSL specification needs to be corrected to match the "actual" meaning (which presumably means whatever vendors' implementations do in practice).

What it says is:



3.8.2 Uniform and Non-Uniform Control Flow

When executing statements in a fragment shader, control flow starts as uniform control flow; all fragments
enter the same control path into main(). Control flow becomes non-uniform when different fragments
take different paths through control-flow statements (selection, iteration, and jumps). Control flow
subsequently returns to being uniform after such divergent sub-statements or skipped code completes,
until the next time different control paths are taken.


According to that, it's not about whether multiple control paths exist, but whether different fragments actually take different paths (which clearly cannot happen if the condition involves only uniforms and constants).

Maybe that's not what the authors meant, but that's what it says (although I wouldn't be all that surprised if it's incorrect, given the attempt at defining "dynamically uniform" in 3.8.3).

And in fact, I'm unsure how any implementation would behave otherwise, unless it's specifically performing a compile-time check for whether a derivative is being requested within a branch and if so silently eliding it. The "obvious" implementation strategies (linear interpolation with a parameter of zero or one, dynamic recompilation, and conditional store) would only be affected by whether control flow actually diverged at execution time, not whether they might diverge based upon static analysis.

Alfonse Reinheart
03-30-2015, 02:29 PM
That's not what non-uniform flow control means.

Actually, it is. Well, maybe.

The spec says:


Control flow becomes non-uniform when different fragments take different paths through control-flow statements (selection, iteration, and jumps).

What is not mentioned is whether these "different fragments" are in the same rendering call or not. If the scope of the uniformality is only within the rendering call (or even the same primitive), then conditions based on "uniform" values do represent uniform flow control.

So it's unclear if it is uniform control flow or not.

*edit* Scooped by GClements, due to filing a bug report on this matter (https://www.khronos.org/bugzilla/show_bug.cgi?id=1321).

mhagain
03-30-2015, 03:58 PM
Hmmm, my reading of the spec is that "uniform flow control" essentially equates to "no flow control at all", but the statement that "This is similarly defined for other shader stages, based on the per-instance data items they process" definitely clouds the matter (it doesn't help either that it's not totally clear what is meant by "per-instance" here - I'm assuming that the section on "interface blocks" provides the definition, but it would be nicer to have an explicit definition).

D3D is quite a bit more explicit:

When flow control is present in a shader, the result of a gradient calculation requested inside a given branch path is ambiguous when adjacent pixels may execute separate flow control paths. Therefore, it is deemed illegal to use any pixel shader operation that requests a gradient calculation to occur at a location that is inside a flow control construct which could vary across pixels for a given primitive being rasterized.
So there the limit is per-primitive, and it seems reasonable to me to assume that this is a hardware constraint rather than an API constraint; if so then the same should apply to GL.