Reputation: 1607
I'm working on a WebGL program which implements shadow mapping. After computing the depth values at each fragment, I have an if statement at the end which computes the lighting based on whether the fragment is in a shadow or not.
gl_FragColor = vec4(calcLighting(light0, eye_dir, eye_dir_norm, normal), 1);
if (light_tex_coord.z - depth <= 0.0) {
gl_FragColor += vec4
( calcLighting(light1, eye_dir, eye_dir_norm, normal)
, 0.0
);
}
where depth
is the depth of the shadow map and light_tex_coord
is the fragment's position in the scene space of light1
. light1
is a point light rotating around the model, and light0
is a point light statically positioned at the camera.
The issue here is that the if branch is never taken, so the scene only has light0
applied to it. I've checked that depth
, light_tex_coord
, and calculateLighting
work correctly.
Here's the strange thing, though, replacing the above with the following code:
if (light_tex_coord.z - depth <= 0.0) {
gl_FragColor = vec4(0,1,0,1);
} else {
gl_FragColor = vec4(1,0,0,1);
}
Causes shadowed areas to be correctly drawn in red, and unshadowed to be drawn in green. That is, the branch is correctly evaluated. Replacing it with this:
gl_FragColor = vec4(calcLighting(light0, eye_dir, eye_dir_norm, normal), 1);
gl_FragColor += vec4
( calcLighting(light1, eye_dir, eye_dir_norm, normal)
, 0.0
);
Causes lighting to be correctly computed (sans shadows, though). It seems that when I call the more expensive calcLighting function in the if statement, it doesn't even bother taking it.
Further, I've tried applying the lighting in several ways including using the clamp
function; always doing the addition and using a terinary operator to multiply the second calcLighting
call by 1 or 0, and arranging my if statement in different ways. Nothing seems to work.
Is there something I'm missing about how branching works in webgl?
Upvotes: 8
Views: 4715
Reputation: 266
The topic is 2 years old but here's my 2 cents:
I had a similar problem and found an page on the Internet with a discussion containing the following sentence :
[...] (unless you do crazy stuff like image writes inside conditional blocks). [...]
So I tried to put the pixel color in a temporary variable
vec4 col;
local to main(), in the "if" statements I modify only col, and I set the pixel color only at the very end:
gl_FragColor = col;
This solved my problem. Of course it may require annoying additionnal programming to let the flow reach that last line in every situation.
Upvotes: 0
Reputation: 43319
Instead of the branch, have you considered something really radical like this:
gl_FragColor += vec4 (
calcLighting(light1, eye_dir, eye_dir_norm, normal)
, 0.0
) * abs (min (sign (light_tex_coord.z - depth), 0.0));
It is not the prettiest solution in the world, but it just might get you something more along the lines of what you are looking for. It basically takes your light_tex_coord.z - depth <= 0.0
conditional expression and makes it into a nice floating-point 0.0 or 1.0 that you can multiply the lighting by to either keep or discard the branch result. Kind of the way shaders used to work before dynamic flow control was introduced.
Upvotes: 0
Reputation: 866
Maybe the WebGl context does not support depth. Then expressions using it would be ignored.
You can check this with getContextAttributes()
Upvotes: 0