Skip to content

⬅️ Back to Table of Contents

📄 WebGLLights.js

📊 Analysis Summary

Metric Count
🔧 Functions 10
📦 Imports 5
📊 Variables & Constants 45

📚 Table of Contents

🛠️ File Location:

📂 src/renderers/webgl/WebGLLights.js

📦 Imports

Name Source
Color ../../math/Color.js
Matrix4 ../../math/Matrix4.js
Vector2 ../../math/Vector2.js
Vector3 ../../math/Vector3.js
UniformsLib ../shaders/UniformsLib.js

Variables & Constants

Name Type Kind Value Exported
lights {} let/var {}
uniforms any let/var *not shown*
lights {} let/var {}
uniforms any let/var *not shown*
nextVersion number let/var 0
cache any let/var new UniformsCache()
state { version: number; hash: { directiona... let/var { version: 0, hash: { directionalLength: - 1, pointLength: - 1, spotLength: -...
vector3 Vector3 let/var new Vector3()
matrix4 Matrix4 let/var new Matrix4()
matrix42 Matrix4 let/var new Matrix4()
r number let/var 0
g number let/var 0
b number let/var 0
directionalLength number let/var 0
pointLength number let/var 0
spotLength number let/var 0
rectAreaLength number let/var 0
hemiLength number let/var 0
numDirectionalShadows number let/var 0
numPointShadows number let/var 0
numSpotShadows number let/var 0
numSpotMaps number let/var 0
numSpotShadowsWithMaps number let/var 0
numLightProbes number let/var 0
light any let/var lights[ i ]
color any let/var light.color
intensity any let/var light.intensity
distance any let/var light.distance
shadowMap any let/var ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null
shadow any let/var light.shadow
shadow any let/var light.shadow
shadow any let/var light.shadow
hash { directionalLength: number; pointLen... let/var state.hash
directionalLength number let/var 0
pointLength number let/var 0
spotLength number let/var 0
rectAreaLength number let/var 0
hemiLength number let/var 0
viewMatrix any let/var camera.matrixWorldInverse
light any let/var lights[ i ]
uniforms any let/var state.directional[ directionalLength ]
uniforms any let/var state.spot[ spotLength ]
uniforms any let/var state.rectArea[ rectAreaLength ]
uniforms any let/var state.point[ pointLength ]
uniforms any let/var state.hemi[ hemiLength ]

Functions

UniformsCache(): { get: (light: any) => any; }

Returns: { get: (light: any) => any; }

Code
function UniformsCache() {

    const lights = {};

    return {

        get: function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        direction: new Vector3(),
                        color: new Color()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        position: new Vector3(),
                        direction: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        coneCos: 0,
                        penumbraCos: 0,
                        decay: 0
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        position: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        decay: 0
                    };
                    break;

                case 'HemisphereLight':
                    uniforms = {
                        direction: new Vector3(),
                        skyColor: new Color(),
                        groundColor: new Color()
                    };
                    break;

                case 'RectAreaLight':
                    uniforms = {
                        color: new Color(),
                        position: new Vector3(),
                        halfWidth: new Vector3(),
                        halfHeight: new Vector3()
                    };
                    break;

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

    };

}

get(light: any): any

Parameters:

  • light any

Returns: any

Code
function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        direction: new Vector3(),
                        color: new Color()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        position: new Vector3(),
                        direction: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        coneCos: 0,
                        penumbraCos: 0,
                        decay: 0
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        position: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        decay: 0
                    };
                    break;

                case 'HemisphereLight':
                    uniforms = {
                        direction: new Vector3(),
                        skyColor: new Color(),
                        groundColor: new Color()
                    };
                    break;

                case 'RectAreaLight':
                    uniforms = {
                        color: new Color(),
                        position: new Vector3(),
                        halfWidth: new Vector3(),
                        halfHeight: new Vector3()
                    };
                    break;

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

get(light: any): any

Parameters:

  • light any

Returns: any

Code
function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        direction: new Vector3(),
                        color: new Color()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        position: new Vector3(),
                        direction: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        coneCos: 0,
                        penumbraCos: 0,
                        decay: 0
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        position: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        decay: 0
                    };
                    break;

                case 'HemisphereLight':
                    uniforms = {
                        direction: new Vector3(),
                        skyColor: new Color(),
                        groundColor: new Color()
                    };
                    break;

                case 'RectAreaLight':
                    uniforms = {
                        color: new Color(),
                        position: new Vector3(),
                        halfWidth: new Vector3(),
                        halfHeight: new Vector3()
                    };
                    break;

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

ShadowUniformsCache(): { get: (light: any) => any; }

Returns: { get: (light: any) => any; }

Code
function ShadowUniformsCache() {

    const lights = {};

    return {

        get: function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2(),
                        shadowCameraNear: 1,
                        shadowCameraFar: 1000
                    };
                    break;

                // TODO (abelnation): set RectAreaLight shadow uniforms

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

    };

}

get(light: any): any

Parameters:

  • light any

Returns: any

Code
function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2(),
                        shadowCameraNear: 1,
                        shadowCameraFar: 1000
                    };
                    break;

                // TODO (abelnation): set RectAreaLight shadow uniforms

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

