UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

94 lines (93 loc) 4.3 kB
var shadowSoft_default = ` fn fractSinRand(uv: vec2f) -> f32 { let PI: f32 = 3.141592653589793; let a: f32 = 12.9898; let b: f32 = 78.233; let c: f32 = 43758.5453; let dt: f32 = dot(uv.xy, vec2f(a, b)); let sn: f32 = dt % PI; return fract(sin(sn) * c); } struct VogelDiskData { invNumSamples: f32, initialAngle: f32, currentPointId: f32, } fn prepareDiskConstants(data: ptr<function, VogelDiskData>, sampleCount: i32, randomSeed: f32) { let pi2: f32 = 6.28318530718; data.invNumSamples = 1.0 / f32(sampleCount); data.initialAngle = randomSeed * pi2; data.currentPointId = 0.0; } fn generateDiskSample(data: ptr<function, VogelDiskData>) -> vec2f { let GOLDEN_ANGLE: f32 = 2.399963; let r: f32 = sqrt((data.currentPointId + 0.5) * data.invNumSamples); let theta: f32 = data.currentPointId * GOLDEN_ANGLE + data.initialAngle; let offset: vec2f = vec2f(cos(theta), sin(theta)) * pow(r, 1.33); data.currentPointId = data.currentPointId + 1.0; return offset; } fn PCSSFindBlocker(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, avgBlockerDepth: ptr<function, f32>, numBlockers: ptr<function, i32>, shadowCoords: vec2f, z: f32, shadowBlockerSamples: i32, searchWidthUv: f32, randomSeed: f32) { var diskData: VogelDiskData; prepareDiskConstants(&diskData, shadowBlockerSamples, randomSeed); var blockerSum: f32 = 0.0; var numBlockers_local: i32 = 0; for( var i: i32 = 0; i < shadowBlockerSamples; i = i + 1 ) { let diskUV: vec2f = generateDiskSample(&diskData); let sampleUV: vec2f = shadowCoords + diskUV * searchWidthUv; let shadowMapDepth: f32 = textureSampleLevel(shadowMap, shadowMapSampler, sampleUV, 0.0).r; if ( shadowMapDepth < z ) { blockerSum = blockerSum + shadowMapDepth; numBlockers_local = numBlockers_local + 1; } } *avgBlockerDepth = blockerSum / f32(numBlockers_local); *numBlockers = numBlockers_local; } fn PCSSFilter(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, uv: vec2f, receiverDepth: f32, shadowSamples: i32, filterRadius: f32, randomSeed: f32) -> f32 { var diskData: VogelDiskData; prepareDiskConstants(&diskData, shadowSamples, randomSeed); var sum: f32 = 0.0; for (var i: i32 = 0; i < shadowSamples; i = i + 1) { let offsetUV: vec2f = generateDiskSample(&diskData) * filterRadius; let depth: f32 = textureSampleLevel(shadowMap, shadowMapSampler, uv + offsetUV, 0.0).r; sum = sum + step(receiverDepth, depth); } return sum / f32(shadowSamples); } fn PCSSDirectional(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, shadowCoords: vec3f, cameraParams: vec4f, softShadowParams: vec4f) -> f32 { let receiverDepth: f32 = shadowCoords.z; let receiverDepthClamped: f32 = min(receiverDepth, 0.9999); let randomSeed: f32 = fractSinRand(pcPosition.xy); let shadowSamples: i32 = i32(softShadowParams.x); let shadowBlockerSamples: i32 = i32(softShadowParams.y); let penumbraSize: f32 = softShadowParams.z; let penumbraFalloff: f32 = softShadowParams.w; let orthoRadius: f32 = cameraParams.x; let depthRange: f32 = cameraParams.y - cameraParams.z; let worldPerUv: f32 = 2.0 * orthoRadius; var filterRadius: f32; if (shadowBlockerSamples > 0) { let searchWidthUv: f32 = (penumbraSize * depthRange) / worldPerUv; var avgBlockerDepth: f32 = 0.0; var numBlockers: i32 = 0; PCSSFindBlocker(shadowMap, shadowMapSampler, &avgBlockerDepth, &numBlockers, shadowCoords.xy, receiverDepthClamped, shadowBlockerSamples, searchWidthUv, randomSeed); if (numBlockers < 1) { return 1.0; } let worldDist: f32 = max((receiverDepth - avgBlockerDepth) * depthRange, 0.0); let t: f32 = clamp(worldDist / depthRange, 0.0, 1.0); let shape: f32 = 1.0 - pow(1.0 - t, penumbraFalloff); let penumbraWorld: f32 = shape * penumbraSize * depthRange; filterRadius = penumbraWorld / worldPerUv; } else { filterRadius = penumbraSize / worldPerUv; } return PCSSFilter(shadowMap, shadowMapSampler, shadowCoords.xy, receiverDepthClamped, shadowSamples, filterRadius, randomSeed); } fn getShadowPCSS(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, shadowCoord: vec3f, shadowParams: vec4f, cameraParams: vec4f, softShadowParams: vec4f, lightDir: vec3f) -> f32 { return PCSSDirectional(shadowMap, shadowMapSampler, shadowCoord, cameraParams, softShadowParams); } `; export { shadowSoft_default as default };