UNPKG

gpu-curtains

Version:

gpu-curtains is a 3D WebGPU rendering engine. It can be used as a standalone 3D engine, but also includes extra classes focused on mapping 3d objects to DOM elements; It allows users to synchronize values such as position, sizing, or scale between them.

64 lines (49 loc) 2.56 kB
//#region src/core/shaders/chunks/fragment/head/get-PCF-point-shadow-contribution.ts /** Helper chunk to get the PCF soft shadow generated by a given {@link core/lights/PointLight.PointLight | PointLight}. */ const getPCFPointShadowContribution = ` fn getPCFPointShadowContribution(index: i32, shadowPosition: vec4f, fragmentPosition: vec2f, depthCubeTexture: texture_depth_cube) -> f32 { let pointShadow: PointShadowsElement = pointShadows.pointShadowsElements[index]; var visibility = 0.0; // for point lights, the uniform @vShadowCoord is re-purposed to hold // the vector from the light to the world-space position of the fragment. let lightToPosition: vec3f = shadowPosition.xyz; // For cube shadow maps, depth is stored as radial distance let distanceToLight: f32 = length(lightToPosition); if (distanceToLight < pointShadow.cameraNear || distanceToLight > pointShadow.cameraFar) { return 1.0; } // Direction from light to fragment // bd3D = base direction 3D let bd3D: vec3f = normalize(lightToPosition); let size: vec2u = textureDimensions(depthCubeTexture); let maxSize: f32 = f32(max(size.x, size.y)); let texelSize: f32 = 1.0 / maxSize; // Hardware PCF with LinearFilter gives us 4-tap filtering per sample // 5 samples using Vogel disk + IGN = effectively 20 filtered taps with better distribution let radius: f32 = pointShadow.radius * texelSize; // Use IGN to rotate sampling pattern per pixel let phi: f32 = interleavedGradientNoise(fragmentPosition.xy) * PI2; var dp = (distanceToLight - pointShadow.cameraNear) / (pointShadow.cameraFar - pointShadow.cameraNear); dp = saturate(dp - pointShadow.bias); // Build a tangent-space coordinate system for applying offsets let absDir: vec3f = abs(bd3D); var tangent: vec3f = select(vec3(0.0, 1.0, 0.0), vec3(1.0, 0.0, 0.0), abs(bd3D.y) > 0.999); tangent = normalize(cross(bd3D, tangent)); let bitangent: vec3f = cross(bd3D, tangent); let pcfSamples: i32 = pointShadow.pcfSamples; for(var i: i32 = 0; i < pcfSamples; i++) { let offset: vec2f = vogelDiskSample(i, pcfSamples, phi); let offsetDir: vec3f = tangent * offset.x + bitangent * offset.y; let sampleDir: vec3f = normalize(bd3D + offsetDir * radius); visibility += textureSampleCompareLevel( depthCubeTexture, depthComparisonSampler, sampleDir, dp ); } visibility /= f32(pcfSamples); return mix(1.0, visibility, saturate(pointShadow.intensity)); }`; //#endregion export { getPCFPointShadowContribution };