Skip to content

Commit b8433f3

Browse files
authored
Merge pull request #20422 from higharc/defer-light-transform
WebGLRenderer: Avoid creating per-camera render states.
2 parents 66e033f + 60defe3 commit b8433f3

File tree

6 files changed

+133
-73
lines changed

6 files changed

+133
-73
lines changed

src/renderers/WebGLRenderer.js

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ function WebGLRenderer( parameters ) {
6767
let currentRenderList = null;
6868
let currentRenderState = null;
6969

70+
// render() can be called from within a callback triggered by another render.
71+
// We track this so that the nested render call gets its state isolated from the parent render call.
72+
73+
const renderStateStack = [];
74+
7075
// public properties
7176

7277
this.domElement = _canvas;
@@ -133,7 +138,6 @@ function WebGLRenderer( parameters ) {
133138
let _currentMaterialId = - 1;
134139

135140
let _currentCamera = null;
136-
let _currentArrayCamera = null;
137141

138142
const _currentViewport = new Vector4();
139143
const _currentScissor = new Vector4();
@@ -887,7 +891,7 @@ function WebGLRenderer( parameters ) {
887891

888892
this.compile = function ( scene, camera ) {
889893

890-
currentRenderState = renderStates.get( scene, camera );
894+
currentRenderState = renderStates.get( scene );
891895
currentRenderState.init();
892896

893897
scene.traverseVisible( function ( object ) {
@@ -906,7 +910,7 @@ function WebGLRenderer( parameters ) {
906910

907911
} );
908912

909-
currentRenderState.setupLights( camera );
913+
currentRenderState.setupLights();
910914

911915
const compiled = new WeakMap();
912916

@@ -1021,9 +1025,11 @@ function WebGLRenderer( parameters ) {
10211025
//
10221026
if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, renderTarget || _currentRenderTarget );
10231027

1024-
currentRenderState = renderStates.get( scene, camera );
1028+
currentRenderState = renderStates.get( scene, renderStateStack.length );
10251029
currentRenderState.init();
10261030

1031+
renderStateStack.push( currentRenderState );
1032+
10271033
_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
10281034
_frustum.setFromProjectionMatrix( _projScreenMatrix );
10291035

@@ -1051,7 +1057,8 @@ function WebGLRenderer( parameters ) {
10511057

10521058
shadowMap.render( shadowsArray, scene, camera );
10531059

1054-
currentRenderState.setupLights( camera );
1060+
currentRenderState.setupLights();
1061+
currentRenderState.setupLightsView( camera );
10551062

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

@@ -1105,8 +1112,18 @@ function WebGLRenderer( parameters ) {
11051112

11061113
// _gl.finish();
11071114

1115+
renderStateStack.pop();
1116+
if ( renderStateStack.length > 0 ) {
1117+
1118+
currentRenderState = renderStateStack[ renderStateStack.length - 1 ];
1119+
1120+
} else {
1121+
1122+
currentRenderState = null;
1123+
1124+
}
1125+
11081126
currentRenderList = null;
1109-
currentRenderState = null;
11101127

11111128
};
11121129

@@ -1250,8 +1267,6 @@ function WebGLRenderer( parameters ) {
12501267

12511268
if ( camera.isArrayCamera ) {
12521269

1253-
_currentArrayCamera = camera;
1254-
12551270
const cameras = camera.cameras;
12561271

12571272
for ( let j = 0, jl = cameras.length; j < jl; j ++ ) {
@@ -1262,7 +1277,7 @@ function WebGLRenderer( parameters ) {
12621277

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

1265-
currentRenderState.setupLights( camera2 );
1280+
currentRenderState.setupLightsView( camera2 );
12661281

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

@@ -1272,8 +1287,6 @@ function WebGLRenderer( parameters ) {
12721287

12731288
} else {
12741289

1275-
_currentArrayCamera = null;
1276-
12771290
renderObject( object, scene, camera, geometry, material, group );
12781291

12791292
}
@@ -1285,7 +1298,6 @@ function WebGLRenderer( parameters ) {
12851298
function renderObject( object, scene, camera, geometry, material, group ) {
12861299

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

12901302
object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
12911303
object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
@@ -1307,7 +1319,6 @@ function WebGLRenderer( parameters ) {
13071319
}
13081320

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

13121323
}
13131324

@@ -1766,18 +1777,6 @@ function WebGLRenderer( parameters ) {
17661777

17671778
};
17681779

1769-
this.getRenderState = function () {
1770-
1771-
return currentRenderState;
1772-
1773-
};
1774-
1775-
this.setRenderState = function ( renderState ) {
1776-
1777-
currentRenderState = renderState;
1778-
1779-
};
1780-
17811780
this.getRenderTarget = function () {
17821781

17831782
return _currentRenderTarget;

src/renderers/webgl/WebGLCubeMaps.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,13 @@ function WebGLCubeMaps( renderer ) {
4242

4343
const currentRenderList = renderer.getRenderList();
4444
const currentRenderTarget = renderer.getRenderTarget();
45-
const currentRenderState = renderer.getRenderState();
4645

4746
const renderTarget = new WebGLCubeRenderTarget( image.height / 2 );
4847
renderTarget.fromEquirectangularTexture( renderer, texture );
4948
cubemaps.set( texture, renderTarget );
5049

5150
renderer.setRenderTarget( currentRenderTarget );
5251
renderer.setRenderList( currentRenderList );
53-
renderer.setRenderState( currentRenderState );
5452

5553
texture.addEventListener( 'dispose', onTextureDispose );
5654

src/renderers/webgl/WebGLLights.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export class WebGLLights {
3939
};
4040

4141
get( light: any ): any;
42-
setup( lights: any, shadows: any, camera: any ): void;
42+
setup( lights: any ): void;
43+
setupView( lights: any, camera: any ): void;
4344

4445
}

src/renderers/webgl/WebGLLights.js

Lines changed: 87 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ function WebGLLights( extensions, capabilities ) {
199199
const matrix4 = new Matrix4();
200200
const matrix42 = new Matrix4();
201201

202-
function setup( lights, shadows, camera ) {
202+
function setup( lights ) {
203203

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

@@ -215,8 +215,6 @@ function WebGLLights( extensions, capabilities ) {
215215
let numPointShadows = 0;
216216
let numSpotShadows = 0;
217217

218-
const viewMatrix = camera.matrixWorldInverse;
219-
220218
lights.sort( shadowCastingLightsFirst );
221219

222220
for ( let i = 0, l = lights.length; i < l; i ++ ) {
@@ -248,10 +246,6 @@ function WebGLLights( extensions, capabilities ) {
248246
const uniforms = cache.get( light );
249247

250248
uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
251-
uniforms.direction.setFromMatrixPosition( light.matrixWorld );
252-
vector3.setFromMatrixPosition( light.target.matrixWorld );
253-
uniforms.direction.sub( vector3 );
254-
uniforms.direction.transformDirection( viewMatrix );
255249

256250
if ( light.castShadow ) {
257251

@@ -281,16 +275,10 @@ function WebGLLights( extensions, capabilities ) {
281275
const uniforms = cache.get( light );
282276

283277
uniforms.position.setFromMatrixPosition( light.matrixWorld );
284-
uniforms.position.applyMatrix4( viewMatrix );
285278

286279
uniforms.color.copy( color ).multiplyScalar( intensity );
287280
uniforms.distance = distance;
288281

289-
uniforms.direction.setFromMatrixPosition( light.matrixWorld );
290-
vector3.setFromMatrixPosition( light.target.matrixWorld );
291-
uniforms.direction.sub( vector3 );
292-
uniforms.direction.transformDirection( viewMatrix );
293-
294282
uniforms.coneCos = Math.cos( light.angle );
295283
uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
296284
uniforms.decay = light.decay;
@@ -328,24 +316,9 @@ function WebGLLights( extensions, capabilities ) {
328316
// (b) intensity is the brightness of the light
329317
uniforms.color.copy( color ).multiplyScalar( intensity );
330318

331-
uniforms.position.setFromMatrixPosition( light.matrixWorld );
332-
uniforms.position.applyMatrix4( viewMatrix );
333-
334-
// extract local rotation of light to derive width/height half vectors
335-
matrix42.identity();
336-
matrix4.copy( light.matrixWorld );
337-
matrix4.premultiply( viewMatrix );
338-
matrix42.extractRotation( matrix4 );
339-
340319
uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
341320
uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
342321

343-
uniforms.halfWidth.applyMatrix4( matrix42 );
344-
uniforms.halfHeight.applyMatrix4( matrix42 );
345-
346-
// TODO (abelnation): RectAreaLight distance?
347-
// uniforms.distance = distance;
348-
349322
state.rectArea[ rectAreaLength ] = uniforms;
350323

351324
rectAreaLength ++;
@@ -354,9 +327,6 @@ function WebGLLights( extensions, capabilities ) {
354327

355328
const uniforms = cache.get( light );
356329

357-
uniforms.position.setFromMatrixPosition( light.matrixWorld );
358-
uniforms.position.applyMatrix4( viewMatrix );
359-
360330
uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
361331
uniforms.distance = light.distance;
362332
uniforms.decay = light.decay;
@@ -390,10 +360,6 @@ function WebGLLights( extensions, capabilities ) {
390360

391361
const uniforms = cache.get( light );
392362

393-
uniforms.direction.setFromMatrixPosition( light.matrixWorld );
394-
uniforms.direction.transformDirection( viewMatrix );
395-
uniforms.direction.normalize();
396-
397363
uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
398364
uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
399365

@@ -485,8 +451,94 @@ function WebGLLights( extensions, capabilities ) {
485451

486452
}
487453

454+
function setupView( lights, camera ) {
455+
456+
let directionalLength = 0;
457+
let pointLength = 0;
458+
let spotLength = 0;
459+
let rectAreaLength = 0;
460+
let hemiLength = 0;
461+
462+
const viewMatrix = camera.matrixWorldInverse;
463+
464+
for ( let i = 0, l = lights.length; i < l; i ++ ) {
465+
466+
const light = lights[ i ];
467+
468+
if ( light.isDirectionalLight ) {
469+
470+
const uniforms = state.directional[ directionalLength ];
471+
472+
uniforms.direction.setFromMatrixPosition( light.matrixWorld );
473+
vector3.setFromMatrixPosition( light.target.matrixWorld );
474+
uniforms.direction.sub( vector3 );
475+
uniforms.direction.transformDirection( viewMatrix );
476+
477+
directionalLength ++;
478+
479+
} else if ( light.isSpotLight ) {
480+
481+
const uniforms = state.spot[ spotLength ];
482+
483+
uniforms.position.setFromMatrixPosition( light.matrixWorld );
484+
uniforms.position.applyMatrix4( viewMatrix );
485+
486+
uniforms.direction.setFromMatrixPosition( light.matrixWorld );
487+
vector3.setFromMatrixPosition( light.target.matrixWorld );
488+
uniforms.direction.sub( vector3 );
489+
uniforms.direction.transformDirection( viewMatrix );
490+
491+
spotLength ++;
492+
493+
} else if ( light.isRectAreaLight ) {
494+
495+
const uniforms = state.rectArea[ rectAreaLength ];
496+
497+
uniforms.position.setFromMatrixPosition( light.matrixWorld );
498+
uniforms.position.applyMatrix4( viewMatrix );
499+
500+
// extract local rotation of light to derive width/height half vectors
501+
matrix42.identity();
502+
matrix4.copy( light.matrixWorld );
503+
matrix4.premultiply( viewMatrix );
504+
matrix42.extractRotation( matrix4 );
505+
506+
uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
507+
uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
508+
509+
uniforms.halfWidth.applyMatrix4( matrix42 );
510+
uniforms.halfHeight.applyMatrix4( matrix42 );
511+
512+
rectAreaLength ++;
513+
514+
} else if ( light.isPointLight ) {
515+
516+
const uniforms = state.point[ pointLength ];
517+
518+
uniforms.position.setFromMatrixPosition( light.matrixWorld );
519+
uniforms.position.applyMatrix4( viewMatrix );
520+
521+
pointLength ++;
522+
523+
} else if ( light.isHemisphereLight ) {
524+
525+
const uniforms = state.hemi[ hemiLength ];
526+
527+
uniforms.direction.setFromMatrixPosition( light.matrixWorld );
528+
uniforms.direction.transformDirection( viewMatrix );
529+
uniforms.direction.normalize();
530+
531+
hemiLength ++;
532+
533+
}
534+
535+
}
536+
537+
}
538+
488539
return {
489540
setup: setup,
541+
setupView: setupView,
490542
state: state
491543
};
492544

src/renderers/webgl/WebGLRenderStates.d.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ interface WebGLRenderState {
1414
shadowsArray: Light[];
1515
lights: WebGLLights;
1616
};
17-
setupLights( camera: Camera ): void;
17+
setupLights(): void;
18+
setupLightsView( camera: Camera ): void;
1819
pushLight( light: Light ): void;
1920
pushShadow( shadowLight: Light ): void;
2021

@@ -24,7 +25,9 @@ export class WebGLRenderStates {
2425

2526
constructor( extensions: WebGLExtensions, capabilities: WebGLCapabilities );
2627

27-
get( scene: Scene, camera: Camera ): WebGLRenderState;
28+
// renderCallDepth indexes start from 0.
29+
get( scene: Scene, renderCallDepth?: number ): WebGLRenderState;
30+
2831
dispose(): void;
2932

3033
}

0 commit comments

Comments
 (0)