get(light: any): any

Parameters:

  • light any

Returns: any

Code
function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2(),
                        shadowCameraNear: 1,
                        shadowCameraFar: 1000
                    };
                    break;

                // TODO (abelnation): set RectAreaLight shadow uniforms

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

shadowCastingAndTexturingLightsFirst(lightA: any, lightB: any): number

Parameters:

  • lightA any
  • lightB any

Returns: number

Code
function shadowCastingAndTexturingLightsFirst( lightA, lightB ) {

    return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 );

}

WebGLLights(extensions: any): { setup: (lights: any) => void; setupView: (lights: any, camera: any) => void; state: { version: number; hash: { directionalLength: number; pointLength: number; spotLength: number; rectAreaLength: number; ... 5 more ...; numLightProbes: number; }; ... 20 more ...; numLightProbes: number; }; }

Parameters:

  • extensions any

Returns: { setup: (lights: any) => void; setupView: (lights: any, camera: any) => void; state: { version: number; hash: { directionalLength: number; pointLength: number; spotLength: number; rectAreaLength: number; ... 5 more ...; numLightProbes: number; }; ... 20 more ...; numLightProbes: number; }; }

Calls:

  • ShadowUniformsCache
  • state.probe.push
  • state.probe[ i ].set
  • lights.sort
  • state.probe[ j ].addScaledVector
  • cache.get
  • uniforms.color.copy( light.color ).multiplyScalar
  • shadowCache.get
  • uniforms.position.setFromMatrixPosition
  • uniforms.color.copy( color ).multiplyScalar
  • Math.cos
  • shadow.updateMatrices
  • uniforms.halfWidth.set
  • uniforms.halfHeight.set
  • uniforms.skyColor.copy( light.color ).multiplyScalar
  • uniforms.groundColor.copy( light.groundColor ).multiplyScalar
  • extensions.has
  • uniforms.direction.setFromMatrixPosition
  • vector3.setFromMatrixPosition
  • uniforms.direction.sub
  • uniforms.direction.transformDirection
  • uniforms.position.applyMatrix4
  • matrix42.identity
  • matrix4.copy
  • matrix4.premultiply
  • matrix42.extractRotation
  • uniforms.halfWidth.applyMatrix4
  • uniforms.halfHeight.applyMatrix4

Internal Comments:

// ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] (x4)
// make sure the lightMatrix is up to date (x4)
// TODO : do it if required only (x4)
// extract local rotation of light to derive width/height half vectors (x4)

