Răsfoiți Sursa

DRACOLoader, DRACOExporter: Assign color space to vertex colors. (#25390)

Don McCurdy 2 ani în urmă
părinte
comite
d5456c92b9

+ 1 - 1
editor/js/Loader.js

@@ -200,7 +200,7 @@ function Loader( editor ) {
 
 
 					const loader = new DRACOLoader();
 					const loader = new DRACOLoader();
 					loader.setDecoderPath( '../examples/jsm/libs/draco/' );
 					loader.setDecoderPath( '../examples/jsm/libs/draco/' );
-					loader.decodeDracoFile( contents, function ( geometry ) {
+					loader.parse( contents, function ( geometry ) {
 
 
 						let object;
 						let object;
 
 

+ 41 - 2
examples/jsm/exporters/DRACOExporter.js

@@ -1,3 +1,5 @@
+import { Color } from 'three';
+
 /**
 /**
  * Export draco compressed files from threejs geometry objects.
  * Export draco compressed files from threejs geometry objects.
  *
  *
@@ -100,7 +102,9 @@ class DRACOExporter {
 
 
 				if ( colors !== undefined ) {
 				if ( colors !== undefined ) {
 
 
-					builder.AddFloatAttributeToMesh( dracoObject, dracoEncoder.COLOR, colors.count, colors.itemSize, colors.array );
+					const array = createVertexColorSRGBArray( colors );
+
+					builder.AddFloatAttributeToMesh( dracoObject, dracoEncoder.COLOR, colors.count, colors.itemSize, array );
 
 
 				}
 				}
 
 
@@ -120,7 +124,9 @@ class DRACOExporter {
 
 
 				if ( colors !== undefined ) {
 				if ( colors !== undefined ) {
 
 
-					builder.AddFloatAttribute( dracoObject, dracoEncoder.COLOR, colors.count, colors.itemSize, colors.array );
+					const array = createVertexColorSRGBArray( colors );
+
+					builder.AddFloatAttribute( dracoObject, dracoEncoder.COLOR, colors.count, colors.itemSize, array );
 
 
 				}
 				}
 
 
@@ -206,6 +212,39 @@ class DRACOExporter {
 
 
 }
 }
 
 
+function createVertexColorSRGBArray( attribute ) {
+
+	// While .drc files do not specify colorspace, the only 'official' tooling
+	// is PLY and OBJ converters, which use sRGB. We'll assume sRGB is expected
+	// for .drc files, but note that Draco buffers embedded in glTF files will
+	// be Linear-sRGB instead.
+
+	const _color = new Color();
+
+	const count = attribute.count;
+	const itemSize = attribute.itemSize;
+	const array = new Float32Array( count * itemSize );
+
+	for ( let i = 0, il = count; i < il; i ++ ) {
+
+		_color.fromBufferAttribute( attribute, i ).convertLinearToSRGB();
+
+		array[ i * itemSize ] = _color.r;
+		array[ i * itemSize + 1 ] = _color.g;
+		array[ i * itemSize + 2 ] = _color.b;
+
+		if ( itemSize === 4 ) {
+
+			array[ i * itemSize + 3 ] = attribute.getW( i );
+
+		}
+
+	}
+
+	return array;
+
+}
+
 // Encoder methods
 // Encoder methods
 
 
 DRACOExporter.MESH_EDGEBREAKER_ENCODING = 1;
 DRACOExporter.MESH_EDGEBREAKER_ENCODING = 1;

+ 56 - 10
examples/jsm/loaders/DRACOLoader.js

@@ -1,8 +1,11 @@
 import {
 import {
 	BufferAttribute,
 	BufferAttribute,
 	BufferGeometry,
 	BufferGeometry,
+	Color,
 	FileLoader,
 	FileLoader,
-	Loader
+	Loader,
+	LinearSRGBColorSpace,
+	SRGBColorSpace
 } from 'three';
 } from 'three';
 
 
 const _taskCache = new WeakMap();
 const _taskCache = new WeakMap();
@@ -73,18 +76,25 @@ class DRACOLoader extends Loader {
 
 
 		loader.load( url, ( buffer ) => {
 		loader.load( url, ( buffer ) => {
 
 
-			this.decodeDracoFile( buffer, onLoad ).catch( onError );
+			this.parse( buffer, onLoad, onError );
 
 
 		}, onProgress, onError );
 		}, onProgress, onError );
 
 
 	}
 	}
 
 
-	decodeDracoFile( buffer, callback, attributeIDs, attributeTypes ) {
+	parse ( buffer, onLoad, onError ) {
+
+		this.decodeDracoFile( buffer, onLoad, null, null, SRGBColorSpace ).catch( onError );
+
+	}
+
+	decodeDracoFile( buffer, callback, attributeIDs, attributeTypes, vertexColorSpace = LinearSRGBColorSpace ) {
 
 
 		const taskConfig = {
 		const taskConfig = {
 			attributeIDs: attributeIDs || this.defaultAttributeIDs,
 			attributeIDs: attributeIDs || this.defaultAttributeIDs,
 			attributeTypes: attributeTypes || this.defaultAttributeTypes,
 			attributeTypes: attributeTypes || this.defaultAttributeTypes,
-			useUniqueIDs: !! attributeIDs
+			useUniqueIDs: !! attributeIDs,
+			vertexColorSpace: vertexColorSpace,
 		};
 		};
 
 
 		return this.decodeGeometry( buffer, taskConfig ).then( callback );
 		return this.decodeGeometry( buffer, taskConfig ).then( callback );
@@ -188,12 +198,20 @@ class DRACOLoader extends Loader {
 
 
 		for ( let i = 0; i < geometryData.attributes.length; i ++ ) {
 		for ( let i = 0; i < geometryData.attributes.length; i ++ ) {
 
 
-			const attribute = geometryData.attributes[ i ];
-			const name = attribute.name;
-			const array = attribute.array;
-			const itemSize = attribute.itemSize;
+			const result = geometryData.attributes[ i ];
+			const name = result.name;
+			const array = result.array;
+			const itemSize = result.itemSize;
+
+			const attribute = new BufferAttribute( array, itemSize );
+
+			if ( name === 'color' ) {
 
 
-			geometry.setAttribute( name, new BufferAttribute( array, itemSize ) );
+				this._assignVertexColorSpace( attribute, result.vertexColorSpace );
+
+			}
+
+			geometry.setAttribute( name, attribute );
 
 
 		}
 		}
 
 
@@ -201,6 +219,26 @@ class DRACOLoader extends Loader {
 
 
 	}
 	}
 
 
+	_assignVertexColorSpace( attribute, inputColorSpace ) {
+
+		// While .drc files do not specify colorspace, the only 'official' tooling
+		// is PLY and OBJ converters, which use sRGB. We'll assume sRGB when a .drc
+		// file is passed into .load() or .parse(). GLTFLoader uses internal APIs
+		// to decode geometry, and vertex colors are already Linear-sRGB in there.
+
+		if ( inputColorSpace !== SRGBColorSpace ) return;
+
+		const _color = new Color();
+
+		for ( let i = 0, il = attribute.count; i < il; i ++ ) {
+
+			_color.fromBufferAttribute( attribute, i ).convertSRGBToLinear();
+			attribute.setXYZ( i, _color.r, _color.g, _color.b );
+
+		}
+
+	}
+
 	_loadLibrary( url, responseType ) {
 	_loadLibrary( url, responseType ) {
 
 
 		const loader = new FileLoader( this.manager );
 		const loader = new FileLoader( this.manager );
@@ -493,7 +531,15 @@ function DRACOWorker() {
 
 
 			}
 			}
 
 
-			geometry.attributes.push( decodeAttribute( draco, decoder, dracoGeometry, attributeName, attributeType, attribute ) );
+			const attributeResult = decodeAttribute( draco, decoder, dracoGeometry, attributeName, attributeType, attribute );
+
+			if ( attributeName === 'color' ) {
+
+				attributeResult.vertexColorSpace = taskConfig.vertexColorSpace;
+
+			}
+
+			geometry.attributes.push( attributeResult );
 
 
 		}
 		}