After some large programming sessions my mobile graphics engine is now compatible not only with OpenGLES but also with Vulkan. I followed some Vulkan tutorials but mainly the great Sascha Willems framework/examples. At this moment forward rendering, sorted transparencies, GPUSkinning…Works pretty well.
Next step was trying to add a depth render pass just to use it for several purposes like shadow mapping, I decided to implement it in the same way Sascha Willems did in ShadowMappingCascade example.
Depth render pass, glm math matrices, scene resources, shaders, light animation, camera parameters and cascade debugging are basically the same. I don’t flip Y geometry coordinate because I prefer making negative viewport height in addition to VK_KHR_MAINTENANCE1_EXTENSION_NAME
extension as Sascha Willems explains at Flipping the vulkan viewport.
Unfortunately some rendering issues are produced and a lot of time and effort pass without finding the solution.
Let me explain a list of problems I’ve experimented:
a) 4 cascades are generated in the shadow render pass using a depth attachment, first cascade looks fine but next cascades seems to have problems with inverted z-values and corresponding framebuffers don’t clear depth values correctly.
Depth pass preparation:
...
attachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
...
Depth pass rendering sets clear values like this:
VkClearValue clearValues[1];
clearValues[0].depthStencil = { 1.0f, 0 };
...
b) Split behavior is incorrect, I always see the last cascade (debugged with yellow color). To choose the cascade index in the fragment shader the following condition: inViewPos.z > ubo.vCascadeSplits[i]
is changed fragments are from near to far blue, green and red respectively (just the opposite than the Sascha example). I’m using right handled coordinate system. I tried to invert geometry z coordinate but it doesn’t fix the problem.
Scene fragment shader
...
// Get cascade index for the current fragment's view position
uint cascadeIndex = 0;
for(uint i = 0; i < SHADOW_MAP_CASCADE_COUNT - 1; ++i)
{
if(inViewPos.z > ubo.cascadeSplits[i])
{
cascadeIndex = i + 1;
}
}
...
c) Shadow projection is wrong. Multiplying cascade light view projection matrix to world pos doesn’t generate a correct texture coordinate to sample the shadow texture for the current cascade, the matrix is the same used in depth pass for cascade generation and seems more or less correct. #define GLM_FORCE_ZERO_TO_ONE
is declared.
Transform fragment world pos to cascade light space is done in the fragment shader as follows:
...
vec4 shadowCoord = (biasMat * ubo.cascadeViewProjMat[cascadeIndex]) * vec4(inPos, 1.0);
shadowCoord = shadowCoord / shadowCoord.w;
...
The below screenshot illustrates listed problems:
Has anyone experimented similar issues?
Thanks in advance