@luma.gl/shadertools
Version:
Shader module system for luma.gl
155 lines • 5.74 kB
JavaScript
// luma.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { log } from '@luma.gl/core';
import { lightingUniformsGLSL } from "./lighting-uniforms-glsl.js";
import { lightingUniformsWGSL } from "./lighting-uniforms-wgsl.js";
/** Max number of supported lights (in addition to ambient light */
const MAX_LIGHTS = 3;
/** Whether to divide */
const COLOR_FACTOR = 255.0;
/** Shader type field for lights */
// eslint-disable-next-line no-shadow
export var LIGHT_TYPE;
(function (LIGHT_TYPE) {
LIGHT_TYPE[LIGHT_TYPE["POINT"] = 0] = "POINT";
LIGHT_TYPE[LIGHT_TYPE["DIRECTIONAL"] = 1] = "DIRECTIONAL";
})(LIGHT_TYPE || (LIGHT_TYPE = {}));
/** UBO ready lighting module */
export const lighting = {
props: {},
uniforms: {},
name: 'lighting',
defines: {
MAX_LIGHTS
},
uniformTypes: {
enabled: 'i32',
lightType: 'i32',
directionalLightCount: 'i32',
pointLightCount: 'i32',
ambientLightColor: 'vec3<f32>',
// TODO define as arrays once we have appropriate uniformTypes
lightColor0: 'vec3<f32>',
lightPosition0: 'vec3<f32>',
// TODO - could combine direction and attenuation
lightDirection0: 'vec3<f32>',
lightAttenuation0: 'vec3<f32>',
lightColor1: 'vec3<f32>',
lightPosition1: 'vec3<f32>',
lightDirection1: 'vec3<f32>',
lightAttenuation1: 'vec3<f32>',
lightColor2: 'vec3<f32>',
lightPosition2: 'vec3<f32>',
lightDirection2: 'vec3<f32>',
lightAttenuation2: 'vec3<f32>'
},
defaultUniforms: {
enabled: 1,
lightType: LIGHT_TYPE.POINT,
directionalLightCount: 0,
pointLightCount: 0,
ambientLightColor: [0.1, 0.1, 0.1],
lightColor0: [1, 1, 1],
lightPosition0: [1, 1, 2],
// TODO - could combine direction and attenuation
lightDirection0: [1, 1, 1],
lightAttenuation0: [1, 0, 0],
lightColor1: [1, 1, 1],
lightPosition1: [1, 1, 2],
lightDirection1: [1, 1, 1],
lightAttenuation1: [1, 0, 0],
lightColor2: [1, 1, 1],
lightPosition2: [1, 1, 2],
lightDirection2: [1, 1, 1],
lightAttenuation2: [1, 0, 0]
},
source: lightingUniformsWGSL,
vs: lightingUniformsGLSL,
fs: lightingUniformsGLSL,
getUniforms
};
function getUniforms(props, prevUniforms = {}) {
// Copy props so we can modify
props = props ? { ...props } : props;
// TODO legacy
if (!props) {
return { ...lighting.defaultUniforms };
}
// Support for array of lights. Type of light is detected by type field
if (props.lights) {
props = { ...props, ...extractLightTypes(props.lights), lights: undefined };
}
// Specify lights separately
const { ambientLight, pointLights, directionalLights } = props || {};
const hasLights = ambientLight ||
(pointLights && pointLights.length > 0) ||
(directionalLights && directionalLights.length > 0);
// TODO - this may not be the correct decision
if (!hasLights) {
return { ...lighting.defaultUniforms, enabled: 0 };
}
const uniforms = {
...lighting.defaultUniforms,
...prevUniforms,
...getLightSourceUniforms({ ambientLight, pointLights, directionalLights })
};
if (props.enabled !== undefined) {
uniforms.enabled = props.enabled ? 1 : 0;
}
return uniforms;
}
function getLightSourceUniforms({ ambientLight, pointLights = [], directionalLights = [] }) {
const lightSourceUniforms = {};
lightSourceUniforms.ambientLightColor = convertColor(ambientLight);
let currentLight = 0;
for (const pointLight of pointLights) {
lightSourceUniforms.lightType = LIGHT_TYPE.POINT;
const i = currentLight;
lightSourceUniforms[`lightColor${i}`] = convertColor(pointLight);
lightSourceUniforms[`lightPosition${i}`] = pointLight.position;
lightSourceUniforms[`lightAttenuation${i}`] = pointLight.attenuation || [1, 0, 0];
currentLight++;
}
for (const directionalLight of directionalLights) {
lightSourceUniforms.lightType = LIGHT_TYPE.DIRECTIONAL;
const i = currentLight;
lightSourceUniforms[`lightColor${i}`] = convertColor(directionalLight);
lightSourceUniforms[`lightDirection${i}`] = directionalLight.direction;
currentLight++;
}
if (currentLight > MAX_LIGHTS) {
log.warn('MAX_LIGHTS exceeded')();
}
lightSourceUniforms.directionalLightCount = directionalLights.length;
lightSourceUniforms.pointLightCount = pointLights.length;
return lightSourceUniforms;
}
function extractLightTypes(lights) {
const lightSources = { pointLights: [], directionalLights: [] };
for (const light of lights || []) {
switch (light.type) {
case 'ambient':
// Note: Only uses last ambient light
// TODO - add ambient light sources on CPU?
lightSources.ambientLight = light;
break;
case 'directional':
lightSources.directionalLights?.push(light);
break;
case 'point':
lightSources.pointLights?.push(light);
break;
default:
// eslint-disable-next-line
// console.warn(light.type);
}
}
return lightSources;
}
/** Take color 0-255 and intensity as input and output 0.0-1.0 range */
function convertColor(colorDef = {}) {
const { color = [0, 0, 0], intensity = 1.0 } = colorDef;
return color.map(component => (component * intensity) / COLOR_FACTOR);
}
//# sourceMappingURL=lighting.js.map