playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
64 lines (63 loc) • 3.54 kB
JavaScript
var shadowEVSM_default = `
fn linstep(a: f32, b: f32, v: f32) -> f32 {
return clamp((v - a) / (b - a), 0.0, 1.0);
}
fn reduceLightBleeding(pMax: f32, amount: f32) -> f32 {
return linstep(amount, 1.0, pMax);
}
fn chebyshevUpperBound(moments: vec2f, mean: f32, minVariance: f32, lightBleedingReduction: f32) -> f32 {
var variance: f32 = moments.y - (moments.x * moments.x);
variance = max(variance, minVariance);
let d: f32 = mean - moments.x;
var pMax: f32 = variance / (variance + (d * d));
pMax = reduceLightBleeding(pMax, lightBleedingReduction);
return select(pMax, 1.0, mean <= moments.x);
}
fn calculateEVSM(moments_in: vec3f, Z_in: f32, vsmBias: f32, exponent: f32) -> f32 {
let Z: f32 = 2.0 * Z_in - 1.0;
let warpedDepth: f32 = exp(exponent * Z);
let moments: vec2f = moments_in.xy + vec2f(warpedDepth, warpedDepth*warpedDepth) * (1.0 - moments_in.z);
let VSMBias: f32 = vsmBias;
let depthScale: f32 = VSMBias * exponent * warpedDepth;
let minVariance1: f32 = depthScale * depthScale;
return chebyshevUpperBound(moments, warpedDepth, minVariance1, 0.1);
}
fn VSM16(tex: texture_2d<f32>, texSampler: sampler, texCoords: vec2f, resolution: f32, Z: f32, vsmBias: f32, exponent: f32) -> f32 {
let moments: vec3f = textureSampleLevel(tex, texSampler, texCoords, 0.0).xyz;
return calculateEVSM(moments, Z, vsmBias, exponent);
}
fn getShadowVSM16(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, shadowCoord: vec3f, shadowParams: vec4f, exponent: f32) -> f32 {
return VSM16(shadowMap, shadowMapSampler, shadowCoord.xy, shadowParams.x, shadowCoord.z, shadowParams.y, exponent);
}
fn getShadowSpotVSM16(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, shadowCoord: vec3f, shadowParams: vec4f, exponent: f32, lightDir: vec3f) -> f32 {
let Z: f32 = length(lightDir) * shadowParams.w + shadowParams.z;
return VSM16(shadowMap, shadowMapSampler, shadowCoord.xy, shadowParams.x, Z, shadowParams.y, exponent);
}
fn VSM32(tex: texture_2d<f32>, texSampler: sampler, texCoords_in: vec2f, resolution: f32, Z: f32, vsmBias: f32, exponent: f32) -> f32 {
#ifdef CAPS_TEXTURE_FLOAT_FILTERABLE
var moments: vec3f = textureSampleLevel(tex, texSampler, texCoords_in, 0.0).xyz;
#else
var pixelSize : f32 = 1.0 / resolution;
let texCoords: vec2f = texCoords_in - vec2f(pixelSize);
let s00: vec3f = textureSampleLevel(tex, texSampler, texCoords, 0.0).xyz;
let s10: vec3f = textureSampleLevel(tex, texSampler, texCoords + vec2f(pixelSize, 0.0), 0.0).xyz;
let s01: vec3f = textureSampleLevel(tex, texSampler, texCoords + vec2f(0.0, pixelSize), 0.0).xyz;
let s11: vec3f = textureSampleLevel(tex, texSampler, texCoords + vec2f(pixelSize), 0.0).xyz;
let fr: vec2f = fract(texCoords * resolution);
let h0: vec3f = mix(s00, s10, fr.x);
let h1: vec3f = mix(s01, s11, fr.x);
var moments: vec3f = mix(h0, h1, fr.y);
#endif
return calculateEVSM(moments, Z, vsmBias, exponent);
}
fn getShadowVSM32(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, shadowCoord: vec3f, shadowParams: vec4f, exponent: f32) -> f32 {
return VSM32(shadowMap, shadowMapSampler, shadowCoord.xy, shadowParams.x, shadowCoord.z, shadowParams.y, exponent);
}
fn getShadowSpotVSM32(shadowMap: texture_2d<f32>, shadowMapSampler: sampler, shadowCoord: vec3f, shadowParams: vec4f, exponent: f32, lightDir: vec3f) -> f32 {
let Z: f32 = length(lightDir) * shadowParams.w + shadowParams.z;
return VSM32(shadowMap, shadowMapSampler, shadowCoord.xy, shadowParams.x, Z, shadowParams.y, exponent);
}
`;
export {
shadowEVSM_default as default
};