Mr.doob 3 лет назад
Родитель
Сommit
d37f7d0d37

+ 41 - 52
examples/js/exporters/GLTFExporter.js

@@ -626,68 +626,55 @@
 
 		}
 
-		buildORMTexture( material ) {
+		buildMetalRoughTexture( metalnessMap, roughnessMap ) {
 
-			const occlusion = material.aoMap?.image;
-			const roughness = material.roughnessMap?.image;
-			const metalness = material.metalnessMap?.image;
-			if ( occlusion === roughness && roughness === metalness ) return material.aoMap;
+			if ( metalnessMap === roughnessMap ) return metalnessMap;
+			console.warn( 'THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.' );
+			const metalness = metalnessMap?.image;
+			const roughness = roughnessMap?.image;
+			const width = Math.max( metalness?.width || 0, roughness?.width || 0 );
+			const height = Math.max( metalness?.height || 0, roughness?.height || 0 );
+			const canvas = document.createElement( 'canvas' );
+			canvas.width = width;
+			canvas.height = height;
+			const context = canvas.getContext( '2d' );
+			context.fillStyle = '#00ffff';
+			context.fillRect( 0, 0, width, height );
+			const composite = context.getImageData( 0, 0, width, height );
 
-			if ( occlusion || roughness || metalness ) {
+			if ( metalness ) {
 
-				const width = Math.max( occlusion?.width || 0, roughness?.width || 0, metalness?.width || 0 );
-				const height = Math.max( occlusion?.height || 0, roughness?.height || 0, metalness?.height || 0 );
-				const canvas = document.createElement( 'canvas' );
-				canvas.width = width;
-				canvas.height = height;
-				const context = canvas.getContext( '2d' );
-				context.fillStyle = '#ffffff';
-				context.fillRect( 0, 0, width, height );
-				const composite = context.getImageData( 0, 0, width, height );
+				context.drawImage( metalness, 0, 0, width, height );
+				const data = context.getImageData( 0, 0, width, height ).data;
 
-				if ( occlusion ) {
+				for ( let i = 2; i < data.length; i += 4 ) {
 
-					context.drawImage( occlusion, 0, 0, width, height );
-					const data = context.getImageData( 0, 0, width, height ).data;
-
-					for ( let i = 0; i < data.length; i += 4 ) {
-
-						composite.data[ i ] = data[ i ];
-
-					}
+					composite.data[ i ] = data[ i ];
 
 				}
 
-				if ( roughness ) {
+			}
 
-					context.drawImage( roughness, 0, 0, width, height );
-					const data = context.getImageData( 0, 0, width, height ).data;
+			if ( roughness ) {
 
-					for ( let i = 1; i < data.length; i += 4 ) {
+				context.drawImage( roughness, 0, 0, width, height );
+				const data = context.getImageData( 0, 0, width, height ).data;
 
-						composite.data[ i ] = data[ i ];
+				for ( let i = 1; i < data.length; i += 4 ) {
 
-					}
+					composite.data[ i ] = data[ i ];
 
 				}
 
-				if ( metalness ) {
-
-					context.drawImage( metalness, 0, 0, width, height );
-					const data = context.getImageData( 0, 0, width, height ).data;
-
-					for ( let i = 2; i < data.length; i += 4 ) {
-
-						composite.data[ i ] = data[ i ];
-
-					}
+			}
 
-				}
+			context.putImageData( composite, 0, 0 ); //
 
-				context.putImageData( composite, 0, 0 );
-				return new THREE.Texture( canvas );
+			const reference = metalnessMap || roughnessMap;
+			const texture = reference.clone(); // TODO Use new Source() instead?
 
-			}
+			texture.source = new THREE.Texture( canvas ).source;
+			return texture;
 
 		}
 		/**
@@ -933,11 +920,12 @@
    * @param  {Image} image to process
    * @param  {Integer} format of the image (THREE.RGBAFormat)
    * @param  {Boolean} flipY before writing out the image
+   * @param  {String} mimeType export format
    * @return {Integer}     Index of the processed texture in the "images" array
    */
 
 
-		processImage( image, format, flipY ) {
+		processImage( image, format, flipY, mimeType = 'image/png' ) {
 
 			const writer = this;
 			const cache = writer.cache;
@@ -946,7 +934,6 @@
 			const pending = writer.pending;
 			if ( ! cache.images.has( image ) ) cache.images.set( image, {} );
 			const cachedImages = cache.images.get( image );
-			const mimeType = 'image/png';
 			const key = mimeType + ':flipY/' + flipY.toString();
 			if ( cachedImages[ key ] !== undefined ) return cachedImages[ key ];
 			if ( ! json.images ) json.images = [];
@@ -1068,9 +1055,11 @@
 			const json = this.json;
 			if ( cache.textures.has( map ) ) return cache.textures.get( map );
 			if ( ! json.textures ) json.textures = [];
+			let mimeType = map.userData.mimeType;
+			if ( mimeType === 'image/webp' ) mimeType = 'image/png';
 			const textureDef = {
 				sampler: this.processSampler( map ),
-				source: this.processImage( map.image, map.format, map.flipY )
+				source: this.processImage( map.image, map.format, map.flipY, mimeType )
 			};
 			if ( map.name ) textureDef.name = map.name;
 
@@ -1136,16 +1125,16 @@
 				materialDef.pbrMetallicRoughness.metallicFactor = 0.5;
 				materialDef.pbrMetallicRoughness.roughnessFactor = 0.5;
 
-			}
+			} // pbrMetallicRoughness.metallicRoughnessTexture
 
-			const ormTexture = this.buildORMTexture( material ); // pbrMetallicRoughness.metallicRoughnessTexture
 
 			if ( material.metalnessMap || material.roughnessMap ) {
 
+				const metalRoughTexture = this.buildMetalRoughTexture( material.metalnessMap, material.roughnessMap );
 				const metalRoughMapDef = {
-					index: this.processTexture( ormTexture )
+					index: this.processTexture( metalRoughTexture )
 				};
-				this.applyTextureTransform( metalRoughMapDef, material.metalnessMap || material.roughnessMap );
+				this.applyTextureTransform( metalRoughMapDef, metalRoughTexture );
 				materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
 
 			} // pbrMetallicRoughness.baseColorTexture or pbrSpecularGlossiness diffuseTexture
@@ -1217,7 +1206,7 @@
 			if ( material.aoMap ) {
 
 				const occlusionMapDef = {
-					index: this.processTexture( ormTexture ),
+					index: this.processTexture( material.aoMap ),
 					texCoord: 1
 				};
 

+ 2 - 2
examples/js/helpers/ViewHelper.js

@@ -127,8 +127,8 @@
 
 				if ( this.animating === true ) return false;
 				const rect = dom.getBoundingClientRect();
-				const offsetX = rect.left + ( container.dom.offsetWidth - dim );
-				const offsetY = rect.top + ( container.dom.offsetHeight - dim );
+				const offsetX = rect.left + ( dom.offsetWidth - dim );
+				const offsetY = rect.top + ( dom.offsetHeight - dim );
 				mouse.x = ( event.clientX - offsetX ) / ( rect.width - offsetX ) * 2 - 1;
 				mouse.y = - ( ( event.clientY - offsetY ) / ( rect.bottom - offsetY ) ) * 2 + 1;
 				raycaster.setFromCamera( mouse, camera );

+ 9 - 0
examples/js/loaders/GLTFLoader.js

@@ -1981,6 +1981,14 @@
 
 		}
 
+	}
+
+	function getImageURIMimeType( uri ) {
+
+		if ( uri.search( /\.jpe?g($|\?)/i ) > 0 || uri.search( /^data\:image\/jpeg/ ) === 0 ) return 'image/jpeg';
+		if ( uri.search( /\.webp($|\?)/i ) > 0 || uri.search( /^data\:image\/webp/ ) === 0 ) return 'image/webp';
+		return 'image/png';
+
 	}
 	/* GLTF PARSER */
 
@@ -2683,6 +2691,7 @@
 
 				}
 
+				texture.userData.mimeType = sourceDef.mimeType || getImageURIMimeType( sourceDef.uri );
 				return texture;
 
 			} ).catch( function ( error ) {

+ 26 - 25
examples/js/math/Lut.js

@@ -44,27 +44,35 @@
 			this.map = ColorMapKeywords[ colormap ] || ColorMapKeywords.rainbow;
 			this.n = count;
 			const step = 1.0 / this.n;
-			this.lut.length = 0;
+			const minColor = new THREE.Color();
+			const maxColor = new THREE.Color();
+			this.lut.length = 0; // sample at 0
 
-			for ( let i = 0; i <= 1; i += step ) {
+			this.lut.push( new THREE.Color( this.map[ 0 ][ 1 ] ) ); // sample at 1/n, ..., (n-1)/n
+
+			for ( let i = 1; i < count; i ++ ) {
+
+				const alpha = i * step;
 
 				for ( let j = 0; j < this.map.length - 1; j ++ ) {
 
-					if ( i >= this.map[ j ][ 0 ] && i < this.map[ j + 1 ][ 0 ] ) {
+					if ( alpha > this.map[ j ][ 0 ] && alpha <= this.map[ j + 1 ][ 0 ] ) {
 
 						const min = this.map[ j ][ 0 ];
 						const max = this.map[ j + 1 ][ 0 ];
-						const minColor = new THREE.Color( this.map[ j ][ 1 ] );
-						const maxColor = new THREE.Color( this.map[ j + 1 ][ 1 ] );
-						const color = minColor.lerp( maxColor, ( i - min ) / ( max - min ) );
+						minColor.set( this.map[ j ][ 1 ] );
+						maxColor.set( this.map[ j + 1 ][ 1 ] );
+						const color = new THREE.Color().lerpColors( minColor, maxColor, ( alpha - min ) / ( max - min ) );
 						this.lut.push( color );
 
 					}
 
 				}
 
-			}
+			} // sample at 1
 
+
+			this.lut.push( new THREE.Color( this.map[ this.map.length - 1 ][ 1 ] ) );
 			return this;
 
 		}
@@ -82,19 +90,9 @@
 
 		getColor( alpha ) {
 
-			if ( alpha <= this.minV ) {
-
-				alpha = this.minV;
-
-			} else if ( alpha >= this.maxV ) {
-
-				alpha = this.maxV;
-
-			}
-
+			alpha = THREE.MathUtils.clamp( alpha, this.minV, this.maxV );
 			alpha = ( alpha - this.minV ) / ( this.maxV - this.minV );
-			let colorPosition = Math.round( alpha * this.n );
-			if ( colorPosition === this.n ) colorPosition -= 1;
+			const colorPosition = Math.round( alpha * this.n );
 			return this.lut[ colorPosition ];
 
 		}
@@ -125,6 +123,9 @@
 			const data = imageData.data;
 			let k = 0;
 			const step = 1.0 / this.n;
+			const minColor = new THREE.Color();
+			const maxColor = new THREE.Color();
+			const finalColor = new THREE.Color();
 
 			for ( let i = 1; i >= 0; i -= step ) {
 
@@ -134,12 +135,12 @@
 
 						const min = this.map[ j - 1 ][ 0 ];
 						const max = this.map[ j ][ 0 ];
-						const minColor = new THREE.Color( this.map[ j - 1 ][ 1 ] );
-						const maxColor = new THREE.Color( this.map[ j ][ 1 ] );
-						const color = minColor.lerp( maxColor, ( i - min ) / ( max - min ) );
-						data[ k * 4 ] = Math.round( color.r * 255 );
-						data[ k * 4 + 1 ] = Math.round( color.g * 255 );
-						data[ k * 4 + 2 ] = Math.round( color.b * 255 );
+						minColor.set( this.map[ j - 1 ][ 1 ] );
+						maxColor.set( this.map[ j ][ 1 ] );
+						finalColor.lerpColors( minColor, maxColor, ( i - min ) / ( max - min ) );
+						data[ k * 4 ] = Math.round( finalColor.r * 255 );
+						data[ k * 4 + 1 ] = Math.round( finalColor.g * 255 );
+						data[ k * 4 + 2 ] = Math.round( finalColor.b * 255 );
 						data[ k * 4 + 3 ] = 255;
 						k += 1;
 

+ 6 - 7
examples/js/renderers/CSS2DRenderer.js

@@ -102,17 +102,16 @@
 
 				if ( object.isCSS2DObject ) {
 
-					const visible = object.visible && _vector.z >= - 1 && _vector.z <= 1 && object.layers.test( camera.layers );
-					object.element.style.display = visible ? '' : 'none';
+					_vector.setFromMatrixPosition( object.matrixWorld );
 
-					if ( visible ) {
+					_vector.applyMatrix4( _viewProjectionMatrix );
 
-						object.onBeforeRender( _this, scene, camera );
-
-						_vector.setFromMatrixPosition( object.matrixWorld );
+					const visible = object.visible === true && _vector.z >= - 1 && _vector.z <= 1 && object.layers.test( camera.layers ) === true;
+					object.element.style.display = visible === true ? '' : 'none';
 
-						_vector.applyMatrix4( _viewProjectionMatrix );
+					if ( visible === true ) {
 
+						object.onBeforeRender( _this, scene, camera );
 						const element = object.element;
 
 						if ( /apple/i.test( navigator.vendor ) ) {

+ 3 - 3
examples/js/renderers/CSS3DRenderer.js

@@ -181,10 +181,10 @@
 
 				if ( object.isCSS3DObject ) {
 
-					const visible = object.visible && object.layers.test( camera.layers );
-					object.element.style.display = visible ? '' : 'none'; // only getObjectCSSMatrix when object.visible
+					const visible = object.visible === true && object.layers.test( camera.layers ) === true;
+					object.element.style.display = visible === true ? '' : 'none';
 
-					if ( visible ) {
+					if ( visible === true ) {
 
 						object.onBeforeRender( _this, scene, camera );
 						let style;