Spaces:
Running
Running
/** | |
* @author mrdoob / http://mrdoob.com/ | |
*/ | |
import { Color } from '../../math/Color.js'; | |
import { Matrix4 } from '../../math/Matrix4.js'; | |
import { Vector2 } from '../../math/Vector2.js'; | |
import { Vector3 } from '../../math/Vector3.js'; | |
function UniformsCache() { | |
var lights = {}; | |
return { | |
get: function ( light ) { | |
if ( lights[ light.id ] !== undefined ) { | |
return lights[ light.id ]; | |
} | |
var uniforms; | |
switch ( light.type ) { | |
case 'DirectionalLight': | |
uniforms = { | |
direction: new Vector3(), | |
color: new Color(), | |
shadow: false, | |
shadowBias: 0, | |
shadowRadius: 1, | |
shadowMapSize: new Vector2() | |
}; | |
break; | |
case 'SpotLight': | |
uniforms = { | |
position: new Vector3(), | |
direction: new Vector3(), | |
color: new Color(), | |
distance: 0, | |
coneCos: 0, | |
penumbraCos: 0, | |
decay: 0, | |
shadow: false, | |
shadowBias: 0, | |
shadowRadius: 1, | |
shadowMapSize: new Vector2() | |
}; | |
break; | |
case 'PointLight': | |
uniforms = { | |
position: new Vector3(), | |
color: new Color(), | |
distance: 0, | |
decay: 0, | |
shadow: false, | |
shadowBias: 0, | |
shadowRadius: 1, | |
shadowMapSize: new Vector2(), | |
shadowCameraNear: 1, | |
shadowCameraFar: 1000 | |
}; | |
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() | |
// TODO (abelnation): set RectAreaLight shadow uniforms | |
}; | |
break; | |
} | |
lights[ light.id ] = uniforms; | |
return uniforms; | |
} | |
}; | |
} | |
var count = 0; | |
function WebGLLights() { | |
var cache = new UniformsCache(); | |
var state = { | |
id: count ++, | |
hash: { | |
stateID: - 1, | |
directionalLength: - 1, | |
pointLength: - 1, | |
spotLength: - 1, | |
rectAreaLength: - 1, | |
hemiLength: - 1, | |
shadowsLength: - 1 | |
}, | |
ambient: [ 0, 0, 0 ], | |
directional: [], | |
directionalShadowMap: [], | |
directionalShadowMatrix: [], | |
spot: [], | |
spotShadowMap: [], | |
spotShadowMatrix: [], | |
rectArea: [], | |
point: [], | |
pointShadowMap: [], | |
pointShadowMatrix: [], | |
hemi: [] | |
}; | |
var vector3 = new Vector3(); | |
var matrix4 = new Matrix4(); | |
var matrix42 = new Matrix4(); | |
function setup( lights, shadows, camera ) { | |
var r = 0, g = 0, b = 0; | |
var directionalLength = 0; | |
var pointLength = 0; | |
var spotLength = 0; | |
var rectAreaLength = 0; | |
var hemiLength = 0; | |
var viewMatrix = camera.matrixWorldInverse; | |
for ( var i = 0, l = lights.length; i < l; i ++ ) { | |
var light = lights[ i ]; | |
var color = light.color; | |
var intensity = light.intensity; | |
var distance = light.distance; | |
var 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.isDirectionalLight ) { | |
var uniforms = cache.get( light ); | |
uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); | |
uniforms.direction.setFromMatrixPosition( light.matrixWorld ); | |
vector3.setFromMatrixPosition( light.target.matrixWorld ); | |
uniforms.direction.sub( vector3 ); | |
uniforms.direction.transformDirection( viewMatrix ); | |
uniforms.shadow = light.castShadow; | |
if ( light.castShadow ) { | |
var shadow = light.shadow; | |
uniforms.shadowBias = shadow.bias; | |
uniforms.shadowRadius = shadow.radius; | |
uniforms.shadowMapSize = shadow.mapSize; | |
} | |
state.directionalShadowMap[ directionalLength ] = shadowMap; | |
state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; | |
state.directional[ directionalLength ] = uniforms; | |
directionalLength ++; | |
} else if ( light.isSpotLight ) { | |
var uniforms = cache.get( light ); | |
uniforms.position.setFromMatrixPosition( light.matrixWorld ); | |
uniforms.position.applyMatrix4( viewMatrix ); | |
uniforms.color.copy( color ).multiplyScalar( intensity ); | |
uniforms.distance = distance; | |
uniforms.direction.setFromMatrixPosition( light.matrixWorld ); | |
vector3.setFromMatrixPosition( light.target.matrixWorld ); | |
uniforms.direction.sub( vector3 ); | |
uniforms.direction.transformDirection( viewMatrix ); | |
uniforms.coneCos = Math.cos( light.angle ); | |
uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); | |
uniforms.decay = light.decay; | |
uniforms.shadow = light.castShadow; | |
if ( light.castShadow ) { | |
var shadow = light.shadow; | |
uniforms.shadowBias = shadow.bias; | |
uniforms.shadowRadius = shadow.radius; | |
uniforms.shadowMapSize = shadow.mapSize; | |
} | |
state.spotShadowMap[ spotLength ] = shadowMap; | |
state.spotShadowMatrix[ spotLength ] = light.shadow.matrix; | |
state.spot[ spotLength ] = uniforms; | |
spotLength ++; | |
} else if ( light.isRectAreaLight ) { | |
var uniforms = cache.get( light ); | |
// (a) intensity is the total visible light emitted | |
//uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) ); | |
// (b) intensity is the brightness of the light | |
uniforms.color.copy( color ).multiplyScalar( intensity ); | |
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 ); | |
// TODO (abelnation): RectAreaLight distance? | |
// uniforms.distance = distance; | |
state.rectArea[ rectAreaLength ] = uniforms; | |
rectAreaLength ++; | |
} else if ( light.isPointLight ) { | |
var uniforms = cache.get( light ); | |
uniforms.position.setFromMatrixPosition( light.matrixWorld ); | |
uniforms.position.applyMatrix4( viewMatrix ); | |
uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); | |
uniforms.distance = light.distance; | |
uniforms.decay = light.decay; | |
uniforms.shadow = light.castShadow; | |
if ( light.castShadow ) { | |
var shadow = light.shadow; | |
uniforms.shadowBias = shadow.bias; | |
uniforms.shadowRadius = shadow.radius; | |
uniforms.shadowMapSize = shadow.mapSize; | |
uniforms.shadowCameraNear = shadow.camera.near; | |
uniforms.shadowCameraFar = shadow.camera.far; | |
} | |
state.pointShadowMap[ pointLength ] = shadowMap; | |
state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; | |
state.point[ pointLength ] = uniforms; | |
pointLength ++; | |
} else if ( light.isHemisphereLight ) { | |
var uniforms = cache.get( light ); | |
uniforms.direction.setFromMatrixPosition( light.matrixWorld ); | |
uniforms.direction.transformDirection( viewMatrix ); | |
uniforms.direction.normalize(); | |
uniforms.skyColor.copy( light.color ).multiplyScalar( intensity ); | |
uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); | |
state.hemi[ hemiLength ] = uniforms; | |
hemiLength ++; | |
} | |
} | |
state.ambient[ 0 ] = r; | |
state.ambient[ 1 ] = g; | |
state.ambient[ 2 ] = b; | |
state.directional.length = directionalLength; | |
state.spot.length = spotLength; | |
state.rectArea.length = rectAreaLength; | |
state.point.length = pointLength; | |
state.hemi.length = hemiLength; | |
state.hash.stateID = state.id; | |
state.hash.directionalLength = directionalLength; | |
state.hash.pointLength = pointLength; | |
state.hash.spotLength = spotLength; | |
state.hash.rectAreaLength = rectAreaLength; | |
state.hash.hemiLength = hemiLength; | |
state.hash.shadowsLength = shadows.length; | |
} | |
return { | |
setup: setup, | |
state: state | |
}; | |
} | |
export { WebGLLights }; | |