playcanvas
Version:
PlayCanvas WebGL game engine
3 lines (2 loc) • 5.19 kB
TypeScript
declare const _default: "\n\nfn fractSinRand(uv: vec2f) -> f32 {\n let PI: f32 = 3.141592653589793;\n let a: f32 = 12.9898; let b: f32 = 78.233; let c: f32 = 43758.5453;\n let dt: f32 = dot(uv.xy, vec2f(a, b));\n let sn: f32 = dt % PI;\n return fract(sin(sn) * c);\n}\n\n// struct to hold precomputed constants and current state\nstruct VogelDiskData {\n invNumSamples: f32,\n initialAngle: f32,\n currentPointId: f32,\n}\n\n// prepare the Vogel disk constants and initialize the current state in the struct\nfn prepareDiskConstants(data: ptr<function, VogelDiskData>, sampleCount: i32, randomSeed: f32) {\n let pi2: f32 = 6.28318530718;\n data.invNumSamples = 1.0 / f32(sampleCount);\n data.initialAngle = randomSeed * pi2;\n data.currentPointId = 0.0;\n}\n\n\nfn generateDiskSample(data: ptr<function, VogelDiskData>) -> vec2f {\n let GOLDEN_ANGLE: f32 = 2.399963;\n let r: f32 = sqrt((data.currentPointId + 0.5) * data.invNumSamples);\n let theta: f32 = data.currentPointId * GOLDEN_ANGLE + data.initialAngle;\n\n let offset: vec2f = vec2f(cos(theta), sin(theta)) * pow(r, 1.33);\n\n data.currentPointId = data.currentPointId + 1.0;\n return offset;\n}\n\nfn PCSSFindBlocker(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, avgBlockerDepth: ptr<function, f32>, numBlockers: ptr<function, i32>,\n shadowCoords: vec2f, z: f32, shadowBlockerSamples: i32, penumbraSize: f32, invShadowMapSize: f32, randomSeed: f32) {\n\n var diskData: VogelDiskData;\n prepareDiskConstants(&diskData, shadowBlockerSamples, randomSeed);\n\n let searchWidth: f32 = penumbraSize * invShadowMapSize;\n var blockerSum: f32 = 0.0;\n var numBlockers_local: i32 = 0;\n\n for( var i: i32 = 0; i < shadowBlockerSamples; i = i + 1 ) {\n let diskUV: vec2f = generateDiskSample(&diskData);\n let sampleUV: vec2f = shadowCoords + diskUV * searchWidth;\n let shadowMapDepth: f32 = textureSampleLevel(shadowMap, shadowMapSampler, sampleUV, 0.0).r;\n if ( shadowMapDepth < z ) {\n blockerSum = blockerSum + shadowMapDepth;\n numBlockers_local = numBlockers_local + 1;\n }\n }\n *avgBlockerDepth = blockerSum / f32(numBlockers_local);\n *numBlockers = numBlockers_local;\n}\n\nfn PCSSFilter(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, uv: vec2f, receiverDepth: f32, shadowSamples: i32, filterRadius: f32, randomSeed: f32) -> f32 {\n\n var diskData: VogelDiskData;\n prepareDiskConstants(&diskData, shadowSamples, randomSeed);\n\n var sum: f32 = 0.0;\n for (var i: i32 = 0; i < shadowSamples; i = i + 1) {\n let offsetUV: vec2f = generateDiskSample(&diskData) * filterRadius;\n let depth: f32 = textureSampleLevel(shadowMap, shadowMapSampler, uv + offsetUV, 0.0).r;\n sum = sum + step(receiverDepth, depth);\n }\n return sum / f32(shadowSamples);\n}\n\nfn getPenumbra(dblocker: f32, dreceiver: f32, penumbraSize: f32, penumbraFalloff: f32) -> f32 {\n let dist: f32 = dreceiver - dblocker;\n let penumbra: f32 = 1.0 - pow(1.0 - dist, penumbraFalloff);\n return penumbra * penumbraSize;\n}\n\nfn PCSSDirectional(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, shadowCoords: vec3f, cameraParams: vec4f, softShadowParams: vec4f) -> f32 {\n\n let receiverDepth: f32 = shadowCoords.z;\n let randomSeed: f32 = fractSinRand(pcPosition.xy);\n let shadowSamples: i32 = i32(softShadowParams.x);\n let shadowBlockerSamples: i32 = i32(softShadowParams.y);\n let penumbraSize: f32 = softShadowParams.z;\n let penumbraFalloff: f32 = softShadowParams.w;\n\n let shadowMapSize: i32 = i32(textureDimensions(shadowMap, 0).x);\n var invShadowMapSize: f32 = 1.0 / f32(shadowMapSize);\n invShadowMapSize = invShadowMapSize * (f32(shadowMapSize) / 2048.0);\n\n var penumbra: f32;\n\n // contact hardening path\n if (shadowBlockerSamples > 0) {\n\n // find average blocker depth\n var avgBlockerDepth: f32 = 0.0;\n var numBlockers: i32 = 0;\n PCSSFindBlocker(shadowMap, shadowMapSampler, &avgBlockerDepth, &numBlockers, shadowCoords.xy, receiverDepth, shadowBlockerSamples, penumbraSize, invShadowMapSize, randomSeed);\n\n // early out when no blockers are present\n if (numBlockers < 1) {\n return 1.0;\n }\n\n // penumbra size is based on the blocker depth\n penumbra = getPenumbra(avgBlockerDepth, shadowCoords.z, penumbraSize, penumbraFalloff);\n\n } else {\n\n // constant filter size, no contact hardening\n penumbra = penumbraSize;\n }\n\n let filterRadius: f32 = penumbra * invShadowMapSize;\n\n // filtering\n return PCSSFilter(shadowMap, shadowMapSampler, shadowCoords.xy, receiverDepth, shadowSamples, filterRadius, randomSeed);\n}\n\nfn getShadowPCSS(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, shadowCoord: vec3f, shadowParams: vec4f, cameraParams: vec4f, softShadowParams: vec4f, lightDir: vec3f) -> f32 { // lightDir unused? Kept param.\n return PCSSDirectional(shadowMap, shadowMapSampler, shadowCoord, cameraParams, softShadowParams);\n}\n";
export default _default;