#ifdef SHADOW uniform sampler2DShadow shadowtex0; #ifdef SHADOW_COLOR uniform sampler2DShadow shadowtex1; uniform sampler2D shadowcolor0; #endif // uniform sampler2D shadowtex0; // #ifdef SHADOW_COLOR // uniform sampler2D shadowtex1; // uniform sampler2D shadowcolor0; // #endif vec2 shadowOffsets[9] = vec2[9]( vec2( 0.0, 0.0), vec2( 0.0, 1.0), vec2( 0.7, 0.7), vec2( 1.0, 0.0), vec2( 0.7,-0.7), vec2( 0.0,-1.0), vec2(-0.7,-0.7), vec2(-1.0, 0.0), vec2(-0.7, 0.7) ); float biasDistribution[10] = float[10]( 0.0, 0.057, 0.118, 0.184, 0.255, 0.333, 0.423, 0.529, 0.667, 1.0 ); float getShadow(sampler2D shadowtex, vec2 shadowPosXY, float shadowPosZ) { float shadow = texture2D(shadowtex,shadowPosXY).x; shadow = clamp((shadow - shadowPosZ)*16384.0+0.5,0.0,1.0); return shadow; } float texture2DShadow2x2(sampler2D shadowtex, vec3 shadowPos) { shadowPos.xy -= 0.5 / shadowMapResolution; vec2 frac = fract(shadowPos.xy * shadowMapResolution); shadowPos.xy = (floor(shadowPos.xy * shadowMapResolution) + 0.5) / shadowMapResolution; float shadow0 = getShadow(shadowtex,shadowPos.st + vec2(0.0, 0.0) / shadowMapResolution, shadowPos.z); float shadow1 = getShadow(shadowtex,shadowPos.st + vec2(0.0, 1.0) / shadowMapResolution, shadowPos.z); float shadow2 = getShadow(shadowtex,shadowPos.st + vec2(1.0, 0.0) / shadowMapResolution, shadowPos.z); float shadow3 = getShadow(shadowtex,shadowPos.st + vec2(1.0, 1.0) / shadowMapResolution, shadowPos.z); float shadowx0 = mix(shadow0, shadow1, frac.y); float shadowx1 = mix(shadow2, shadow3, frac.y); float shadow = mix(shadowx0, shadowx1, frac.x); return shadow; } float texture2DShadow(sampler2D shadowtex, vec3 shadowPos) { return texture2DShadow2x2(shadowtex, shadowPos); } float texture2DShadow(sampler2DShadow shadowtex, vec3 shadowPos) { return shadow2D(shadowtex, shadowPos).x; } vec3 DistortShadow(vec3 worldPos, float distortFactor) { worldPos.xy /= distortFactor; worldPos.z *= 0.2; return worldPos * 0.5 + 0.5; } float GetCurvedBias(int i, float dither) { return mix(biasDistribution[i], biasDistribution[i+1], dither); } float InterleavedGradientNoise() { float n = 52.9829189 * fract(0.06711056 * gl_FragCoord.x + 0.00583715 * gl_FragCoord.y); return fract(n + frameCounter * 1.618); } vec3 SampleBasicShadow(vec3 shadowPos, float subsurface) { float shadow0 = texture2DShadow(shadowtex0, vec3(shadowPos.st, shadowPos.z)); vec3 shadowCol = vec3(0.0); #ifdef SHADOW_COLOR if (shadow0 < 1.0) { shadowCol = texture2D(shadowcolor0, shadowPos.st).rgb * texture2DShadow(shadowtex1, vec3(shadowPos.st, shadowPos.z)); #ifdef WATER_CAUSTICS shadowCol *= 4.0; #endif } #endif shadow0 *= mix(shadow0, 1.0, subsurface); shadowCol *= shadowCol; return clamp(shadowCol * (1.0 - shadow0) + shadow0, vec3(0.0), vec3(16.0)); } vec3 SampleFilteredShadow(vec3 shadowPos, float offset, float subsurface) { float shadow0 = 0.0; for (int i = 0; i < 9; i++) { vec2 shadowOffset = shadowOffsets[i] * offset; shadow0 += texture2DShadow(shadowtex0, vec3(shadowPos.st + shadowOffset, shadowPos.z)); } shadow0 /= 9.0; vec3 shadowCol = vec3(0.0); #ifdef SHADOW_COLOR if (shadow0 < 0.999) { for (int i = 0; i < 9; i++) { vec2 shadowOffset = shadowOffsets[i] * offset; vec3 shadowColSample = texture2D(shadowcolor0, shadowPos.st + shadowOffset).rgb * texture2DShadow(shadowtex1, vec3(shadowPos.st + shadowOffset, shadowPos.z)); #ifdef WATER_CAUSTICS shadowColSample *= 4.0; #endif shadowCol += shadowColSample; } shadowCol /= 9.0; } #endif shadow0 *= mix(shadow0, 1.0, subsurface); shadowCol *= shadowCol; return clamp(shadowCol * (1.0 - shadow0) + shadow0, vec3(0.0), vec3(16.0)); } vec3 GetShadow(vec3 worldPos, vec3 normal, float NoL, float subsurface, float skylight) { #if SHADOW_PIXEL > 0 worldPos = (floor((worldPos + cameraPosition) * SHADOW_PIXEL + 0.01) + 0.5) / SHADOW_PIXEL - cameraPosition; #endif vec3 shadowPos = ToShadow(worldPos); float distb = sqrt(dot(shadowPos.xy, shadowPos.xy)); float distortFactor = distb * shadowMapBias + (1.0 - shadowMapBias); #if SHADOW_BIAS == 1 if (subsurface == 0) { float distortNBias = distortFactor * shadowDistance / 256.0; distortNBias *= distortNBias; vec3 worldNormal = (gbufferModelViewInverse * vec4(normal, 0.0)).xyz; worldPos += worldNormal * distortNBias * 8192.0 / shadowMapResolution; shadowPos = ToShadow(worldPos); distb = sqrt(dot(shadowPos.xy, shadowPos.xy)); distortFactor = distb * shadowMapBias + (1.0 - shadowMapBias); } #endif shadowPos = DistortShadow(shadowPos, distortFactor); bool doShadow = shadowPos.x > 0.0 && shadowPos.x < 1.0 && shadowPos.y > 0.0 && shadowPos.y < 1.0; #ifdef OVERWORLD doShadow = doShadow && skylight > 0.001; #endif if (!doShadow) return vec3(1.0); float bias = 0.0; float offset = 1.0 / shadowMapResolution; #if SHADOW_BIAS == 0 float biasFactor = sqrt(1.0 - NoL * NoL) / NoL; float distortBias = distortFactor * shadowDistance / 256.0; distortBias *= 8.0 * distortBias; float distanceBias = sqrt(dot(worldPos.xyz, worldPos.xyz)) * 0.005; bias = (distortBias * biasFactor + distanceBias + 0.05) / shadowMapResolution; #else bias = 0.35 / shadowMapResolution; #endif if (subsurface > 0.0) { float blurFadeIn = clamp(distb * 20.0, 0.0, 1.0); float blurFadeOut = 1.0 - clamp(distb * 10.0 - 2.0, 0.0, 1.0); float blurMult = blurFadeIn * blurFadeOut * (1.0 - NoL); blurMult = blurMult * 1.5 + 1.0; offset = 0.0007 * blurMult; bias = 0.0002; } #if SHADOW_PIXEL > 0 bias += 0.0025 / SHADOW_PIXEL; #endif shadowPos.z -= bias; #ifdef SHADOW_FILTER vec3 shadow = SampleFilteredShadow(shadowPos, offset, subsurface); #else vec3 shadow = SampleBasicShadow(shadowPos, subsurface); #endif return shadow; } vec3 GetSubsurfaceShadow(vec3 worldPos, float subsurface, float skylight) { float gradNoise = InterleavedGradientNoise(); vec3 shadowPos = ToShadow(worldPos); float distb = sqrt(dot(shadowPos.xy, shadowPos.xy)); float distortFactor = distb * shadowMapBias + (1.0 - shadowMapBias); shadowPos = DistortShadow(shadowPos, distortFactor); vec3 subsurfaceShadow = vec3(0.0); vec3 offsetScale = vec3(0.002 / distortFactor, 0.002 / distortFactor, 0.001) * (subsurface * 0.75 + 0.25); for(int i = 0; i < 12; i++) { gradNoise = fract(gradNoise + 1.618); float rot = gradNoise * 6.283; float dist = (i + gradNoise) / 12.0; vec2 offset2D = vec2(cos(rot), sin(rot)) * dist; float offsetZ = -(dist * dist + 0.025); vec3 offset = vec3(offset2D, offsetZ) * offsetScale; vec3 samplePos = shadowPos + offset; float shadow0 = texture2DShadow(shadowtex0, samplePos); vec3 shadowCol = vec3(0.0); #ifdef SHADOW_COLOR if (shadow0 < 1.0) { shadowCol = texture2D(shadowcolor0, samplePos.st).rgb * texture2DShadow(shadowtex1, samplePos); #ifdef WATER_CAUSTICS shadowCol *= 4.0; #endif } #endif subsurfaceShadow += clamp(shadowCol * (1.0 - shadow0) + shadow0, vec3(0.0), vec3(1.0)); } subsurfaceShadow /= 12.0; subsurfaceShadow *= subsurfaceShadow; return subsurfaceShadow; } #else vec3 GetShadow(vec3 worldPos, vec3 normal, float NoL, float subsurface, float skylight) { #ifdef OVERWORLD float skylightShadow = smoothstep(0.866,1.0,skylight); skylightShadow *= skylightShadow; return vec3(skylightShadow); #else return vec3(1.0); #endif } vec3 GetSubsurfaceShadow(vec3 worldPos, float subsurface, float skylight) { return vec3(0.0); } #endif float GetCloudShadow(vec3 worldPos) { vec2 wind = vec2( frametime * CLOUD_SPEED * 0.0005, sin(frametime * CLOUD_SPEED * 0.001) * 0.005 ) * CLOUD_HEIGHT / 15.0; vec3 coveragePos = worldPos; worldPos += cameraPosition; vec3 worldLightVec = (gbufferModelViewInverse * vec4(lightVec, 0.0)).xyz; float cloudHeight = CLOUD_HEIGHT * CLOUD_VOLUMETRIC_SCALE + 70; worldPos.xz += worldLightVec.xz / worldLightVec.y * max(cloudHeight - worldPos.y, 0.0); coveragePos.xz += worldLightVec.xz / worldLightVec.y * -coveragePos.y; float scaledThickness = CLOUD_THICKNESS * CLOUD_VOLUMETRIC_SCALE; float cloudFadeOut = 1.0 - clamp((worldPos.y - cloudHeight) / scaledThickness, 0.0, 1.0); float coverageFadeOut = 1.0 - clamp((cameraPosition.y - cloudHeight) / scaledThickness, 0.0, 1.0); vec2 coord = worldPos.xz / CLOUD_VOLUMETRIC_SCALE; float sunCoverageSize = CLOUD_VOLUMETRIC_SCALE * 3.0 / worldLightVec.y; float sunCoverage = max(1.0 - length(coveragePos.xz) / sunCoverageSize, 0.0) * coverageFadeOut; coord.xy *= 0.004; #if CLOUD_BASE == 0 float noiseBase = texture2D(noisetex, coord * 0.25 + wind).r; #else float noiseBase = texture2D(noisetex, coord * 0.5 + wind).g; noiseBase = pow(1.0 - noiseBase, 2.0) * 0.5 + 0.25; #endif float noise = mix(noiseBase, 1.0, 0.33 * rainStrength) * 21.0; noise = max(noise - (sunCoverage * 3.0 + CLOUD_AMOUNT), 0.0); noise *= CLOUD_DENSITY * 0.125; noise *= (1.0 - 0.75 * rainStrength); noise = noise / sqrt(noise * noise + 0.5); noise *= cloudFadeOut; return 1.0 - noise * CLOUD_OPACITY * 0.85; }