UNPKG

@babylonjs/viewer

Version:

The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.

111 lines (108 loc) 4.59 kB
import { M as MAX_LIGHTS } from './index-By0tcgYN.esm.js'; function MULTI_LIGHT_STRUCTS() { return ` struct LightEntry { vLightData: vec4<f32>, vLightDiffuse: vec4<f32>, vLightSpecular: vec4<f32>, vLightDirection: vec4<f32>, }; struct lightsUniforms { count: u32, _p0: u32, _p1: u32, _p2: u32, lights: array<LightEntry, ${MAX_LIGHTS}>, }; `; } const COMPUTE_PBR_LIGHT = ` struct PbrLightResult { L: vec3<f32>, NdotL: f32, atten: f32, color: vec3<f32>, specColor: vec3<f32>, isHemi: bool }; fn computePbrLight(entry: LightEntry, N: vec3<f32>, worldPos: vec3<f32>, lightFalloffMode: f32) -> PbrLightResult { var r: PbrLightResult; let t = u32(entry.vLightData.w); r.isHemi = t == 3u; r.specColor = entry.vLightDiffuse.rgb; if (t == 3u) { r.L = normalize(entry.vLightData.xyz); r.NdotL = dot(N, r.L) * 0.5 + 0.5; r.atten = 1.0; r.color = mix(entry.vLightDirection.xyz, entry.vLightDiffuse.rgb, r.NdotL); return r; } if (t == 1u) { r.L = normalize(-entry.vLightData.xyz); r.atten = 1.0; } else { let toLight = entry.vLightData.xyz - worldPos; let d2 = dot(toLight, toLight); let dist = sqrt(d2); r.L = toLight / max(dist, 0.0001); let physicalFalloff = lightFalloffMode >= 0.5; let rangeAtt = select(max(0.0, 1.0 - dist / entry.vLightDiffuse.a), 1.0 / max(d2, 0.0000001), physicalFalloff); if (t == 2u) { let cosHalfAngle = entry.vLightDirection.w; let c = dot(-entry.vLightDirection.xyz, r.L); let standardDirFalloff = select(0.0, max(0.0, pow(max(c, 0.0), entry.vLightSpecular.a)), c >= cosHalfAngle); let kappa = 6.64385618977 / max(1.0 - cosHalfAngle, 0.0001); let physicalDirFalloff = exp2(kappa * (c - 1.0)); r.atten = rangeAtt * select(standardDirFalloff, physicalDirFalloff, physicalFalloff); } else { r.atten = rangeAtt; } } r.NdotL = max(dot(N, r.L), 0.0); r.color = entry.vLightDiffuse.rgb; return r; } `; function getMultiLightLoop() { return `var directDiffuse = vec3<f32>(0.0); var directSpecular = vec3<f32>(0.0); // BJS direct-light specular: roughness is clamped by the geometric AA factor // BEFORE being squared (matches BJS pbrDirectLightingFunctions.fx line 103). // The IBL-path alphaG already has AA_factor_y additively baked in; direct // specular uses its own squaring after max(roughness, AA_factor_x). let directRoughness = max(roughness, AA_factor_x); let directAlphaG = directRoughness * directRoughness + 0.0005; var shadowFactors = array<f32, ${MAX_LIGHTS}>(${new Array(MAX_LIGHTS).fill("1.0").join(", ")}); let lightCount = min(mesh.lc, ${MAX_LIGHTS}u); /*AS*/ // First-light aliases — kept at directLightBlock scope so the AD slot below // (clearcoat / sheen / subsurface) sees the same single-light variable names // it was originally written against. Multi-light direct contributions // for those ancillary BRDFs are not yet supported (single-light parity only). let lightIndex0 = mli(0u); let entry0 = lights.lights[lightIndex0]; let pl0 = computePbrLight(entry0, N, input.worldPos, material.lightFalloffMode); let L = pl0.L; let NdotL = pl0.NdotL; let lightColor = pl0.specColor; let lightAtten = pl0.atten * shadowFactors[lightIndex0]; let H = normalize(V + L); let NdotH = clamp(dot(N, H), 0.0000001, 1.0); let VdotH = saturate(dot(V, H)); for (var li = 0u; li < lightCount; li++) { var pl: PbrLightResult; let lightIndex = mli(li); if (li == 0u) { pl = pl0; } else { pl = computePbrLight(lights.lights[lightIndex], N, input.worldPos, material.lightFalloffMode); } let sf = shadowFactors[lightIndex]; if (pl.isHemi) { directDiffuse += pl.color * surfaceAlbedo * material.directIntensity * sf; } else { directDiffuse += surfaceAlbedo * (1.0 / PI) * pl.NdotL * pl.color * pl.atten * material.directIntensity * sf; } // Specular uses pl.NdotL (hemispheric 0.5+0.5*dot for hemi, max(dot,0) for others) // and pl.specColor (un-mixed light diffuse — matches single-light fast path // and Std's LIGHTING_FN which uses vLightSpecular for the specular bounce). if (pl.NdotL > 0.0 && pl.atten > 0.0) { let specH = normalize(V + pl.L); let specNdotH = clamp(dot(N, specH), 0.0000001, 1.0); let specVdotH = saturate(dot(V, specH)); let D = distributionGGX(specNdotH, directAlphaG); let G = geometrySmithGGX(pl.NdotL, NdotV, directAlphaG); let coloredFresnel = fresnelSchlick(specVdotH, colorF0, colorF90); directSpecular += coloredFresnel * D * G * pl.NdotL * pl.specColor * pl.atten * material.directIntensity * sf; } } /*AD*/`; } export { COMPUTE_PBR_LIGHT, MULTI_LIGHT_STRUCTS, getMultiLightLoop }; //# sourceMappingURL=multilight-wgsl-f1eQI9X9.esm.js.map