diff --git a/leenkx/Shaders/std/shadows.glsl b/leenkx/Shaders/std/shadows.glsl index 3ee7b23..7f74a78 100644 --- a/leenkx/Shaders/std/shadows.glsl +++ b/leenkx/Shaders/std/shadows.glsl @@ -58,7 +58,15 @@ vec2 sampleCube(vec3 dir, out int faceIndex) { } #endif -vec3 PCF(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec2 uv, const float compare, const vec2 smSize, const bool transparent) { +vec3 PCF(sampler2DShadow shadowMap, + #ifdef _ShadowMapTransparent + sampler2D shadowMapTransparent, + #endif + const vec2 uv, const float compare, const vec2 smSize + #ifdef _ShadowMapTransparent + , const bool transparent + #endif + ) { vec3 result = vec3(0.0); result.x = texture(shadowMap, vec3(uv + (vec2(-1.0, -1.0) / smSize), compare)); result.x += texture(shadowMap, vec3(uv + (vec2(-1.0, 0.0) / smSize), compare)); @@ -71,11 +79,13 @@ vec3 PCF(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec2 u result.x += texture(shadowMap, vec3(uv + (vec2(1.0, 1.0) / smSize), compare)); result = result.xxx / 9.0; + #ifdef _ShadowMapTransparent if (transparent == false) { vec4 shadowmap_transparent = texture(shadowMapTransparent, uv); if (shadowmap_transparent.a < compare) result *= shadowmap_transparent.rgb; } + #endif return result; } @@ -87,7 +97,15 @@ float lpToDepth(vec3 lp, const vec2 lightProj) { return zcomp * 0.5 + 0.5; } -vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const bool transparent) { +vec3 PCFCube(samplerCubeShadow shadowMapCube, + #ifdef _ShadowMapTransparent + samplerCube shadowMapCubeTransparent, + #endif + const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n + #ifdef _ShadowMapTransparent + , const bool transparent + #endif + ) { const float s = shadowmapCubePcfSize; // TODO: incorrect... float compare = lpToDepth(lp, lightProj) - bias * 1.5; ml = ml + n * bias * 20; @@ -106,11 +124,13 @@ vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTranspare result.x += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare)); result = result.xxx / 9.0; + #ifdef _ShadowMapTransparent if (transparent == false) { vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml); if (shadowmap_transparent.a < compare) result *= shadowmap_transparent.rgb; } + #endif return result; } @@ -209,32 +229,57 @@ vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 uv) { return uv; } -vec3 PCFFakeCube(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const int index, const bool transparent) { +vec3 PCFFakeCube(sampler2DShadow shadowMap, + #ifdef _ShadowMapTransparent + sampler2D shadowMapTransparent, + #endif + const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const int index + #ifdef _ShadowMapTransparent + , const bool transparent + #endif + ) { const vec2 smSize = smSizeUniform; // TODO: incorrect... const float compare = lpToDepth(lp, lightProj) - bias * 1.5; ml = ml + n * bias * 20; - int faceIndex = 0; const int lightIndex = index * 6; const vec2 uv = sampleCube(ml, faceIndex); - vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy; #ifdef _FlipY uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system #endif + if (any(lessThan(uvtiled, vec2(0.0))) || any(greaterThan(uvtiled, vec2(1.0)))) { + return vec3(1.0); // Or handle edge cases differently + } + vec3 result = vec3(0.0); - result.x += texture(shadowMap, vec3(uvtiled, compare)); - // soft shadowing - int newFaceIndex = 0; - uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, 0.0) / smSize))); - pointLightTile = pointLightDataArray[lightIndex + newFaceIndex]; - uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy; + // In PCFFakeCube(), modify the sampling pattern to be more robust: + const vec2 offsets[9] = vec2[]( + vec2(0, 0), + vec2(1, 0), vec2(-1, 0), vec2(0, 1), vec2(0, -1), + vec2(1, 1), vec2(-1, 1), vec2(1, -1), vec2(-1, -1) + ); + + for (int i = 0; i < 9; i++) { + vec2 sampleUV = uv + offsets[i] / smSize; + int newFaceIndex; + vec2 transformedUV = transformOffsetedUV(faceIndex, newFaceIndex, sampleUV); + pointLightTile = pointLightDataArray[lightIndex + newFaceIndex]; + uvtiled = pointLightTile.z * transformedUV + pointLightTile.xy; + #ifdef _FlipY + uvtiled.y = 1.0 - uvtiled.y; + #endif + result.x += texture(shadowMap, vec3(uvtiled, compare)); + } + result = result.xxx / 9.0; + + pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas + uvtiled = pointLightTile.z * uv + pointLightTile.xy; #ifdef _FlipY uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system #endif - result.x += texture(shadowMap, vec3(uvtiled, compare)); #ifdef _ShadowMapTransparent if (transparent == false) { @@ -244,88 +289,39 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, cons } #endif - result.x += texture(shadowMap, vec3(uvtiled, compare)); - - uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.0, -1.0) / smSize))); - pointLightTile = pointLightDataArray[lightIndex + newFaceIndex]; - uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy; - #ifdef _FlipY - uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system - #endif - result.x += texture(shadowMap, vec3(uvtiled, compare)); - - uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, -1.0) / smSize))); - pointLightTile = pointLightDataArray[lightIndex + newFaceIndex]; - uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy; - #ifdef _FlipY - uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system - #endif - result.x += texture(shadowMap, vec3(uvtiled, compare)); - - uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.0, 1.0) / smSize))); - pointLightTile = pointLightDataArray[lightIndex + newFaceIndex]; - uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy; - #ifdef _FlipY - uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system - #endif - result.x += texture(shadowMap, vec3(uvtiled, compare)); - - uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(1.0, -1.0) / smSize))); - pointLightTile = pointLightDataArray[lightIndex + newFaceIndex]; - uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy; - #ifdef _FlipY - uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system - #endif - result.x += texture(shadowMap, vec3(uvtiled, compare)); - - uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(1.0, 0.0) / smSize))); - pointLightTile = pointLightDataArray[lightIndex + newFaceIndex]; - uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy; - #ifdef _FlipY - uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system - #endif - result.x += texture(shadowMap, vec3(uvtiled, compare)); - - uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(1.0, 1.0) / smSize))); - pointLightTile = pointLightDataArray[lightIndex + newFaceIndex]; - uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy; - #ifdef _FlipY - uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system - #endif - result.x += texture(shadowMap, vec3(uvtiled, compare)); - - result = result.xxx / 9.0; - - pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas - uvtiled = pointLightTile.z * uv + pointLightTile.xy; - #ifdef _FlipY - uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system - #endif - - if (transparent == false) { - vec4 shadowmap_transparent = texture(shadowMapTransparent, uvtiled); - if (shadowmap_transparent.a < compare) - result *= shadowmap_transparent.rgb; - } - return result; } #endif -vec3 shadowTest(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 lPos, const float shadowsBias, const bool transparent) { +vec3 shadowTest(sampler2DShadow shadowMap, + #ifdef _ShadowMapTransparent + sampler2D shadowMapTransparent, + #endif + const vec3 lPos, const float shadowsBias + #ifdef _ShadowMapTransparent + , const bool transparent + #endif + ) { #ifdef _SMSizeUniform vec2 smSize = smSizeUniform; #else const vec2 smSize = shadowmapSize; #endif if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return vec3(1.0); - return PCF(shadowMap, shadowMapTransparent, lPos.xy, lPos.z - shadowsBias, smSize, transparent); + return PCF(shadowMap, + #ifdef _ShadowMapTransparent + shadowMapTransparent, + #endif + lPos.xy, lPos.z - shadowsBias, smSize + #ifdef _ShadowMapTransparent + , transparent + #endif + ); } #ifdef _CSM mat4 getCascadeMat(const float d, out int casi, out int casIndex) { const int c = shadowmapCascades; - // Get cascade index // TODO: use bounding box slice selection instead of sphere const vec4 ci = vec4(float(c > 0), float(c > 1), float(c > 2), float(c > 3)); @@ -341,21 +337,26 @@ mat4 getCascadeMat(const float d, out int casi, out int casIndex) { float(d > casData[c * 4].z), float(d > casData[c * 4].w)); casi = int(min(dot(ci, comp), c)); - // Get cascade mat casIndex = casi * 4; - return mat4( casData[casIndex ], casData[casIndex + 1], casData[casIndex + 2], casData[casIndex + 3]); - // if (casIndex == 0) return mat4(casData[0], casData[1], casData[2], casData[3]); // .. } -vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 eye, const vec3 p, const float shadowsBias, const bool transparent) { +vec3 shadowTestCascade(sampler2DShadow shadowMap, + #ifdef _ShadowMapTransparent + sampler2D shadowMapTransparent, + #endif + const vec3 eye, const vec3 p, const float shadowsBias + #ifdef _ShadowMapTransparent + , const bool transparent + #endif + ) { #ifdef _SMSizeUniform vec2 smSize = smSizeUniform; #else @@ -363,16 +364,22 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent #endif const int c = shadowmapCascades; float d = distance(eye, p); - int casi; int casIndex; mat4 LWVP = getCascadeMat(d, casi, casIndex); - vec4 lPos = LWVP * vec4(p, 1.0); lPos.xyz /= lPos.w; vec3 visibility = vec3(1.0); - if (lPos.w > 0.0) visibility = PCF(shadowMap, shadowMapTransparent, lPos.xy, lPos.z - shadowsBias, smSize, transparent); + if (lPos.w > 0.0) visibility = PCF(shadowMap, + #ifdef _ShadowMapTransparent + shadowMapTransparent, + #endif + lPos.xy, lPos.z - shadowsBias, smSize + #ifdef _ShadowMapTransparent + , transparent + #endif + ); // Blend cascade // https://github.com/TheRealMJP/Shadows @@ -391,13 +398,20 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent vec4 lPos2 = LWVP2 * vec4(p, 1.0); lPos2.xyz /= lPos2.w; vec3 visibility2 = vec3(1.0); - if (lPos2.w > 0.0) visibility2 = PCF(shadowMap, shadowMapTransparent, lPos2.xy, lPos2.z - shadowsBias, smSize, transparent); + if (lPos2.w > 0.0) visibility2 = PCF(shadowMap, + #ifdef _ShadowMapTransparent + shadowMapTransparent, + #endif + lPos.xy, lPos.z - shadowsBias, smSize + #ifdef _ShadowMapTransparent + , transparent + #endif + ); float lerpAmt = smoothstep(0.0, blendThres, splitDist); return mix(visibility2, visibility, lerpAmt); } return visibility; - // Visualize cascades // if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0); // if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0); @@ -405,4 +419,4 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent // if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0); } #endif -#endif +#endif \ No newline at end of file