diff --git a/examples/webgl_loader_gltf.html b/examples/webgl_loader_gltf.html
index 5fc7e80327b48a..7b89a65f4dce71 100644
--- a/examples/webgl_loader_gltf.html
+++ b/examples/webgl_loader_gltf.html
@@ -62,9 +62,13 @@
const loader = new GLTFLoader().setPath( 'models/gltf/DamagedHelmet/glTF/' );
loader.load( 'DamagedHelmet.gltf', async function ( gltf ) {
- scene.add( gltf.scene );
+ const model = gltf.scene;
- await renderer.compileAsync( scene, camera );
+ // wait until the model can be added to the scene without blocking due to shader compilation
+
+ await renderer.compileAsync( model, camera, scene );
+
+ scene.add( model );
render();
diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js
index 1930522ee58ff7..15ebd1c6434e2c 100644
--- a/src/renderers/WebGLRenderer.js
+++ b/src/renderers/WebGLRenderer.js
@@ -939,14 +939,18 @@ class WebGLRenderer {
}
- this.compile = function ( scene, camera ) {
+ this.compile = function ( scene, camera, targetScene = null ) {
- currentRenderState = renderStates.get( scene );
+ if ( targetScene === null ) targetScene = scene;
+
+ currentRenderState = renderStates.get( targetScene );
currentRenderState.init();
renderStateStack.push( currentRenderState );
- scene.traverseVisible( function ( object ) {
+ // gather lights from both the target scene and the new object that will be added to the scene.
+
+ targetScene.traverseVisible( function ( object ) {
if ( object.isLight && object.layers.test( camera.layers ) ) {
@@ -962,67 +966,31 @@ class WebGLRenderer {
} );
- currentRenderState.setupLights( _this._useLegacyLights );
-
- scene.traverse( function ( object ) {
-
- const material = object.material;
+ if ( scene !== targetScene ) {
- if ( material ) {
+ scene.traverseVisible( function ( object ) {
- if ( Array.isArray( material ) ) {
+ if ( object.isLight && object.layers.test( camera.layers ) ) {
- for ( let i = 0; i < material.length; i ++ ) {
+ currentRenderState.pushLight( object );
- const material2 = material[ i ];
+ if ( object.castShadow ) {
- prepareMaterial( material2, scene, object );
+ currentRenderState.pushShadow( object );
}
- } else {
-
- prepareMaterial( material, scene, object );
-
}
- }
-
- } );
-
- renderStateStack.pop();
- currentRenderState = null;
-
- };
-
- // compileAsync
-
- this.compileAsync = function ( scene, camera ) {
-
- currentRenderState = renderStates.get( scene );
- currentRenderState.init();
-
- renderStateStack.push( currentRenderState );
-
- scene.traverseVisible( function ( object ) {
-
- if ( object.isLight && object.layers.test( camera.layers ) ) {
-
- currentRenderState.pushLight( object );
-
- if ( object.castShadow ) {
-
- currentRenderState.pushShadow( object );
-
- }
-
- }
+ } );
- } );
+ }
currentRenderState.setupLights( _this._useLegacyLights );
- const compiling = new Set();
+ // Only initialize materials in the new scene, not the targetScene.
+
+ const materials = new Set();
scene.traverse( function ( object ) {
@@ -1036,15 +1004,15 @@ class WebGLRenderer {
const material2 = material[ i ];
- prepareMaterial( material2, scene, object );
- compiling.add( material2 );
+ prepareMaterial( material2, targetScene, object );
+ materials.add( material2 );
}
} else {
- prepareMaterial( material, scene, object );
- compiling.add( material );
+ prepareMaterial( material, targetScene, object );
+ materials.add( material );
}
@@ -1055,6 +1023,16 @@ class WebGLRenderer {
renderStateStack.pop();
currentRenderState = null;
+ return materials;
+
+ };
+
+ // compileAsync
+
+ this.compileAsync = function ( scene, camera, targetScene = null ) {
+
+ const materials = this.compile( scene, camera, targetScene );
+
// Wait for all the materials in the new object to indicate that they're
// ready to be used before resolving the promise.
@@ -1062,7 +1040,7 @@ class WebGLRenderer {
function checkMaterialsReady() {
- compiling.forEach( function ( material ) {
+ materials.forEach( function ( material ) {
const materialProperties = properties.get( material );
const program = materialProperties.currentProgram;
@@ -1070,7 +1048,7 @@ class WebGLRenderer {
if ( program.isReady() ) {
// remove any programs that report they're ready to use from the list
- compiling.delete( material );
+ materials.delete( material );
}
@@ -1078,7 +1056,7 @@ class WebGLRenderer {
// once the list of compiling materials is empty, call the callback
- if ( compiling.size === 0 ) {
+ if ( materials.size === 0 ) {
resolve( scene );
return;