Code
function WebGLLights( extensions ) {

    const cache = new UniformsCache();

    const shadowCache = ShadowUniformsCache();

    const state = {

        version: 0,

        hash: {
            directionalLength: - 1,
            pointLength: - 1,
            spotLength: - 1,
            rectAreaLength: - 1,
            hemiLength: - 1,

            numDirectionalShadows: - 1,
            numPointShadows: - 1,
            numSpotShadows: - 1,
            numSpotMaps: - 1,

            numLightProbes: - 1
        },

        ambient: [ 0, 0, 0 ],
        probe: [],
        directional: [],
        directionalShadow: [],
        directionalShadowMap: [],
        directionalShadowMatrix: [],
        spot: [],
        spotLightMap: [],
        spotShadow: [],
        spotShadowMap: [],
        spotLightMatrix: [],
        rectArea: [],
        rectAreaLTC1: null,
        rectAreaLTC2: null,
        point: [],
        pointShadow: [],
        pointShadowMap: [],
        pointShadowMatrix: [],
        hemi: [],
        numSpotLightShadowsWithMaps: 0,
        numLightProbes: 0

    };

    for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );

    const vector3 = new Vector3();
    const matrix4 = new Matrix4();
    const matrix42 = new Matrix4();

    function setup( lights ) {

        let r = 0, g = 0, b = 0;

        for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );

        let directionalLength = 0;
        let pointLength = 0;
        let spotLength = 0;
        let rectAreaLength = 0;
        let hemiLength = 0;

        let numDirectionalShadows = 0;
        let numPointShadows = 0;
        let numSpotShadows = 0;
        let numSpotMaps = 0;
        let numSpotShadowsWithMaps = 0;

        let numLightProbes = 0;

        // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ]
        lights.sort( shadowCastingAndTexturingLightsFirst );

        for ( let i = 0, l = lights.length; i < l; i ++ ) {

            const light = lights[ i ];

            const color = light.color;
            const intensity = light.intensity;
            const distance = light.distance;

            const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;

            if ( light.isAmbientLight ) {

                r += color.r * intensity;
                g += color.g * intensity;
                b += color.b * intensity;

            } else if ( light.isLightProbe ) {

                for ( let j = 0; j < 9; j ++ ) {

                    state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );

                }

                numLightProbes ++;

            } else if ( light.isDirectionalLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( light.color ).multiplyScalar( light.intensity );

                if ( light.castShadow ) {

                    const shadow = light.shadow;

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;

                    state.directionalShadow[ directionalLength ] = shadowUniforms;
                    state.directionalShadowMap[ directionalLength ] = shadowMap;
                    state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;

                    numDirectionalShadows ++;

                }

                state.directional[ directionalLength ] = uniforms;

                directionalLength ++;

            } else if ( light.isSpotLight ) {

                const uniforms = cache.get( light );

                uniforms.position.setFromMatrixPosition( light.matrixWorld );

                uniforms.color.copy( color ).multiplyScalar( intensity );
                uniforms.distance = distance;

                uniforms.coneCos = Math.cos( light.angle );
                uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
                uniforms.decay = light.decay;

                state.spot[ spotLength ] = uniforms;

                const shadow = light.shadow;

                if ( light.map ) {

                    state.spotLightMap[ numSpotMaps ] = light.map;
                    numSpotMaps ++;

                    // make sure the lightMatrix is up to date
                    // TODO : do it if required only
                    shadow.updateMatrices( light );

                    if ( light.castShadow ) numSpotShadowsWithMaps ++;

                }

                state.spotLightMatrix[ spotLength ] = shadow.matrix;

                if ( light.castShadow ) {

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;

                    state.spotShadow[ spotLength ] = shadowUniforms;
                    state.spotShadowMap[ spotLength ] = shadowMap;

                    numSpotShadows ++;

                }

                spotLength ++;

            } else if ( light.isRectAreaLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( color ).multiplyScalar( intensity );

                uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
                uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );

                state.rectArea[ rectAreaLength ] = uniforms;

                rectAreaLength ++;

            } else if ( light.isPointLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
                uniforms.distance = light.distance;
                uniforms.decay = light.decay;

                if ( light.castShadow ) {

                    const shadow = light.shadow;

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;
                    shadowUniforms.shadowCameraNear = shadow.camera.near;
                    shadowUniforms.shadowCameraFar = shadow.camera.far;

                    state.pointShadow[ pointLength ] = shadowUniforms;
                    state.pointShadowMap[ pointLength ] = shadowMap;
                    state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;

                    numPointShadows ++;

                }

                state.point[ pointLength ] = uniforms;

                pointLength ++;

            } else if ( light.isHemisphereLight ) {

                const uniforms = cache.get( light );

                uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
                uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );

                state.hemi[ hemiLength ] = uniforms;

                hemiLength ++;

            }

        }

        if ( rectAreaLength > 0 ) {

            if ( extensions.has( 'OES_texture_float_linear' ) === true ) {

                state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
                state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;

            } else {

                state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
                state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;

            }

        }

        state.ambient[ 0 ] = r;
        state.ambient[ 1 ] = g;
        state.ambient[ 2 ] = b;

        const hash = state.hash;

        if ( hash.directionalLength !== directionalLength ||
            hash.pointLength !== pointLength ||
            hash.spotLength !== spotLength ||
            hash.rectAreaLength !== rectAreaLength ||
            hash.hemiLength !== hemiLength ||
            hash.numDirectionalShadows !== numDirectionalShadows ||
            hash.numPointShadows !== numPointShadows ||
            hash.numSpotShadows !== numSpotShadows ||
            hash.numSpotMaps !== numSpotMaps ||
            hash.numLightProbes !== numLightProbes ) {

            state.directional.length = directionalLength;
            state.spot.length = spotLength;
            state.rectArea.length = rectAreaLength;
            state.point.length = pointLength;
            state.hemi.length = hemiLength;

            state.directionalShadow.length = numDirectionalShadows;
            state.directionalShadowMap.length = numDirectionalShadows;
            state.pointShadow.length = numPointShadows;
            state.pointShadowMap.length = numPointShadows;
            state.spotShadow.length = numSpotShadows;
            state.spotShadowMap.length = numSpotShadows;
            state.directionalShadowMatrix.length = numDirectionalShadows;
            state.pointShadowMatrix.length = numPointShadows;
            state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps;
            state.spotLightMap.length = numSpotMaps;
            state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps;
            state.numLightProbes = numLightProbes;

            hash.directionalLength = directionalLength;
            hash.pointLength = pointLength;
            hash.spotLength = spotLength;
            hash.rectAreaLength = rectAreaLength;
            hash.hemiLength = hemiLength;

            hash.numDirectionalShadows = numDirectionalShadows;
            hash.numPointShadows = numPointShadows;
            hash.numSpotShadows = numSpotShadows;
            hash.numSpotMaps = numSpotMaps;

            hash.numLightProbes = numLightProbes;

            state.version = nextVersion ++;

        }

    }

    function setupView( lights, camera ) {

        let directionalLength = 0;
        let pointLength = 0;
        let spotLength = 0;
        let rectAreaLength = 0;
        let hemiLength = 0;

        const viewMatrix = camera.matrixWorldInverse;

        for ( let i = 0, l = lights.length; i < l; i ++ ) {

            const light = lights[ i ];

            if ( light.isDirectionalLight ) {

                const uniforms = state.directional[ directionalLength ];

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                vector3.setFromMatrixPosition( light.target.matrixWorld );
                uniforms.direction.sub( vector3 );
                uniforms.direction.transformDirection( viewMatrix );

                directionalLength ++;

            } else if ( light.isSpotLight ) {

                const uniforms = state.spot[ spotLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                vector3.setFromMatrixPosition( light.target.matrixWorld );
                uniforms.direction.sub( vector3 );
                uniforms.direction.transformDirection( viewMatrix );

                spotLength ++;

            } else if ( light.isRectAreaLight ) {

                const uniforms = state.rectArea[ rectAreaLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                // extract local rotation of light to derive width/height half vectors
                matrix42.identity();
                matrix4.copy( light.matrixWorld );
                matrix4.premultiply( viewMatrix );
                matrix42.extractRotation( matrix4 );

                uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
                uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );

                uniforms.halfWidth.applyMatrix4( matrix42 );
                uniforms.halfHeight.applyMatrix4( matrix42 );

                rectAreaLength ++;

            } else if ( light.isPointLight ) {

                const uniforms = state.point[ pointLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                pointLength ++;

            } else if ( light.isHemisphereLight ) {

                const uniforms = state.hemi[ hemiLength ];

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                uniforms.direction.transformDirection( viewMatrix );

                hemiLength ++;

            }

        }

    }

    return {
        setup: setup,
        setupView: setupView,
        state: state
    };

}

setup(lights: any): void

Parameters:

  • lights any

Returns: void

Calls:

  • state.probe[ i ].set
  • lights.sort
  • state.probe[ j ].addScaledVector
  • cache.get
  • uniforms.color.copy( light.color ).multiplyScalar
  • shadowCache.get
  • uniforms.position.setFromMatrixPosition
  • uniforms.color.copy( color ).multiplyScalar
  • Math.cos
  • shadow.updateMatrices
  • uniforms.halfWidth.set
  • uniforms.halfHeight.set
  • uniforms.skyColor.copy( light.color ).multiplyScalar
  • uniforms.groundColor.copy( light.groundColor ).multiplyScalar
  • extensions.has

Internal Comments:

// ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] (x4)
// make sure the lightMatrix is up to date (x4)
// TODO : do it if required only (x4)

Code
function setup( lights ) {

        let r = 0, g = 0, b = 0;

        for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );

        let directionalLength = 0;
        let pointLength = 0;
        let spotLength = 0;
        let rectAreaLength = 0;
        let hemiLength = 0;

        let numDirectionalShadows = 0;
        let numPointShadows = 0;
        let numSpotShadows = 0;
        let numSpotMaps = 0;
        let numSpotShadowsWithMaps = 0;

        let numLightProbes = 0;

        // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ]
        lights.sort( shadowCastingAndTexturingLightsFirst );

        for ( let i = 0, l = lights.length; i < l; i ++ ) {

            const light = lights[ i ];

            const color = light.color;
            const intensity = light.intensity;
            const distance = light.distance;

            const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;

            if ( light.isAmbientLight ) {

                r += color.r * intensity;
                g += color.g * intensity;
                b += color.b * intensity;

            } else if ( light.isLightProbe ) {

                for ( let j = 0; j < 9; j ++ ) {

                    state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );

                }

                numLightProbes ++;

            } else if ( light.isDirectionalLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( light.color ).multiplyScalar( light.intensity );

                if ( light.castShadow ) {

                    const shadow = light.shadow;

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;

                    state.directionalShadow[ directionalLength ] = shadowUniforms;
                    state.directionalShadowMap[ directionalLength ] = shadowMap;
                    state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;

                    numDirectionalShadows ++;

                }

                state.directional[ directionalLength ] = uniforms;

                directionalLength ++;

            } else if ( light.isSpotLight ) {

                const uniforms = cache.get( light );

                uniforms.position.setFromMatrixPosition( light.matrixWorld );

                uniforms.color.copy( color ).multiplyScalar( intensity );
                uniforms.distance = distance;

                uniforms.coneCos = Math.cos( light.angle );
                uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
                uniforms.decay = light.decay;

                state.spot[ spotLength ] = uniforms;

                const shadow = light.shadow;

                if ( light.map ) {

                    state.spotLightMap[ numSpotMaps ] = light.map;
                    numSpotMaps ++;

                    // make sure the lightMatrix is up to date
                    // TODO : do it if required only
                    shadow.updateMatrices( light );

                    if ( light.castShadow ) numSpotShadowsWithMaps ++;

                }

                state.spotLightMatrix[ spotLength ] = shadow.matrix;

                if ( light.castShadow ) {

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;

                    state.spotShadow[ spotLength ] = shadowUniforms;
                    state.spotShadowMap[ spotLength ] = shadowMap;

                    numSpotShadows ++;

                }

                spotLength ++;

            } else if ( light.isRectAreaLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( color ).multiplyScalar( intensity );

                uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
                uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );

                state.rectArea[ rectAreaLength ] = uniforms;

                rectAreaLength ++;

            } else if ( light.isPointLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
                uniforms.distance = light.distance;
                uniforms.decay = light.decay;

                if ( light.castShadow ) {

                    const shadow = light.shadow;

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;
                    shadowUniforms.shadowCameraNear = shadow.camera.near;
                    shadowUniforms.shadowCameraFar = shadow.camera.far;

                    state.pointShadow[ pointLength ] = shadowUniforms;
                    state.pointShadowMap[ pointLength ] = shadowMap;
                    state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;

                    numPointShadows ++;

                }

                state.point[ pointLength ] = uniforms;

                pointLength ++;

            } else if ( light.isHemisphereLight ) {

                const uniforms = cache.get( light );

                uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
                uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );

                state.hemi[ hemiLength ] = uniforms;

                hemiLength ++;

            }

        }

        if ( rectAreaLength > 0 ) {

            if ( extensions.has( 'OES_texture_float_linear' ) === true ) {

                state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
                state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;

            } else {

                state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
                state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;

            }

        }

        state.ambient[ 0 ] = r;
        state.ambient[ 1 ] = g;
        state.ambient[ 2 ] = b;

        const hash = state.hash;

        if ( hash.directionalLength !== directionalLength ||
            hash.pointLength !== pointLength ||
            hash.spotLength !== spotLength ||
            hash.rectAreaLength !== rectAreaLength ||
            hash.hemiLength !== hemiLength ||
            hash.numDirectionalShadows !== numDirectionalShadows ||
            hash.numPointShadows !== numPointShadows ||
            hash.numSpotShadows !== numSpotShadows ||
            hash.numSpotMaps !== numSpotMaps ||
            hash.numLightProbes !== numLightProbes ) {

            state.directional.length = directionalLength;
            state.spot.length = spotLength;
            state.rectArea.length = rectAreaLength;
            state.point.length = pointLength;
            state.hemi.length = hemiLength;

            state.directionalShadow.length = numDirectionalShadows;
            state.directionalShadowMap.length = numDirectionalShadows;
            state.pointShadow.length = numPointShadows;
            state.pointShadowMap.length = numPointShadows;
            state.spotShadow.length = numSpotShadows;
            state.spotShadowMap.length = numSpotShadows;
            state.directionalShadowMatrix.length = numDirectionalShadows;
            state.pointShadowMatrix.length = numPointShadows;
            state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps;
            state.spotLightMap.length = numSpotMaps;
            state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps;
            state.numLightProbes = numLightProbes;

            hash.directionalLength = directionalLength;
            hash.pointLength = pointLength;
            hash.spotLength = spotLength;
            hash.rectAreaLength = rectAreaLength;
            hash.hemiLength = hemiLength;

            hash.numDirectionalShadows = numDirectionalShadows;
            hash.numPointShadows = numPointShadows;
            hash.numSpotShadows = numSpotShadows;
            hash.numSpotMaps = numSpotMaps;

            hash.numLightProbes = numLightProbes;

            state.version = nextVersion ++;

        }

    }

