Clipping planes appear disabled when rendering shadows on iOS?

Hey All,

I’ve implemented cascaded shadow maps with PCF and ESM successfully already on my mac. However, when I run the same application on my ipad it appears as though the near or far clipping planes are no longer being used and I get large triangles spanning across my entire texture atlas when rendering the first cascade. I suspect this has something to do with the configuration of my framebuffers, or something my shadow casting shader is doing on mobile. I was curious if anyone is aware of things that could potentially disable the clipping planes, or a reason why my clipping planes may appear to be correct on desktop but not on mobile?

The only differences in code between the mobile and desktop versions that I’m aware of are that I do not disable the draw buffer on mobile since opengl es does not support glDrawBuffer(GL_NONE). I also do not enable GL_DEPTH_CLAMP. The latter obviously sounds suspect, but disabling it on desktop does not reproduce the same issue. I believe that disabling depth clamp should result in less writing to the depth buffer as opposed to more.

Here is some more information about my setup:

I’m constructing a framebuffer for shadow casting with only a depth texture (GL_DEPTH_COMPONENT32F). I’m attaching this to the depth attachment of the framebuffer. Notably, I’m not attaching anything to the color attachments of the framebuffer.

Shadow matrix construction:
I’m constructing an orthographic projection matrix that is fit to each cascade of the view frustrum and then rendering these cascades to a single wide texture atlas split evenly along its width. I use glm’s glm::ortho function to construct the appropriate orthographic clip matrices centered at the origin of each cascade with negative / positive values for left/right/near/far etc.

Shadow map generation:
I use glViewport to offset into the shadow map texture atlas at render time for each cascade. I use the appropriate shadow matrix to project the vertices into the directional light space and then use the following shader to write out the depth values. I’ve tried replacing this shader with one that does not touch gl_FragDepth but it didn’t help:

uniform int shadow_map_type;
void main() {
float dx = dFdx(gl_FragCoord.z);
float dy = dFdy(gl_FragCoord.z);
float biased_depth = gl_FragCoord.z + sqrt(dxdx + dydy)+0.003;
gl_FragDepth = biased_depth;

I’m trying to debug the issue by only rendering to the first cascade. Unfortunately, doing this results in a big black triangle gradually filling the entire texture atlas as I move my geometry into the first cascade’s view frustrum. I believe this triangle is coming from something that should have been clipped away by the near or far clip plans.

Any insights would be greatly appreciated!


I tracked down the issue. It appears that at least on my mobile device, glViewport only applies to the currently bound framebuffer. I had some state management code that only changed glViewport if I specified new values, but this state was being tracked globally as opposed to per viewport. This was likely my own misunderstanding about how glViewport works, but the fact that the desktop version worked without it makes me wonder if the behavior of glViewport is different on opengl es 3 vs. desktop gl.