441 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			GLSL
		
	
	
	
	
	
			
		
		
	
	
			441 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			GLSL
		
	
	
	
	
	
| //Transparent shadow implemented by Yvain Douard with reference:
 | |
| //https://wickedengine.net/2018/01/easy-transparent-shadow-maps/comment-page-1/
 | |
| 
 | |
| #ifndef _SHADOWS_GLSL_
 | |
| #define _SHADOWS_GLSL_
 | |
| 
 | |
| #include "compiled.inc"
 | |
| 
 | |
| #ifdef _CSM
 | |
| uniform vec4 casData[shadowmapCascades * 4 + 4];
 | |
| #endif
 | |
| 
 | |
| #ifdef _SMSizeUniform
 | |
| uniform vec2 smSizeUniform;
 | |
| #endif
 | |
| 
 | |
| #ifdef _ShadowMap
 | |
| 	#ifdef _Clusters
 | |
| 		#ifdef _ShadowMapAtlas
 | |
| 			uniform vec4 pointLightDataArray[maxLightsCluster * 6];
 | |
| 		#endif
 | |
| 	#endif
 | |
| #endif
 | |
| 
 | |
| #ifdef _ShadowMapAtlas
 | |
| // https://www.khronos.org/registry/OpenGL/specs/gl/glspec20.pdf // p:168
 | |
| // https://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/5337472/
 | |
| vec2 sampleCube(vec3 dir, out int faceIndex) {
 | |
| 	vec3 dirAbs = abs(dir);
 | |
| 	float ma;
 | |
| 	vec2 uv;
 | |
| 	if(dirAbs.z >= dirAbs.x && dirAbs.z >= dirAbs.y) {
 | |
| 		faceIndex = dir.z < 0.0 ? 5 : 4;
 | |
| 		ma = 0.5 / dirAbs.z;
 | |
| 		uv = vec2(dir.z < 0.0 ? -dir.x : dir.x, -dir.y);
 | |
| 	}
 | |
| 	else if(dirAbs.y >= dirAbs.x) {
 | |
| 		faceIndex = dir.y < 0.0 ? 3 : 2;
 | |
| 		ma = 0.5 / dirAbs.y;
 | |
| 		uv = vec2(dir.x, dir.y < 0.0 ? -dir.z : dir.z);
 | |
| 	}
 | |
| 	else {
 | |
| 		faceIndex = dir.x < 0.0 ? 1 : 0;
 | |
| 		ma = 0.5 / dirAbs.x;
 | |
| 		uv = vec2(dir.x < 0.0 ? dir.z : -dir.z, -dir.y);
 | |
| 	}
 | |
| 	// downscale uv a little to hide seams
 | |
| 	// transform coordinates from clip space to texture space
 | |
| 	#ifndef _FlipY
 | |
| 		return uv * 0.9976 * ma + 0.5;
 | |
| 	#else
 | |
| 		#ifdef HLSL
 | |
| 			return uv * 0.9976 * ma + 0.5;
 | |
| 		#else
 | |
| 			return vec2(uv.x * ma, uv.y * -ma) * 0.9976 + 0.5;
 | |
| 		#endif
 | |
| 	#endif
 | |
| }
 | |
| #endif
 | |
| 
 | |
| vec3 PCF(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec2 uv, const float compare, const vec2 smSize, const bool transparent) {
 | |
| 	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));
 | |
| 	result.x += texture(shadowMap, vec3(uv + (vec2(-1.0, 1.0) / smSize), compare));
 | |
| 	result.x += texture(shadowMap, vec3(uv + (vec2(0.0, -1.0) / smSize), compare));
 | |
| 	result.x += texture(shadowMap, vec3(uv, compare));
 | |
| 	result.x += texture(shadowMap, vec3(uv + (vec2(0.0, 1.0) / smSize), compare));
 | |
| 	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));
 | |
| 	result.x += texture(shadowMap, vec3(uv + (vec2(1.0, 1.0) / smSize), compare));
 | |
| 	result = result.xxx / 9.0;
 | |
| 
 | |
| 	if (transparent == false) {
 | |
| 		vec4 shadowmap_transparent = texture(shadowMapTransparent, uv);
 | |
| 		if (shadowmap_transparent.a < compare)
 | |
| 			result *= shadowmap_transparent.rgb;
 | |
| 	}
 | |
| 
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| float lpToDepth(vec3 lp, const vec2 lightProj) {
 | |
| 	lp = abs(lp);
 | |
| 	float zcomp = max(lp.x, max(lp.y, lp.z));
 | |
| 	zcomp = lightProj.x - lightProj.y / zcomp;
 | |
| 	return zcomp * 0.5 + 0.5;
 | |
| }
 | |
| 
 | |
