playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
3 lines (2 loc) • 5.32 kB
TypeScript
declare const _default: "\n #include \"screenDepthPS\"\n\n varying uv0: vec2f;\n\n uniform uFogCameraPos: vec3f;\n uniform uFogCameraFwd: vec3f;\n uniform uFogInvView: mat4x4f;\n uniform uFogProjScale: vec2f;\n uniform uFogTint: vec3f;\n uniform uFogLightColor: vec3f;\n uniform uFogLightDir: vec3f; // world space direction towards the light\n uniform uFogAmbient: vec3f;\n uniform uFogParams: vec4f; // x: density, y: height base, z: height falloff, w: max distance\n uniform uFogScatterParams: vec4f; // x: anisotropy, y: step count, z: temporal noise offset, w: shadow intensity\n\n #ifdef FOG_SHADOWS\n uniform uFogShadowMatrixPalette: array<mat4x4f, 4>;\n uniform uFogShadowCascadeDistances: vec4f;\n uniform uFogShadowParams: vec4f; // x: cascade count, y: bias, z: unused, w: max shadow distance\n #ifdef FOG_SHADOW_PCF\n var uFogShadowMap: texture_depth_2d;\n var uFogShadowMapSampler: sampler_comparison;\n #else\n var uFogShadowMap: texture_2d<f32>;\n var uFogShadowMapSampler: sampler;\n #endif\n\n fn sampleFogShadow(worldPos: vec3f, viewDepth: f32) -> f32 {\n\n // no shadow past the shadow distance\n if (viewDepth >= uniform.uFogShadowParams.w) {\n return 1.0;\n }\n\n // cascade index based on the view depth\n let comparisons: vec4f = step(uniform.uFogShadowCascadeDistances, vec4f(viewDepth));\n let cascadeIndex: i32 = i32(min(dot(comparisons, vec4f(1.0)), uniform.uFogShadowParams.x - 1.0));\n\n let shadowCoord: vec3f = (uniform.uFogShadowMatrixPalette[cascadeIndex] * vec4f(worldPos, 1.0)).xyz;\n let z: f32 = shadowCoord.z - uniform.uFogShadowParams.y;\n\n #ifdef FOG_SHADOW_PCF\n // hardware comparison on the depth format shadow map\n return textureSampleCompareLevel(uFogShadowMap, uFogShadowMapSampler, shadowCoord.xy, z);\n #else\n // manual comparison on the color format shadow map storing depth (PCSS / VSM)\n return step(z, textureSampleLevel(uFogShadowMap, uFogShadowMapSampler, shadowCoord.xy, 0.0).r);\n #endif\n }\n #endif\n\n // interleaved gradient noise\n fn fogNoise(fragCoord: vec2f) -> f32 {\n const magic: vec3f = vec3f(0.06711056, 0.00583715, 52.9829189);\n return fract(magic.z * fract(dot(fragCoord, magic.xy)));\n }\n\n // normalized Henyey-Greenstein phase function\n fn fogPhase(cosTheta: f32, g: f32) -> f32 {\n let g2: f32 = g * g;\n let denom: f32 = 1.0 + g2 - 2.0 * g * cosTheta;\n return (1.0 - g2) / (12.56637 * denom * sqrt(denom));\n }\n\n @fragment\n fn fragmentMain(input: FragmentInput) -> FragmentOutput {\n var output: FragmentOutput;\n\n // world space ray for this pixel (perspective projection). Note that uv0 addresses\n // textures (getImageEffectUV flips it on WebGPU), so undo the flip to get NDC\n let ndcUV: vec2f = vec2f(input.uv0.x, 1.0 - input.uv0.y);\n let ndc: vec2f = ndcUV * 2.0 - 1.0;\n let rayDir: vec3f = normalize((uniform.uFogInvView * vec4f(ndc * uniform.uFogProjScale, -1.0, 0.0)).xyz);\n\n // distance along the ray to the scene surface\n let rayDot: f32 = max(dot(rayDir, uniform.uFogCameraFwd), 0.001);\n let rayLength: f32 = min(getLinearScreenDepth(input.uv0) / rayDot, uniform.uFogParams.w);\n\n let stepCount: f32 = uniform.uFogScatterParams.y;\n let dt: f32 = rayLength / stepCount;\n\n // per-pixel noise offsets the samples along the ray to hide banding, and cycles over\n // frames when TAA is used to temporally accumulate to a smooth result\n let noise: f32 = fract(fogNoise(pcPosition.xy) + uniform.uFogScatterParams.z);\n\n // single phase function evaluation, as the light direction is constant along the ray\n let sunLight: vec3f = uniform.uFogLightColor * fogPhase(dot(rayDir, uniform.uFogLightDir), uniform.uFogScatterParams.x);\n\n var inscatter: vec3f = vec3f(0.0);\n var transmittance: f32 = 1.0;\n\n for (var i: f32 = 0.0; i < stepCount; i += 1.0) {\n let t: f32 = (i + noise) * dt;\n let pos: vec3f = uniform.uFogCameraPos + rayDir * t;\n\n // exponential height fog density, constant below the base height\n let density: f32 = uniform.uFogParams.x * exp(-uniform.uFogParams.z * max(pos.y - uniform.uFogParams.y, 0.0));\n\n var shadow: f32 = 1.0;\n #ifdef FOG_SHADOWS\n shadow = mix(1.0, sampleFogShadow(pos, t * rayDot), uniform.uFogScatterParams.w);\n #endif\n\n // accumulate in-scattered light and update transmittance (Beer-Lambert)\n let radiance: vec3f = sunLight * shadow + uniform.uFogAmbient;\n inscatter += transmittance * uniform.uFogTint * radiance * (density * dt);\n transmittance *= exp(-density * dt);\n\n if (transmittance < 0.005) {\n break;\n }\n }\n\n output.color = vec4f(inscatter, transmittance);\n return output;\n }\n";
export default _default;