Răsfoiți Sursa

Keep OutlineMaterial in the cache of OutlineEffect (#9933)

Takahiro 8 ani în urmă
părinte
comite
8d06f14bb3
1 a modificat fișierele cu 78 adăugiri și 20 ștergeri
  1. 78 20
      examples/js/effects/OutlineEffect.js

+ 78 - 20
examples/js/effects/OutlineEffect.js

@@ -7,15 +7,17 @@
  * new THREE.OutlineEffect( renderer, {
  * 	defaultThickNess: 0.01,
  * 	defaultColor: new THREE.Color( 0x888888 ),
- * 	defaultAlpha: 0.8
+ * 	defaultAlpha: 0.8,
+ * 	defaultKeepAlive: true // keeps outline material in cache even if material is removed from scene
  * } );
  *
  * // How to set outline parameters for each material
  * material.outlineParameters = {
- * 	thickNess: 0.01,
- * 	color: new THREE.Color( 0x888888 ),
- * 	alpha: 0.8,
- * 	visible: true
+ * 	thickNess: 0.01,                     // this paremeter won't work for MultiMaterial
+ * 	color: new THREE.Color( 0x888888 ),  // this paremeter won't work for MultiMaterial
+ * 	alpha: 0.8,                          // this paremeter won't work for MultiMaterial
+ * 	visible: true,
+ * 	keepAlive: true  // this paremeter won't work for Material in materials of MultiMaterial
  * };
  *
  * TODO
@@ -34,6 +36,12 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 	var defaultThickness = parameters.defaultThickness !== undefined ? parameters.defaultThickness : 0.003;
 	var defaultColor = parameters.defaultColor !== undefined ? parameters.defaultColor : new THREE.Color( 0x000000 );
 	var defaultAlpha = parameters.defaultAlpha !== undefined ? parameters.defaultAlpha : 1.0;
+	var defaultKeepAlive = parameters.defaultKeepAlive !== undefined ? parameters.defaultKeepAlive : false;
+
+	var cache = {};
+	var removeThresholdCount = 60;
+
+	//this.cache = cache;  // for debug
 
 	var invisibleMaterial = new THREE.ShaderMaterial( { visible: false } );
 
@@ -110,7 +118,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	].join( "\n" );
 
-	function createMaterial ( originalMaterial ) {
+	function createMaterial( originalMaterial ) {
 
 		var shaderID = shaderIDs[ originalMaterial.type ];
 		var originalUniforms, originalVertexShader;
@@ -165,7 +173,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	}
 
-	function createMultiMaterial ( originalMaterial ) {
+	function createMultiMaterial( originalMaterial ) {
 
 		var materials = [];
 
@@ -179,33 +187,44 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	}
 
-	function setOutlineMaterial ( object ) {
+	function setOutlineMaterial( object ) {
 
 		if ( object.material === undefined ) return;
 
-		object.userData.originalMaterial = object.material;
+		var data = cache[ object.material.uuid ];
+
+		if ( data === undefined ) {
 
-		if ( object.userData.outlineMaterial === undefined ) {
+			data = {
+				material: object.material.type === 'MultiMaterial' ? createMultiMaterial( object.material ) : createMaterial( object.material ),
+				used: true,
+				keepAlive: defaultKeepAlive,
+				count: 0
+			};
 
-			object.userData.outlineMaterial = object.material.type === 'MultiMaterial' ? createMultiMaterial( object.material ) : createMaterial( object.material );
+			cache[ object.material.uuid ] = data;
 
 		}
 
-		if ( object.userData.outlineMaterial.type === 'MultiMaterial' ) {
+		var outlineMaterial = data.material;
+		data.used = true;
 
-			updateOutlineMultiMaterial( object.userData.outlineMaterial, object.userData.originalMaterial );
+		if ( outlineMaterial.type === 'MultiMaterial' ) {
+
+			updateOutlineMultiMaterial( outlineMaterial, object.material );
 
 		} else {
 
-			updateOutlineMaterial( object.userData.outlineMaterial, object.userData.originalMaterial );
+			updateOutlineMaterial( outlineMaterial, object.material );
 
 		}
 
-		object.material = object.userData.outlineMaterial;
+		object.userData.originalMaterial = object.material;
+		object.material = outlineMaterial;
 
 	}
 
-	function updateOutlineMaterial ( material, originalMaterial ) {
+	function updateOutlineMaterial( material, originalMaterial ) {
 
 		if ( material === invisibleMaterial ) return;
 
@@ -224,14 +243,16 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 			if ( outlineParameters.color !== undefined ) material.uniforms.outlineColor.value.copy( outlineParameters.color );
 			if ( outlineParameters.alpha !== undefined ) material.uniforms.outlineAlpha.value = outlineParameters.alpha;
 			if ( outlineParameters.visible !== undefined ) material.visible = outlineParameters.visible;
+			// cache[ originalMaterial.uuid ] is undefined if originalMaterial is in materials of MultiMaterial
+			if ( outlineParameters.keepAlive !== undefined && cache[ originalMaterial.uuid ] !== undefined ) cache[ originalMaterial.uuid ].keepAlive = outlineParameters.keepAlive;
 
 		}
 
-		if ( material.uniforms.outlineAlpha.value < 1.0 ) material.transparent = true;
+		material.transparent = ( material.uniforms.outlineAlpha.value < 1.0 ) ? true : false;
 
 	}
 
-	function updateOutlineMultiMaterial ( material, originalMaterial ) {
+	function updateOutlineMultiMaterial( material, originalMaterial ) {
 
 		var outlineParameters = originalMaterial.outlineParameters;
 
@@ -240,6 +261,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 		if ( outlineParameters !== undefined ) {
 
 			if ( outlineParameters.visible !== undefined ) material.visible = outlineParameters.visible;
+			if ( outlineParameters.keepAlive !== undefined ) cache[ originalMaterial.uuid ].keepAlive = outlineParameters.keepAlive;
 
 		}
 
@@ -251,9 +273,43 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	}
 
-	function restoreOriginalMaterial ( object ) {
+	function restoreOriginalMaterial( object ) {
+
+		if ( object.userData.originalMaterial !== undefined ) {
+
+			object.material = object.userData.originalMaterial;
+			object.userData.originalMaterial = undefined;
+
+		}
+
+	}
+
+	function removeUnusedOutlineMaterialFromCache() {
 
-		if ( object.userData.originalMaterial !== undefined ) object.material = object.userData.originalMaterial;
+		var keys = Object.keys( cache );
+
+		for ( var i = 0, il = keys.length; i < il; i ++ ) {
+
+			var key = keys[ i ];
+
+			if ( cache[ key ].used === false ) {
+
+				cache[ key ].count++;
+
+				if ( cache[ key ].keepAlive === false && cache[ key ].count > removeThresholdCount ) {
+
+					delete cache[ key ];
+
+				}
+
+			} else {
+
+				cache[ key ].used = false;
+				cache[ key ].count = 0;
+
+			}
+
+		}
 
 	}
 
@@ -285,6 +341,8 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 		scene.traverse( restoreOriginalMaterial );
 
+		removeUnusedOutlineMaterialFromCache();
+
 		scene.autoUpdate = currentSceneAutoUpdate;
 		renderer.autoClear = currentAutoClear;
 		renderer.shadowMap.enabled = currentShadowMapEnabled;