| #ifndef _ShadowMapAtlas
 | |
| vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTransparent, vec3 lp, vec3 ml, float bias, vec2 lightProj, vec3 n, const bool transparent) {
 | |
|     const float s = shadowmapCubePcfSize;
 | |
|     float compare = lpToDepth(lp, lightProj) - bias * 1.5;
 | |
|     ml = ml + n * bias * 20;
 | |
|     #ifdef _InvY
 | |
|     ml.y = -ml.y;
 | |
|     #endif
 | |
|     
 | |
|     float shadowFactor = 0.0;
 | |
|     shadowFactor = texture(shadowMapCube, vec4(ml, compare));
 | |
|     shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, s, s), compare));
 | |
|     shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, s, s), compare));
 | |
|     shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, -s, s), compare));
 | |
|     shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, s, -s), compare));
 | |
|     shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, -s, s), compare));
 | |
|     shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, -s, -s), compare));
 | |
|     shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, s, -s), compare));
 | |
|     shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare));
 | |
|     shadowFactor /= 9.0;
 | |
|     
 | |
|     vec3 result = vec3(shadowFactor);
 | |
|     
 | |
|     if (transparent == false) {
 | |
|         vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml);
 | |
|         if (shadowmap_transparent.a < compare)
 | |
|             result *= shadowmap_transparent.rgb;
 | |
|     }
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifdef _ShadowMapAtlas
 | |
| vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const bool transparent) {
 | |
| 	const float s = shadowmapCubePcfSize; // TODO: incorrect...
 | |
| 	float compare = lpToDepth(lp, lightProj) - bias * 1.5;
 | |
| 	ml = ml + n * bias * 20;
 | |
| 	#ifdef _InvY
 | |
| 	ml.y = -ml.y;
 | |
| 	#endif
 | |
| 	vec3 result = vec3(0.0);
 | |
| 	result.x = texture(shadowMapCube, vec4(ml, compare));
 | |
| 	result.x += texture(shadowMapCube, vec4(ml + vec3(s, s, s), compare));
 | |
| 	result.x += texture(shadowMapCube, vec4(ml + vec3(-s, s, s), compare));
 | |
| 	result.x += texture(shadowMapCube, vec4(ml + vec3(s, -s, s), compare));
 | |
| 	result.x += texture(shadowMapCube, vec4(ml + vec3(s, s, -s), compare));
 | |
| 	result.x += texture(shadowMapCube, vec4(ml + vec3(-s, -s, s), compare));
 | |
| 	result.x += texture(shadowMapCube, vec4(ml + vec3(s, -s, -s), compare));
 | |
| 	result.x += texture(shadowMapCube, vec4(ml + vec3(-s, s, -s), compare));
 | |
| 	result.x += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare));
 | |
| 	result = result.xxx / 9.0;
 | |
| 
 | |
| 	if (transparent == false) {
 | |
| 		vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml);
 | |
| 		if (shadowmap_transparent.a < compare)
 | |
| 			result *= shadowmap_transparent.rgb;
 | |
| 	}
 | |
| 
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| // transform "out-of-bounds" coordinates to the correct face/coordinate system
 | |
| // https://www.khronos.org/opengl/wiki/File:CubeMapAxes.png
 | |
| vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 uv) {
 | |
| 	if (uv.x < 0.0) {
 | |
| 		if (faceIndex == 0) { // X+
 | |
| 			newFaceIndex = 4; // Z+
 | |
| 		}
 | |
| 		else if (faceIndex == 1) { // X-
 | |
| 			newFaceIndex = 5; // Z-
 | |
| 		}
 | |
| 		else if (faceIndex == 2) { // Y+
 | |
| 			newFaceIndex = 1; // X-
 | |
| 		}
 | |
| 		else if (faceIndex == 3) { // Y-
 | |
| 			newFaceIndex = 1; // X-
 | |
| 		}
 | |
| 		else if (faceIndex == 4) { // Z+
 | |
| 			newFaceIndex = 1; // X-
 | |
| 		}
 | |
| 		else { // Z-
 | |
| 			newFaceIndex = 0; // X+
 | |
| 		}
 | |
| 		uv = vec2(1.0 + uv.x, uv.y);
 | |
| 	}
 | |
| 	else if (uv.x > 1.0)  {
 | |
| 		if (faceIndex == 0) { // X+
 | |
| 			newFaceIndex = 5; // Z-
 | |
| 		}
 | |
| 		else if (faceIndex == 1) { // X-
 | |
| 			newFaceIndex = 4; // Z+
 | |
| 		}
 | |
| 		else if (faceIndex == 2) { // Y+
 | |
| 			newFaceIndex = 0; // X+
 | |
| 		}
 | |
| 		else if (faceIndex == 3) { // Y-
 | |
| 			newFaceIndex = 0; // X+
 | |
| 		}
 | |
| 		else if (faceIndex == 4) { // Z+
 | |
| 			newFaceIndex = 0; // X+
 | |
| 		}
 | |
| 		else { // Z-
 | |
| 			newFaceIndex = 1; // X-
 | |
| 		}
 | |
| 		uv = vec2(1.0 - uv.x, uv.y);
 | |
| 	}
 | |
| 	else if (uv.y < 0.0) {
 | |
| 		if (faceIndex == 0) { // X+
 | |
| 			newFaceIndex = 2; // Y+
 | |
| 		}
 | |
| 		else if (faceIndex == 1) { // X-
 | |
| 			newFaceIndex = 2; // Y+
 | |
| 		}
 | |
| 		else if (faceIndex == 2) { // Y+
 | |
| 			newFaceIndex = 5; // Z-
 | |
| 		}
 | |
| 		else if (faceIndex == 3) { // Y-
 | |
| 			newFaceIndex = 4; // Z+
 | |
| 		}
 | |
| 		else if (faceIndex == 4) { // Z+
 | |
| 			newFaceIndex = 2; // Y+
 | |
| 		}
 | |
| 		else { // Z-
 | |
| 			newFaceIndex = 2; // Y+
 | |
| 		}
 | |
| 		uv = vec2(uv.x, 1.0 + uv.y);
 | |
| 	}
 | |
| 	else if (uv.y > 1.0) {
 | |
| 		if (faceIndex == 0) { // X+
 | |
| 			newFaceIndex = 3; // Y-
 | |
| 		}
 | |
| 		else if (faceIndex == 1) { // X-
 | |
| 			newFaceIndex = 3; // Y-
 | |
| 		}
 | |
| 		else if (faceIndex == 2) { // Y+
 | |
| 			newFaceIndex = 4; // Z+
 | |
| 		}
 | |
| 		else if (faceIndex == 3) { // Y-
 | |
| 			newFaceIndex = 5; // Z-
 | |
| 		}
 | |
| 		else if (faceIndex == 4) { // Z+
 | |
| 			newFaceIndex = 3; // Y-
 | |
| 		}
 | |
| 		else { // Z-
 | |
| 			newFaceIndex = 3; // Y-
 | |
| 		}
 | |
| 		uv = vec2(uv.x, 1.0 - uv.y);
 | |
| 	} else {
 | |
| 		newFaceIndex = faceIndex;
 | |
| 	}
 | |
| 	// cover corner cases too
 | |
| 	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) {
 | |
| 	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
 | |
| 
 | |
| 	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;
 | |
| 	#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(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) {
 | |
| 	#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);
 | |
| }
 | |
| 
 | |
| #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));
 | |
| 	// int ci;
 | |
| 	// if (d < casData[c * 4].x) ci = 0;
 | |
| 	// else if (d < casData[c * 4].y) ci = 1 * 4;
 | |
| 	// else if (d < casData[c * 4].z) ci = 2 * 4;
 | |
| 	// else ci = 3 * 4;
 | |
| 	// Splits
 | |
| 	vec4 comp = vec4(
 | |
| 		float(d > casData[c * 4].x),
 | |
| 		float(d > casData[c * 4].y),
 | |
| 		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) {
 | |
| 	#ifdef _SMSizeUniform
 | |
| 	vec2 smSize = smSizeUniform;
 | |
| 	#else
 | |
| 	const vec2 smSize = shadowmapSize * vec2(shadowmapCascades, 1.0);
 | |
| 	#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);
 | |
| 
 | |
| 	// Blend cascade
 | |
| 	// https://github.com/TheRealMJP/Shadows
 | |
| 	const float blendThres = 0.15;
 | |
| 	float nextSplit = casData[c * 4][casi];
 | |
| 	float splitSize = casi == 0 ? nextSplit : nextSplit - casData[c * 4][casi - 1];
 | |
| 	float splitDist = (nextSplit - d) / splitSize;
 | |
| 	if (splitDist <= blendThres && casi != c - 1) {
 | |
| 		int casIndex2 = casIndex + 4;
 | |
| 		mat4 LWVP2 = mat4(
 | |
| 			casData[casIndex2    ],
 | |
| 			casData[casIndex2 + 1],
 | |
| 			casData[casIndex2 + 2],
 | |
| 			casData[casIndex2 + 3]);
 | |
| 
 | |
| 		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);
 | |
| 
 | |
| 		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);
 | |
| 	// if (ci == 8) albedo.rgb = vec3(0.0, 0.0, 1.0);
 | |
| 	// if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0);
 | |
| }
 | |
| #endif
 | |
| #endif
 |