UNPKG

@itwin/core-frontend

Version:
128 lines (111 loc) 5.75 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module WebGL */ import { addFrustum } from "./Common"; const computeDirectionalLighting = ` void computeDirectionalLight (inout float diffuse, inout float specular, vec3 normal, vec3 toEye, vec3 lightDir, float lightIntensity, float specularExponent) { diffuse += lightIntensity * max(dot(normal, lightDir), 0.0); vec3 toReflectedLight = normalize(reflect(lightDir, normal)); float specularDot = max(dot(toReflectedLight, toEye), 0.0001); // NB: If specularDot and specularExponent are both zero, 0^0 done below can return NaN. Must make sure specularDot is larger than zero (hence 0.0001 or greater, as ensured above). specular += lightIntensity * pow(specularDot, specularExponent); } `; // mat_weights: x=diffuse y=specular const applyLighting = ` if (baseColor.a <= 0.0 || !u_surfaceFlags[kSurfaceBitIndex_ApplyLighting]) return baseColor; // Extract surface properties vec3 rgb = baseColor.rgb; vec3 toEye = kFrustumType_Perspective == u_frustum.z ? normalize(v_eyeSpace.xyz) : vec3(0.0, 0.0, -1.0); // Extract material properties float diffuseWeight = mat_weights.x; float specularWeight = mat_weights.y * u_lightSettings[13]; float specularExponent = mat_specular.a; vec3 specularColor = mat_specular.rgb; const float ambientWeight = 1.0; // Ignore MicroStation's ambient weights - usually bogus. // Compute directional lights const vec3 portraitDir = vec3(-0.7071, 0.0, 0.7071); float portraitIntensity = u_lightSettings[12]; float sunIntensity = u_lightSettings[0]; float directionalDiffuseIntensity = 0.0; float directionalSpecularIntensity = 0.0; computeDirectionalLight(directionalDiffuseIntensity, directionalSpecularIntensity, g_normal, toEye, u_sunDir, sunIntensity, specularExponent); computeDirectionalLight(directionalDiffuseIntensity, directionalSpecularIntensity, g_normal ,toEye, portraitDir, portraitIntensity, specularExponent); const float directionalFudge = 0.92; // leftover from old lighting implementation vec3 diffuseAccum = directionalDiffuseIntensity * diffuseWeight * rgb * directionalFudge; // directional light is white. vec3 specularAccum = directionalSpecularIntensity * specularWeight * specularColor; // Compute ambient light float ambientIntensity = u_lightSettings[4]; vec3 ambientColor = vec3(u_lightSettings[1], u_lightSettings[2], u_lightSettings[3]); if (ambientColor.r + ambientColor.g + ambientColor.b == 0.0) ambientColor = rgb; diffuseAccum += ambientIntensity * ambientWeight * ambientColor; // Compute hemisphere lights vec3 ground = vec3(u_lightSettings[5], u_lightSettings[6], u_lightSettings[7]); vec3 sky = vec3(u_lightSettings[8], u_lightSettings[9], u_lightSettings[10]); float hemiIntensity = u_lightSettings[11]; // diffuse float hemiDot = dot(g_normal, u_upVector); float hemiDiffuseWeight = 0.5 * hemiDot + 0.5; vec3 hemiColor = mix(ground, sky, hemiDiffuseWeight); diffuseAccum += hemiIntensity * hemiColor * rgb; // sky specular vec3 reflectSky = normalize(reflect(u_upVector, g_normal)); float skyDot = max(dot(reflectSky, toEye), 0.0001); float hemiSpecWeight = hemiIntensity * pow(skyDot, specularExponent); // ground specular vec3 reflectGround = normalize(reflect(-u_upVector, g_normal)); float groundDot = max(dot(reflectGround, toEye), 0.0001); hemiSpecWeight += hemiIntensity * pow(groundDot, specularExponent); specularAccum += hemiSpecWeight * specularColor * hemiColor; vec3 litColor = diffuseAccum + specularAccum; // Apply fresnel reflection. float fresnelIntensity = u_lightSettings[15]; if (0.0 != fresnelIntensity) { float fresnel = -dot(toEye, g_normal); if (fresnelIntensity < 0.0) { fresnelIntensity = abs(fresnelIntensity); fresnel = 1.0 - fresnel; } fresnel = clamp(1.0 - fresnel, 0.0, 1.0); litColor = litColor * (1.0 + fresnelIntensity * fresnel); } // Clamp while preserving hue. float maxIntensity = max(litColor.r, max(litColor.g, litColor.b)); float numCel = u_lightSettings[14]; if (numCel > 0.0) baseColor.rgb = baseColor.rgb * ceil(maxIntensity * numCel) / numCel; else baseColor.rgb = litColor / max(1.0, maxIntensity); return baseColor; `; /** NB: addMaterial() sets up the mat_* variables used by applyLighting. * @internal */ export function addLighting(builder) { addFrustum(builder); const frag = builder.frag; frag.addFunction(computeDirectionalLighting); frag.set(8 /* FragmentShaderComponent.ApplyLighting */, applyLighting); frag.addUniform("u_sunDir", 4 /* VariableType.Vec3 */, (prog) => { prog.addProgramUniform("u_sunDir", (uniform, params) => { params.target.uniforms.bindSunDirection(uniform); }); }, 3 /* VariablePrecision.High */); frag.addUniform("u_lightSettings[16]", 2 /* VariableType.Float */, (prog) => { prog.addProgramUniform("u_lightSettings[0]", (uniform, params) => { params.target.uniforms.lights.bind(uniform); }); }); frag.addUniform("u_upVector", 4 /* VariableType.Vec3 */, (prog) => { prog.addProgramUniform("u_upVector", (uniform, params) => { params.target.uniforms.frustum.bindUpVector(uniform); }); }); } //# sourceMappingURL=Lighting.js.map