From 0439dde4a81d3fd1ac2fed91907c14ecba33c8e5 Mon Sep 17 00:00:00 2001 From: Onek8 Date: Wed, 9 Jul 2025 23:15:54 +0000 Subject: [PATCH] Update leenkx/Shaders/deferred_light/deferred_light.frag.glsl --- .../deferred_light/deferred_light.frag.glsl | 989 ++++++++---------- 1 file changed, 433 insertions(+), 556 deletions(-) diff --git a/leenkx/Shaders/deferred_light/deferred_light.frag.glsl b/leenkx/Shaders/deferred_light/deferred_light.frag.glsl index 73788ff..a1c01f4 100644 --- a/leenkx/Shaders/deferred_light/deferred_light.frag.glsl +++ b/leenkx/Shaders/deferred_light/deferred_light.frag.glsl @@ -1,586 +1,463 @@ -#version 450 +//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" -#include "std/gbuffer.glsl" -#ifdef _Clusters -#include "std/clusters.glsl" -#endif -#ifdef _Irr -#include "std/shirr.glsl" -#endif -#ifdef _SSS -#include "std/sss.glsl" -#endif -#ifdef _SSRS -#include "std/ssrs.glsl" -#endif -uniform sampler2D gbufferD; -uniform sampler2D gbuffer0; -uniform sampler2D gbuffer1; - -#ifdef _gbuffer2 - uniform sampler2D gbuffer2; -#endif -#ifdef _EmissionShaded - uniform sampler2D gbufferEmission; -#endif - -#ifdef _VoxelGI -uniform sampler2D voxels_diffuse; -uniform sampler2D voxels_specular; -#else -#ifdef _VoxelAOvar -uniform sampler2D voxels_ao; -#endif -#endif -#ifdef _VoxelShadow -uniform sampler3D voxels; -uniform sampler3D voxelsSDF; -uniform float clipmaps[10 * voxelgiClipmapCount]; -#endif - -uniform float envmapStrength; -#ifdef _Irr -uniform vec4 shirr[7]; -#endif -#ifdef _Brdf -uniform sampler2D senvmapBrdf; -#endif -#ifdef _Rad -uniform sampler2D senvmapRadiance; -uniform int envmapNumMipmaps; -#endif -#ifdef _EnvCol -uniform vec3 backgroundCol; -#endif - -#ifdef _SSAO -uniform sampler2D ssaotex; -#else -#ifdef _SSGI -uniform sampler2D ssaotex; -#endif -#endif - -#ifdef _SSS -uniform vec2 lightPlane; -#endif - -#ifdef _SSRS -//!uniform mat4 VP; -uniform mat4 invVP; -#endif - -#ifdef _LightIES -//!uniform sampler2D texIES; +#ifdef _CSM +uniform vec4 casData[shadowmapCascades * 4 + 4]; #endif #ifdef _SMSizeUniform -//!uniform vec2 smSizeUniform; +uniform vec2 smSizeUniform; #endif -#ifdef _LTC -//!uniform vec3 lightArea0; -//!uniform vec3 lightArea1; -//!uniform vec3 lightArea2; -//!uniform vec3 lightArea3; -//!uniform sampler2D sltcMat; -//!uniform sampler2D sltcMag; #ifdef _ShadowMap - #ifdef _SinglePoint - //!uniform sampler2DShadow shadowMapSpot[1]; - //!uniform sampler2D shadowMapSpotTransparent[1]; - //!uniform mat4 LWVPSpot[1]; - #endif #ifdef _Clusters - //!uniform sampler2DShadow shadowMapSpot[4]; - //!uniform sampler2D shadowMapSpotTransparent[4]; - //!uniform mat4 LWVPSpotArray[4]; - #endif -#endif -#endif - -uniform vec2 cameraProj; -uniform vec3 eye; -uniform vec3 eyeLook; - -#ifdef _Clusters -uniform vec4 lightsArray[maxLights * 3]; - #ifdef _Spot - uniform vec4 lightsArraySpot[maxLights * 2]; - #endif -uniform sampler2D clustersData; -uniform vec2 cameraPlane; -#endif - -#ifdef _ShadowMap -#ifdef _SinglePoint - #ifdef _Spot - //!uniform sampler2DShadow shadowMapSpot[1]; - #ifdef _ShadowMapTransparent - //!uniform sampler2D shadowMapSpotTransparent[1]; - #endif - //!uniform mat4 LWVPSpot[1]; - #else - //!uniform samplerCubeShadow shadowMapPoint[1]; - #ifdef _ShadowMapTransparent - //!uniform samplerCube shadowMapPointTransparent[1]; - #endif - //!uniform vec2 lightProj; - #endif -#endif -#ifdef _Clusters - #ifdef _ShadowMapAtlas - #ifdef _SingleAtlas - uniform sampler2DShadow shadowMapAtlas; - #ifdef _ShadowMapTransparent - uniform sampler2D shadowMapAtlasTransparent; - #endif - #endif - #endif - #ifdef _ShadowMapAtlas - #ifndef _SingleAtlas - //!uniform sampler2DShadow shadowMapAtlasPoint; - #ifdef _ShadowMapTransparent - //!uniform sampler2D shadowMapAtlasPointTransparent; - #endif - #endif - //!uniform vec4 pointLightDataArray[maxLightsCluster * 6]; - #else - //!uniform samplerCubeShadow shadowMapPoint[4]; - #ifdef _ShadowMapTransparent - //!uniform samplerCube shadowMapPointTransparent[4]; - #endif - #endif - //!uniform vec2 lightProj; - #ifdef _Spot #ifdef _ShadowMapAtlas - #ifndef _SingleAtlas - //!uniform sampler2DShadow shadowMapAtlasSpot; - #ifdef _ShadowMapTransparent - //!uniform sampler2D shadowMapAtlasSpotTransparent; + uniform vec4 pointLightDataArray[maxLightsCluster * 6]; #endif - #endif - #else - //!uniform sampler2DShadow shadowMapSpot[4]; - #ifdef _ShadowMapTransparent - //!uniform sampler2D shadowMapSpotTransparent[4]; - #endif - #endif - //!uniform mat4 LWVPSpotArray[maxLightsCluster]; - #endif -#endif -#endif - -#ifdef _Sun -uniform vec3 sunDir; -uniform vec3 sunCol; - #ifdef _ShadowMap - #ifdef _ShadowMapAtlas - #ifndef _SingleAtlas - uniform sampler2DShadow shadowMapAtlasSun; - #ifdef _ShadowMapTransparent - uniform sampler2D shadowMapAtlasSunTransparent; - #endif - #endif - #else - uniform sampler2DShadow shadowMap; - #ifdef _ShadowMapTransparent - uniform sampler2D shadowMapTransparent; - #endif - #endif - uniform float shadowsBias; - #ifdef _CSM - //!uniform vec4 casData[shadowmapCascades * 4 + 4]; - #else - uniform mat4 LWVP; - #endif - #endif // _ShadowMap -#endif - -#ifdef _SinglePoint // Fast path for single light -uniform vec3 pointPos; -uniform vec3 pointCol; - #ifdef _ShadowMap - uniform float pointBias; - #endif - #ifdef _Spot - uniform vec3 spotDir; - uniform vec3 spotRight; - uniform vec4 spotData; #endif #endif -#ifdef _LightClouds -uniform sampler2D texClouds; -uniform float time; -#endif - -#include "std/light.glsl" - -in vec2 texCoord; -in vec3 viewRay; -out vec4 fragColor; - -void main() { - vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, roughness, metallic/matid - - vec3 n; - n.z = 1.0 - abs(g0.x) - abs(g0.y); - n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy); - n = normalize(n); - - float roughness = g0.b; - float metallic; - uint matid; - unpackFloatInt16(g0.a, metallic, matid); - - vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ - vec2 occspec = unpackFloat2(g1.a); - vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor - vec3 f0 = surfaceF0(g1.rgb, metallic); - - float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; - vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj); - vec3 v = normalize(eye - p); - float dotNV = max(dot(n, v), 0.0); - -#ifdef _gbuffer2 - vec4 g2 = textureLod(gbuffer2, texCoord, 0.0); -#endif - - -#ifdef _MicroShadowing - occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel -#endif - -#ifdef _Brdf - vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy; - vec3 F = f0 * envBRDF.x + envBRDF.y; -#else - vec3 F = f0; -#endif - -#ifndef _VoxelAOvar -#ifndef _VoxelGI - // Envmap -#ifdef _Irr - vec3 envl = shIrradiance(n, shirr); - - #ifdef _gbuffer2 - if (g2.b < 0.5) { - envl = envl; - } else { - envl = vec3(0.0); - } - #endif - - #ifdef _EnvTex - envl /= PI; - #endif -#else - vec3 envl = vec3(0.0); -#endif - -#ifdef _Rad - vec3 reflectionWorld = reflect(-v, n); - float lod = getMipFromRoughness(roughness, envmapNumMipmaps); - vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb; -#endif - -#ifdef _EnvLDR - envl.rgb = pow(envl.rgb, vec3(2.2)); - #ifdef _Rad - prefilteredColor = pow(prefilteredColor, vec3(2.2)); - #endif -#endif - - envl.rgb *= albedo; - -#ifdef _Brdf - envl.rgb *= 1.0 - F; //LV: We should take refracted light into account -#endif - -#ifdef _Rad // Indirect specular - envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT -#else - #ifdef _EnvCol - envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0? - #endif -#endif - - envl.rgb *= envmapStrength * occspec.x; - - fragColor.rgb = envl; -#endif -#endif - -#ifdef _VoxelGI - fragColor.rgb = textureLod(voxels_diffuse, texCoord, 0.0).rgb * voxelgiDiff; - if(roughness < 1.0 && occspec.y > 0.0) - fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * F * voxelgiRefl; -#else -#ifdef _VoxelAOvar - fragColor.rgb = textureLod(voxels_ao, texCoord, 0.0).rgb * voxelgiOcc; -#endif -#endif - - // Show voxels - // vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99); - // vec3 direction = vec3(0.0, 0.0, -1.0); - // vec4 color = vec4(0.0f); - // for(uint step = 0; step < 400 && color.a < 0.99f; ++step) { - // vec3 point = origin + 0.005 * step * direction; - // color += (1.0f - color.a) * textureLod(voxels, point * 0.5 + 0.5, 0); - // } - // fragColor.rgb += color.rgb; - - // Show SSAO - // fragColor.rgb = texture(ssaotex, texCoord).rrr; - -#ifdef _SSAO - // #ifdef _RTGI - // fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).rgb; - // #else - fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r; - // #endif -#else -#ifdef _SSGI - fragColor.rgb += textureLod(ssaotex, texCoord, 0.0).rgb; -#endif -#endif - -#ifdef _EmissionShadeless - if (matid == 1) { // pure emissive material, color stored in basecol - fragColor.rgb += g1.rgb; - fragColor.a = 1.0; // Mark as opaque - return; +#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); } -#endif -#ifdef _EmissionShaded - #ifdef _EmissionShadeless else { - #endif - vec3 emission = textureLod(gbufferEmission, texCoord, 0.0).rgb; - fragColor.rgb += emission; - #ifdef _EmissionShadeless + 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 -#ifdef _Sun - vec3 sh = normalize(v + sunDir); - float sdotNH = max(0.0, dot(n, sh)); - float sdotVH = max(0.0, dot(v, sh)); - float sdotNL = max(0.0, dot(n, sunDir)); - vec3 svisibility = vec3(1.0); - vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) + - specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y; +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)); + 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; - #ifdef _ShadowMap - #ifdef _CSM - svisibility = shadowTestCascade( - #ifdef _ShadowMapAtlas - #ifdef _ShadowMapTransparent - #ifndef _SingleAtlas - shadowMapAtlasSun, shadowMapAtlasSunTransparent - #else - shadowMapAtlas, shadowMapAtlasTransparent - #endif - #else - #ifndef _SingleAtlas - shadowMapAtlasSun - #else - shadowMapAtlas - #endif - #endif - #else + #ifdef _ShadowMapTransparent + if (transparent == false) { + vec4 shadowmap_transparent = texture(shadowMapTransparent, uv); + if (shadowmap_transparent.a < compare) + result *= shadowmap_transparent.rgb; + } + #endif + + 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; +} + +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; + #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; + + #ifdef _ShadowMapTransparent + if (transparent == false) { + vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml); + if (shadowmap_transparent.a < compare) + result *= shadowmap_transparent.rgb; + } + #endif + + return result; +} + +#ifdef _ShadowMapAtlas +// 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, + #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); // Handle edge cases by returning full light + } + + 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(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 + + #ifdef _ShadowMapTransparent + if (transparent == false) { + vec4 shadowmap_transparent = texture(shadowMapTransparent, uvtiled); + if (shadowmap_transparent.a < compare) + result *= shadowmap_transparent.rgb; + } + #endif + + return result; +} +#endif + +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, + #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)); + // 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, + #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 + 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, + #ifdef _ShadowMapTransparent + shadowMapTransparent, + #endif + lPos.xy, lPos.z - shadowsBias, smSize + #ifdef _ShadowMapTransparent + , transparent + #endif + ); + + // 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, #ifdef _ShadowMapTransparent - shadowMap, shadowMapTransparent - #else - shadowMap + shadowMapTransparent, #endif - #endif - , eye, p + n * shadowsBias * 10, shadowsBias + lPos.xy, lPos.z - shadowsBias, smSize #ifdef _ShadowMapTransparent - , false + , transparent #endif ); - #else - vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0); - if (lPos.w > 0.0) { - svisibility = shadowTest( - #ifdef _ShadowMapAtlas - #ifdef _ShadowMapTransparent - #ifndef _SingleAtlas - shadowMapAtlasSun, shadowMapAtlasSunTransparent - #else - shadowMapAtlas, shadowMapAtlasTransparent - #endif - #else - #ifndef _SingleAtlas - shadowMapAtlasSun - #else - shadowMapAtlas - #endif - #endif - #else - #ifdef _ShadowMapTransparent - shadowMap, shadowMapTransparent - #else - shadowMap - #endif - #endif - , lPos.xyz / lPos.w, shadowsBias - #ifdef _ShadowMapTransparent - , false - #endif - ); - } - #endif - #endif - #ifdef _VoxelShadow - svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy, -g2.rg).r) * voxelgiShad; - #endif - - #ifdef _SSRS - // vec2 coords = getProjectedCoord(hitCoord); - // vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy); - // float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0); - svisibility *= traceShadowSS(sunDir, p, gbufferD, invVP, eye); - #endif - - #ifdef _LightClouds - svisibility *= textureLod(texClouds, vec2(p.xy / 100.0 + time / 80.0), 0.0).r * dot(n, vec3(0,0,1)); - #endif - - #ifdef _MicroShadowing - // See https://advances.realtimerendering.com/other/2016/naughty_dog/NaughtyDog_TechArt_Final.pdf - svisibility *= clamp(sdotNL + 2.0 * occspec.x * occspec.x - 1.0, 0.0, 1.0); - #endif - - fragColor.rgb += sdirect * sunCol * svisibility; - -// #ifdef _Hair // Aniso -// if (matid == 2) { -// const float shinyParallel = roughness; -// const float shinyPerpendicular = 0.1; -// const vec3 v = vec3(0.99146, 0.11664, 0.05832); -// vec3 T = abs(dot(n, v)) > 0.99999 ? cross(n, vec3(0.0, 1.0, 0.0)) : cross(n, v); -// fragColor.rgb = orenNayarDiffuseBRDF(albedo, roughness, dotNV, dotNL, dotVH) + wardSpecular(n, h, dotNL, dotNV, dotNH, T, shinyParallel, shinyPerpendicular) * spec; -// } -// #endif - - #ifdef _SSS - if (matid == 2) { - #ifdef _CSM - int casi, casindex; - mat4 LWVP = getCascadeMat(distance(eye, p), casi, casindex); - #endif - fragColor.rgb += fragColor.rgb * SSSSTransmittance( - LWVP, p, n, sunDir, lightPlane.y, - #ifdef _ShadowMapAtlas - #ifndef _SingleAtlas - shadowMapAtlasSun - #else - shadowMapAtlas - #endif - #else - shadowMap - #endif - );//TODO implement transparent shadowmaps into the SSSSTransmittance() + float lerpAmt = smoothstep(0.0, blendThres, splitDist); + return mix(visibility2, visibility, lerpAmt); } - #endif - -#endif // _Sun - -#ifdef _SinglePoint - - fragColor.rgb += sampleLight( - p, n, v, dotNV, pointPos, pointCol, albedo, roughness, occspec.y, f0 - #ifdef _ShadowMap - , 0, pointBias, true - #ifdef _ShadowMapTransparent - , false - #endif - #endif - #ifdef _Spot - , true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight - #endif - #ifdef _VoxelShadow - , voxels, voxelsSDF, clipmaps, -g2.rg - #endif - #ifdef _MicroShadowing - , occspec.x - #endif - #ifdef _SSRS - , gbufferD, invVP, eye - #endif - ); - - #ifdef _Spot - #ifdef _SSS - if (matid == 2) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot[0], p, n, normalize(pointPos - p), lightPlane.y, shadowMapSpot[0]);//TODO implement transparent shadowmaps into the SSSSTransmittance() - #endif - #endif - -#endif - -#ifdef _Clusters - float viewz = linearize(depth * 0.5 + 0.5, cameraProj); - int clusterI = getClusterI(texCoord, viewz, cameraPlane); - int numLights = int(texelFetch(clustersData, ivec2(clusterI, 0), 0).r * 255); - - #ifdef HLSL - viewz += textureLod(clustersData, vec2(0.0), 0.0).r * 1e-9; // TODO: krafix bug, needs to generate sampler - #endif - - #ifdef _Spot - int numSpots = int(texelFetch(clustersData, ivec2(clusterI, 1 + maxLightsCluster), 0).r * 255); - int numPoints = numLights - numSpots; - #endif - - for (int i = 0; i < min(numLights, maxLightsCluster); i++) { - int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255); - fragColor.rgb += sampleLight( - p, - n, - v, - dotNV, - lightsArray[li * 3].xyz, // lp - lightsArray[li * 3 + 1].xyz, // lightCol - albedo, - roughness, - occspec.y, - f0 - #ifdef _ShadowMap - // light index, shadow bias, cast_shadows - , li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0 - #ifdef _ShadowMapTransparent - , false - #endif - #endif - #ifdef _Spot - , lightsArray[li * 3 + 2].y != 0.0 - , lightsArray[li * 3 + 2].y // spot size (cutoff) - , lightsArraySpot[li * 2].w // spot blend (exponent) - , lightsArraySpot[li * 2].xyz // spotDir - , vec2(lightsArray[li * 3].w, lightsArray[li * 3 + 1].w) // scale - , lightsArraySpot[li * 2 + 1].xyz // right - #endif - #ifdef _VoxelShadow - , voxels, voxelsSDF, clipmaps, -g2.rg - #endif - #ifdef _MicroShadowing - , occspec.x - #endif - #ifdef _SSRS - , gbufferD, invVP, eye - #endif - ); - } -#endif // _Clusters - fragColor.a = 1.0; // Mark as opaque + 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 \ No newline at end of file