2
0
Эх сурвалжийг харах

WebGLRenderer: Add `targetScene` parameter to `compile()` methods. (#26966)

Michael Herzog 1 жил өмнө
parent
commit
307e2e65ae

+ 6 - 2
examples/webgl_loader_gltf.html

@@ -62,9 +62,13 @@
 						const loader = new GLTFLoader().setPath( 'models/gltf/DamagedHelmet/glTF/' );
 						const loader = new GLTFLoader().setPath( 'models/gltf/DamagedHelmet/glTF/' );
 						loader.load( 'DamagedHelmet.gltf', async function ( 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();
 							render();
 			
 			

+ 35 - 57
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();
 			currentRenderState.init();
 
 
 			renderStateStack.push( currentRenderState );
 			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 ) ) {
 				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 );
 			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 ) {
 			scene.traverse( function ( object ) {
 
 
@@ -1036,15 +1004,15 @@ class WebGLRenderer {
 
 
 							const material2 = material[ i ];
 							const material2 = material[ i ];
 
 
-							prepareMaterial( material2, scene, object );
-							compiling.add( material2 );
+							prepareMaterial( material2, targetScene, object );
+							materials.add( material2 );
 
 
 						}
 						}
 
 
 					} else {
 					} else {
 
 
-						prepareMaterial( material, scene, object );
-						compiling.add( material );
+						prepareMaterial( material, targetScene, object );
+						materials.add( material );
 
 
 					}
 					}
 
 
@@ -1055,6 +1023,16 @@ class WebGLRenderer {
 			renderStateStack.pop();
 			renderStateStack.pop();
 			currentRenderState = null;
 			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
 			// Wait for all the materials in the new object to indicate that they're
 			// ready to be used before resolving the promise.
 			// ready to be used before resolving the promise.
 
 
@@ -1062,7 +1040,7 @@ class WebGLRenderer {
 
 
 				function checkMaterialsReady() {
 				function checkMaterialsReady() {
 
 
-					compiling.forEach( function ( material ) {
+					materials.forEach( function ( material ) {
 
 
 						const materialProperties = properties.get( material );
 						const materialProperties = properties.get( material );
 						const program = materialProperties.currentProgram;
 						const program = materialProperties.currentProgram;
@@ -1070,7 +1048,7 @@ class WebGLRenderer {
 						if ( program.isReady() ) {
 						if ( program.isReady() ) {
 
 
 							// remove any programs that report they're ready to use from the list
 							// 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
 					// once the list of compiling materials is empty, call the callback
 
 
-					if ( compiling.size === 0 ) {
+					if ( materials.size === 0 ) {
 
 
 						resolve( scene );
 						resolve( scene );
 						return;
 						return;