Преглед на файлове

GLTFExporter: Merge occlusion, roughness and metalness textures (#23229)

* GLTFExporter: Build OcclusionRoughnessMetalness Texture.

* GLTFExporter: Fixed ORM texture check.

* GLTFExporter: Fixed typo.

* Clean up.
mrdoob преди 3 години
родител
ревизия
fd3983ac82
променени са 1 файла, в които са добавени 80 реда и са изтрити 12 реда
  1. 80 12
      examples/jsm/exporters/GLTFExporter.js

+ 80 - 12
examples/jsm/exporters/GLTFExporter.js

@@ -17,6 +17,7 @@ import {
 	RGBAFormat,
 	RepeatWrapping,
 	Scene,
+	Texture,
 	Vector3
 } from 'three';
 
@@ -688,6 +689,79 @@ class GLTFWriter {
 
 	}
 
+	buildORMTexture( material ) {
+
+		const occlusion = material.aoMap?.image;
+		const roughness = material.roughnessMap?.image;
+		const metalness = material.metalnessMap?.image;
+
+		if ( occlusion === roughness && roughness === metalness ) return occlusion;
+
+		if ( occlusion || roughness || 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 );
+
+			if ( occlusion ) {
+
+				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 ];
+
+				}
+
+			}
+
+			if ( roughness ) {
+
+				context.drawImage( roughness, 0, 0, width, height );
+
+				const data = context.getImageData( 0, 0, width, height ).data;
+
+				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 );
+
+			return new Texture( canvas );
+
+		}
+
+	}
+
 	/**
 	 * Process a buffer to append to the default one.
 	 * @param  {ArrayBuffer} buffer
@@ -1178,20 +1252,14 @@ class GLTFWriter {
 
 		}
 
+		const ormTexture = this.buildORMTexture( material );
+
 		// pbrMetallicRoughness.metallicRoughnessTexture
 		if ( material.metalnessMap || material.roughnessMap ) {
 
-			if ( material.metalnessMap === material.roughnessMap ) {
-
-				const metalRoughMapDef = { index: this.processTexture( material.metalnessMap ) };
-				this.applyTextureTransform( metalRoughMapDef, material.metalnessMap );
-				materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
-
-			} else {
-
-				console.warn( 'THREE.GLTFExporter: Ignoring metalnessMap and roughnessMap because they are not the same Texture.' );
-
-			}
+			const metalRoughMapDef = { index: this.processTexture( ormTexture ) };
+			this.applyTextureTransform( metalRoughMapDef, material.metalnessMap || material.roughnessMap );
+			materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
 
 		}
 
@@ -1257,7 +1325,7 @@ class GLTFWriter {
 		if ( material.aoMap ) {
 
 			const occlusionMapDef = {
-				index: this.processTexture( material.aoMap ),
+				index: this.processTexture( ormTexture ),
 				texCoord: 1
 			};