setupView(lights: any, camera: any): void

Parameters:

  • lights any
  • camera any

Returns: void

Calls:

  • uniforms.direction.setFromMatrixPosition
  • vector3.setFromMatrixPosition
  • uniforms.direction.sub
  • uniforms.direction.transformDirection
  • uniforms.position.setFromMatrixPosition
  • uniforms.position.applyMatrix4
  • matrix42.identity
  • matrix4.copy
  • matrix4.premultiply
  • matrix42.extractRotation
  • uniforms.halfWidth.set
  • uniforms.halfHeight.set
  • uniforms.halfWidth.applyMatrix4
  • uniforms.halfHeight.applyMatrix4

Internal Comments:

// extract local rotation of light to derive width/height half vectors (x4)

Code
function setupView( lights, camera ) {

        let directionalLength = 0;
        let pointLength = 0;
        let spotLength = 0;
        let rectAreaLength = 0;
        let hemiLength = 0;

        const viewMatrix = camera.matrixWorldInverse;

        for ( let i = 0, l = lights.length; i < l; i ++ ) {

            const light = lights[ i ];

            if ( light.isDirectionalLight ) {

                const uniforms = state.directional[ directionalLength ];

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                vector3.setFromMatrixPosition( light.target.matrixWorld );
                uniforms.direction.sub( vector3 );
                uniforms.direction.transformDirection( viewMatrix );

                directionalLength ++;

            } else if ( light.isSpotLight ) {

                const uniforms = state.spot[ spotLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                vector3.setFromMatrixPosition( light.target.matrixWorld );
                uniforms.direction.sub( vector3 );
                uniforms.direction.transformDirection( viewMatrix );

                spotLength ++;

            } else if ( light.isRectAreaLight ) {

                const uniforms = state.rectArea[ rectAreaLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                // extract local rotation of light to derive width/height half vectors
                matrix42.identity();
                matrix4.copy( light.matrixWorld );
                matrix4.premultiply( viewMatrix );
                matrix42.extractRotation( matrix4 );

                uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
                uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );

                uniforms.halfWidth.applyMatrix4( matrix42 );
                uniforms.halfHeight.applyMatrix4( matrix42 );

                rectAreaLength ++;

            } else if ( light.isPointLight ) {

                const uniforms = state.point[ pointLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                pointLength ++;

            } else if ( light.isHemisphereLight ) {

                const uniforms = state.hemi[ hemiLength ];

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                uniforms.direction.transformDirection( viewMatrix );

                hemiLength ++;

            }

        }

    }