// Separable SSS Transmittance Function, ref to sss_pass vec3 SSSSTransmittance(mat4 LWVP, vec3 p, vec3 n, vec3 l, float lightFar, sampler2DShadow shadowMap, vec3 sssColor, float sssRadius #ifdef _ShadowMapAtlas , vec4 tileBounds #endif ) { const float translucency = 0.85; vec4 shrinkedPos = vec4(p - 0.005 * n, 1.0); vec4 shadowPos = LWVP * shrinkedPos; vec2 shadowUV = shadowPos.xy / shadowPos.w; #ifdef _ShadowMapAtlas shadowUV = clamp(shadowUV, tileBounds.xy, tileBounds.zw); #endif float scale = 2.5 * (1.0 - translucency) / max(sssRadius, 0.001); float d1 = texture(shadowMap, vec3(shadowUV, shadowPos.z)).r; float d2 = shadowPos.z; d1 *= lightFar; d2 *= lightFar; float d = scale * abs(d1 - d2) * 1000.0; if (d > 10.0) return vec3(0.0); float dd = -d * d; vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); profile *= mix(vec3(1.0), sssColor, 0.8); return profile * clamp(0.5 + dot(l, -n), 0.0, 1.0); } #ifdef _ShadowMapAtlas vec3 SSSSTransmittanceCubeAtlas(sampler2DShadow shadowMap, vec3 lightPos, vec3 p, vec3 n, vec3 l, float lightFar, vec2 lightProj, int index, vec3 sssColor, float sssRadius) { const float translucency = 0.85; vec3 shrinkedPos = p - 0.005 * n; vec3 ld = normalize(shrinkedPos - lightPos); #ifdef _InvY ld.y = -ld.y; #endif float d2 = lpToDepth(ld, lightProj); int faceIndex = 0; int lightIndex = index * 6; vec2 uv = sampleCube(ld, faceIndex); vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy; #ifdef _FlipY uvtiled.y = 1.0 - uvtiled.y; #endif float d1 = texture(shadowMap, vec3(uvtiled, d2)).r; d1 *= lightFar; d2 *= lightFar; float scale = 2.5 * (1.0 - translucency) / max(sssRadius, 0.001); // d1/d2 are in meters, sssRadius is in mm, exponential constants are in mm^2 float d = scale * abs(d1 - d2) * 1000.0; // Convert distance to mm if (d > 10.0) return vec3(0.0); float dd = -d * d; vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); profile *= mix(vec3(1.0), sssColor, 0.8); return profile * clamp(0.5 + dot(l, -n), 0.0, 1.0); } #endif vec3 SSSSTransmittanceCube(samplerCubeShadow shadowMapCube, vec3 lightPos, vec3 p, vec3 n, vec3 l, float lightFar, vec2 lightProj, vec3 sssColor, float sssRadius) { const float translucency = 0.85; vec3 shrinkedPos = p - 0.005 * n; vec3 ld = normalize(shrinkedPos - lightPos); #ifdef _InvY ld.y = -ld.y; #endif float d2 = lpToDepth(ld, lightProj); float d1 = texture(shadowMapCube, vec4(ld, d2)).r; d1 *= lightFar; d2 *= lightFar; float scale = 2.5 * (1.0 - translucency) / max(sssRadius, 0.001); // d1/d2 are in meters, sssRadius is in mm, exponential constants are in mm^2 float d = scale * abs(d1 - d2) * 1000.0; // Convert distance to mm if (d > 10.0) return vec3(0.0); float dd = -d * d; vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); profile *= mix(vec3(1.0), sssColor, 0.8); return profile * clamp(0.5 + dot(l, -n), 0.0, 1.0); }