Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ function WebGLRenderer( parameters ) {
let currentRenderList = null;
let currentRenderState = null;

// render() can be called from within a callback triggered by another render.
// We track this so that the nested render call gets its state isolated from the parent render call.

const currentRenderCallStack = [];

// public properties

this.domElement = _canvas;
Expand Down Expand Up @@ -124,7 +129,6 @@ function WebGLRenderer( parameters ) {
let _currentMaterialId = - 1;

let _currentCamera = null;
let _currentArrayCamera = null;

const _currentViewport = new Vector4();
const _currentScissor = new Vector4();
Expand Down Expand Up @@ -870,7 +874,7 @@ function WebGLRenderer( parameters ) {

this.compile = function ( scene, camera ) {

currentRenderState = renderStates.get( scene, camera );
currentRenderState = renderStates.get( scene, 0 );
currentRenderState.init();

scene.traverse( function ( object ) {
Expand All @@ -889,7 +893,7 @@ function WebGLRenderer( parameters ) {

} );

currentRenderState.setupLights( camera );
currentRenderState.setupLights();

const compiled = new WeakMap();

Expand Down Expand Up @@ -1004,9 +1008,11 @@ function WebGLRenderer( parameters ) {
//
if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, renderTarget || _currentRenderTarget );

currentRenderState = renderStates.get( scene, camera );
currentRenderState = renderStates.get( scene, currentRenderCallStack.length );
currentRenderState.init();

currentRenderCallStack.push( currentRenderState );

_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
_frustum.setFromProjectionMatrix( _projScreenMatrix );

Expand Down Expand Up @@ -1034,7 +1040,8 @@ function WebGLRenderer( parameters ) {

shadowMap.render( shadowsArray, scene, camera );

currentRenderState.setupLights( camera );
currentRenderState.setupLights();
currentRenderState.setupLightsView( camera );

if ( _clippingEnabled === true ) clipping.endShadows();

Expand Down Expand Up @@ -1088,8 +1095,18 @@ function WebGLRenderer( parameters ) {

// _gl.finish();

currentRenderCallStack.pop();
if ( currentRenderCallStack.length > 0 ) {

currentRenderState = currentRenderCallStack[ currentRenderCallStack.length - 1 ];

} else {

currentRenderState = null;

}

currentRenderList = null;
currentRenderState = null;

};

Expand Down Expand Up @@ -1233,8 +1250,6 @@ function WebGLRenderer( parameters ) {

if ( camera.isArrayCamera ) {

_currentArrayCamera = camera;

const cameras = camera.cameras;

for ( let j = 0, jl = cameras.length; j < jl; j ++ ) {
Expand All @@ -1245,7 +1260,7 @@ function WebGLRenderer( parameters ) {

state.viewport( _currentViewport.copy( camera2.viewport ) );

currentRenderState.setupLights( camera2 );
currentRenderState.setupLightsView( camera2 );

renderObject( object, scene, camera2, geometry, material, group );

Expand All @@ -1255,8 +1270,6 @@ function WebGLRenderer( parameters ) {

} else {

_currentArrayCamera = null;

renderObject( object, scene, camera, geometry, material, group );

}
Expand All @@ -1268,7 +1281,6 @@ function WebGLRenderer( parameters ) {
function renderObject( object, scene, camera, geometry, material, group ) {

object.onBeforeRender( _this, scene, camera, geometry, material, group );
currentRenderState = renderStates.get( scene, _currentArrayCamera || camera );

object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
Expand All @@ -1290,7 +1302,6 @@ function WebGLRenderer( parameters ) {
}

object.onAfterRender( _this, scene, camera, geometry, material, group );
currentRenderState = renderStates.get( scene, _currentArrayCamera || camera );

}

Expand Down
3 changes: 2 additions & 1 deletion src/renderers/webgl/WebGLLights.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export class WebGLLights {
};

get( light: any ): any;
setup( lights: any, shadows: any, camera: any ): void;
setup( lights: any ): void;
setupView( lights: any, camera: any ): void;

}
122 changes: 87 additions & 35 deletions src/renderers/webgl/WebGLLights.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ function WebGLLights() {
const matrix4 = new Matrix4();
const matrix42 = new Matrix4();

function setup( lights, shadows, camera ) {
function setup( lights ) {

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

Expand All @@ -215,8 +215,6 @@ function WebGLLights() {
let numPointShadows = 0;
let numSpotShadows = 0;

const viewMatrix = camera.matrixWorldInverse;

lights.sort( shadowCastingLightsFirst );

for ( let i = 0, l = lights.length; i < l; i ++ ) {
Expand Down Expand Up @@ -248,10 +246,6 @@ function WebGLLights() {
const 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 );

if ( light.castShadow ) {

Expand Down Expand Up @@ -281,16 +275,10 @@ function WebGLLights() {
const 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;
Expand Down Expand Up @@ -328,24 +316,9 @@ function WebGLLights() {
// (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 ++;
Expand All @@ -354,9 +327,6 @@ function WebGLLights() {

const 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;
Expand Down Expand Up @@ -390,10 +360,6 @@ function WebGLLights() {

const 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 );

Expand Down Expand Up @@ -459,8 +425,94 @@ function WebGLLights() {

}

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 );
uniforms.direction.normalize();

hemiLength ++;

}

}

}

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

Expand Down
5 changes: 3 additions & 2 deletions src/renderers/webgl/WebGLRenderStates.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ interface WebGLRenderState {
shadowsArray: Light[];
lights: WebGLLights;
};
setupLights( camera: Camera ): void;
setupLights(): void;
setupLightsView( camera: Camera ): void;
pushLight( light: Light ): void;
pushShadow( shadowLight: Light ): void;

}

export class WebGLRenderStates {

get( scene: Scene, camera: Camera ): WebGLRenderState;
get( scene: Scene, renderCallNesting: number ): WebGLRenderState;
dispose(): void;

}
23 changes: 15 additions & 8 deletions src/renderers/webgl/WebGLRenderStates.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ function WebGLRenderState() {

}

function setupLights( camera ) {
function setupLights() {

lights.setup( lightsArray, shadowsArray, camera );
lights.setup( lightsArray );

}

function setupLightsView( camera ) {

lights.setupView( lightsArray, camera );

}

Expand All @@ -43,6 +49,7 @@ function WebGLRenderState() {
init: init,
state: state,
setupLights: setupLights,
setupLightsView: setupLightsView,

pushLight: pushLight,
pushShadow: pushShadow
Expand All @@ -54,26 +61,26 @@ function WebGLRenderStates() {

let renderStates = new WeakMap();

function get( scene, camera ) {
function get( scene, renderCallNesting ) {

let renderState;

if ( renderStates.has( scene ) === false ) {

renderState = new WebGLRenderState();
renderStates.set( scene, new WeakMap() );
renderStates.get( scene ).set( camera, renderState );
renderStates.set( scene, [] );
renderStates.get( scene ).push( renderState );

} else {

if ( renderStates.get( scene ).has( camera ) === false ) {
if ( renderCallNesting >= renderStates.get( scene ).length ) {

renderState = new WebGLRenderState();
renderStates.get( scene ).set( camera, renderState );
renderStates.get( scene ).push( renderState );

} else {

renderState = renderStates.get( scene ).get( camera );
renderState = renderStates.get( scene )[ renderCallNesting ];

}

Expand Down