Răsfoiți Sursa

PLYLoader: Honor PLY data types when creating buffer attributes. (#33622)

Michael Herzog 1 săptămână în urmă
părinte
comite
ca26a206ec
1 a modificat fișierele cu 218 adăugiri și 55 ștergeri
  1. 218 55
      examples/jsm/loaders/PLYLoader.js

+ 218 - 55
examples/jsm/loaders/PLYLoader.js

@@ -1,8 +1,15 @@
 import {
 	BufferGeometry,
 	FileLoader,
+	BufferAttribute,
 	Float32BufferAttribute,
+	Int8BufferAttribute,
+	Int16BufferAttribute,
+	Int32BufferAttribute,
 	Loader,
+	Uint8BufferAttribute,
+	Uint16BufferAttribute,
+	Uint32BufferAttribute,
 	Color,
 	SRGBColorSpace
 } from 'three';
@@ -317,7 +324,8 @@ class PLYLoader extends Loader {
 			  uvs: [],
 			  faceVertexUvs: [],
 			  colors: [],
-			  faceVertexColors: []
+			  faceVertexColors: [],
+			  descriptors: {}
 			};
 
 			for ( const customProperty of Object.keys( scope.customPropertyMapping ) ) {
@@ -330,21 +338,52 @@ class PLYLoader extends Loader {
 
 		}
 
-		function mapElementAttributes( properties ) {
 
-			const elementNames = properties.map( property => {
+		function getBufferAttributeClass( type ) {
 
-				return property.name;
+			switch ( type ) {
+
+				case 'int8': case 'char':		return Int8BufferAttribute;
+				case 'uint8': case 'uchar':		return Uint8BufferAttribute;
+				case 'int16': case 'short':		return Int16BufferAttribute;
+				case 'uint16': case 'ushort':	return Uint16BufferAttribute;
+				case 'int32': case 'int':		return Int32BufferAttribute;
+				case 'uint32': case 'uint':		return Uint32BufferAttribute;
+				case 'float32': case 'float':	return Float32BufferAttribute;
+				case 'float64': case 'double': 	return Float64BufferAttribute;
+
+			}
+
+		}
+
+		function getColorScale( type ) {
+
+			switch ( type ) {
+
+				case 'uchar': case 'uint8':	return 1 / 255;
+				case 'ushort': case 'uint16': return 1 / 65535;
+				case 'float': case 'float32':
+				case 'double': case 'float64': return 1;
+				default: return 1 / 255;
+
+			}
+
+		}
+
+		function isFloatType( type ) {
+
+			return type === 'float' || type === 'float32' || type === 'double' || type === 'float64';
 
-			} );
+		}
 
-			function findAttrName( names ) {
+		function getAttributeDescriptor( properties ) {
 
-				for ( let i = 0, l = names.length; i < l; i ++ ) {
+			function findProperty( names ) {
 
-					const name = names[ i ];
+				for ( const name of names ) {
 
-					if ( elementNames.includes( name ) ) return name;
+					const property = properties.find( p => p.name === name );
+					if ( property ) return property;
 
 				}
 
@@ -352,18 +391,67 @@ class PLYLoader extends Loader {
 
 			}
 
+			// property lookup
+
+			const x = findProperty( [ 'x', 'px', 'posx' ] );
+			const y = findProperty( [ 'y', 'py', 'posy' ] );
+			const z = findProperty( [ 'z', 'pz', 'posz' ] );
+			const nx = findProperty( [ 'nx', 'normalx' ] );
+			const ny = findProperty( [ 'ny', 'normaly' ] );
+			const nz = findProperty( [ 'nz', 'normalz' ] );
+			const s = findProperty( [ 's', 'u', 'texture_u', 'tx' ] );
+			const t = findProperty( [ 't', 'v', 'texture_v', 'ty' ] );
+			const r = findProperty( [ 'red', 'diffuse_red', 'r', 'diffuse_r' ] );
+			const g = findProperty( [ 'green', 'diffuse_green', 'g', 'diffuse_g' ] );
+			const b = findProperty( [ 'blue', 'diffuse_blue', 'b', 'diffuse_b' ] );
+			const texcoord = findProperty( [ 'texcoord' ] );
+
+			// custom property lookup
+
+			const custom = {};
+
+			for ( const customAttr of Object.keys( scope.customPropertyMapping ) ) {
+
+				const propNames = scope.customPropertyMapping[ customAttr ];
+				const matched = propNames.map( name => properties.find( p => p.name === name ) );
+				const types = matched.filter( p => p ).map( p => p.type );
+				const uniform = types.length > 0 && types.every( type => type === types[ 0 ] );
+
+				custom[ customAttr ] = {
+					type: uniform ? types[ 0 ] : 'float32',
+					usage: matched.every( p => p !== undefined ),
+				};
+
+			}
+
+			// build descriptor
+
 			return {
-				attrX: findAttrName( [ 'x', 'px', 'posx' ] ) || 'x',
-				attrY: findAttrName( [ 'y', 'py', 'posy' ] ) || 'y',
-				attrZ: findAttrName( [ 'z', 'pz', 'posz' ] ) || 'z',
-				attrNX: findAttrName( [ 'nx', 'normalx' ] ),
-				attrNY: findAttrName( [ 'ny', 'normaly' ] ),
-				attrNZ: findAttrName( [ 'nz', 'normalz' ] ),
-				attrS: findAttrName( [ 's', 'u', 'texture_u', 'tx' ] ),
-				attrT: findAttrName( [ 't', 'v', 'texture_v', 'ty' ] ),
-				attrR: findAttrName( [ 'red', 'diffuse_red', 'r', 'diffuse_r' ] ),
-				attrG: findAttrName( [ 'green', 'diffuse_green', 'g', 'diffuse_g' ] ),
-				attrB: findAttrName( [ 'blue', 'diffuse_blue', 'b', 'diffuse_b' ] ),
+				position: {
+					names: [ x ? x.name : 'x', y ? y.name : 'y', z ? z.name : 'z' ],
+					type: x ? x.type : 'float32',
+					usage: !! ( x && y && z ),
+				},
+				normal: {
+					names: [ nx ? nx.name : 'nx', ny ? ny.name : 'ny', nz ? nz.name : 'nz' ],
+					type: nx ? nx.type : 'float32',
+					usage: !! ( nx && ny && nz ),
+				},
+				uv: {
+					names: [ s ? s.name : 's', t ? t.name : 't' ],
+					type: s ? s.type : 'float32',
+					usage: !! ( s && t ),
+				},
+				texcoord: {
+					type: texcoord ? texcoord.itemType : 'float32',
+					usage: !! texcoord,
+				},
+				color: {
+					names: [ r ? r.name : 'red', g ? g.name : 'green', b ? b.name : 'blue' ],
+					type: r ? r.type : 'uchar',
+					usage: !! ( r && g && b ),
+				},
+				custom: custom,
 			};
 
 		}
@@ -392,7 +480,8 @@ class PLYLoader extends Loader {
 			loop: for ( let i = 0; i < header.elements.length; i ++ ) {
 
 				const elementDesc = header.elements[ i ];
-				const attributeMap = mapElementAttributes( elementDesc.properties );
+				const attributeDescriptor = getAttributeDescriptor( elementDesc.properties );
+				buffer.descriptors[ elementDesc.name ] = attributeDescriptor;
 
 				for ( let j = 0; j < elementDesc.count; j ++ ) {
 
@@ -400,7 +489,7 @@ class PLYLoader extends Loader {
 
 					if ( ! element ) break loop;
 
-					handleElement( buffer, elementDesc.name, element, attributeMap );
+					handleElement( buffer, elementDesc.name, element, attributeDescriptor );
 
 				}
 
@@ -414,6 +503,8 @@ class PLYLoader extends Loader {
 
 			let geometry = new BufferGeometry();
 
+			const vertexDescriptor = buffer.descriptors.vertex;
+
 			// mandatory buffer data
 
 			if ( buffer.indices.length > 0 ) {
@@ -422,25 +513,32 @@ class PLYLoader extends Loader {
 
 			}
 
-			geometry.setAttribute( 'position', new Float32BufferAttribute( buffer.vertices, 3 ) );
+			const PositionClass = getBufferAttributeClass( vertexDescriptor ? vertexDescriptor.position.type : 'float32' );
+			geometry.setAttribute( 'position', new PositionClass( buffer.vertices, 3 ) );
 
 			// optional buffer data
 
 			if ( buffer.normals.length > 0 ) {
 
-				geometry.setAttribute( 'normal', new Float32BufferAttribute( buffer.normals, 3 ) );
+				const NormalClass = getBufferAttributeClass( vertexDescriptor.normal.type );
+				geometry.setAttribute( 'normal', new NormalClass( buffer.normals, 3 ) );
 
 			}
 
 			if ( buffer.uvs.length > 0 ) {
 
-				geometry.setAttribute( 'uv', new Float32BufferAttribute( buffer.uvs, 2 ) );
+				const UvClass = getBufferAttributeClass( vertexDescriptor.uv.type );
+				geometry.setAttribute( 'uv', new UvClass( buffer.uvs, 2 ) );
 
 			}
 
 			if ( buffer.colors.length > 0 ) {
 
-				geometry.setAttribute( 'color', new Float32BufferAttribute( buffer.colors, 3 ) );
+				const colorType = vertexDescriptor.color.type;
+				const normalized = ! isFloatType( colorType );
+
+				const ColorClass = getBufferAttributeClass( colorType );
+				geometry.setAttribute( 'color', new ColorClass( buffer.colors, 3, normalized ) );
 
 			}
 
@@ -448,8 +546,22 @@ class PLYLoader extends Loader {
 
 				geometry = geometry.toNonIndexed();
 
-				if ( buffer.faceVertexUvs.length > 0 ) geometry.setAttribute( 'uv', new Float32BufferAttribute( buffer.faceVertexUvs, 2 ) );
-				if ( buffer.faceVertexColors.length > 0 ) geometry.setAttribute( 'color', new Float32BufferAttribute( buffer.faceVertexColors, 3 ) );
+				if ( buffer.faceVertexUvs.length > 0 ) {
+
+					const UvClass = getBufferAttributeClass( buffer.descriptors.face.texcoord.type );
+					geometry.setAttribute( 'uv', new UvClass( buffer.faceVertexUvs, 2 ) );
+
+				}
+
+				if ( buffer.faceVertexColors.length > 0 ) {
+
+					const colorType = buffer.descriptors.face.color.type;
+					const normalized = ! isFloatType( colorType );
+
+					const ColorClass = getBufferAttributeClass( colorType );
+					geometry.setAttribute( 'color', new ColorClass( buffer.faceVertexColors, 3, normalized ) );
+
+				}
 
 			}
 
@@ -459,13 +571,8 @@ class PLYLoader extends Loader {
 
 				if ( buffer[ customProperty ].length > 0 ) {
 
-				  	geometry.setAttribute(
-						customProperty,
-						new Float32BufferAttribute(
-					  		buffer[ customProperty ],
-					  		scope.customPropertyMapping[ customProperty ].length
-						)
-				  	);
+					const CustomClass = getBufferAttributeClass( vertexDescriptor.custom[ customProperty ].type );
+					geometry.setAttribute( customProperty, new CustomClass( buffer[ customProperty ], scope.customPropertyMapping[ customProperty ].length ) );
 
 				}
 
@@ -477,34 +584,64 @@ class PLYLoader extends Loader {
 
 		}
 
-		function handleElement( buffer, elementName, element, cacheEntry ) {
+		function handleElement( buffer, elementName, element, attributeDescriptor ) {
 
 			if ( elementName === 'vertex' ) {
 
-				buffer.vertices.push( element[ cacheEntry.attrX ], element[ cacheEntry.attrY ], element[ cacheEntry.attrZ ] );
+				const { position, normal, uv, color } = attributeDescriptor;
+
+				if ( position.usage ) {
+
+					buffer.vertices.push(
+						element[ position.names[ 0 ] ],
+						element[ position.names[ 1 ] ],
+						element[ position.names[ 2 ] ]
+					);
+
+				}
 
-				if ( cacheEntry.attrNX !== null && cacheEntry.attrNY !== null && cacheEntry.attrNZ !== null ) {
+				if ( normal.usage ) {
 
-					buffer.normals.push( element[ cacheEntry.attrNX ], element[ cacheEntry.attrNY ], element[ cacheEntry.attrNZ ] );
+					buffer.normals.push(
+						element[ normal.names[ 0 ] ],
+						element[ normal.names[ 1 ] ],
+						element[ normal.names[ 2 ] ]
+					);
 
 				}
 
-				if ( cacheEntry.attrS !== null && cacheEntry.attrT !== null ) {
+				if ( uv.usage ) {
 
-					buffer.uvs.push( element[ cacheEntry.attrS ], element[ cacheEntry.attrT ] );
+					buffer.uvs.push(
+						element[ uv.names[ 0 ] ],
+						element[ uv.names[ 1 ] ]
+					);
 
 				}
 
-				if ( cacheEntry.attrR !== null && cacheEntry.attrG !== null && cacheEntry.attrB !== null ) {
+				if ( color.usage ) {
+
+					const scale = getColorScale( color.type );
+					const isFloat = isFloatType( color.type );
+
+					// convert to float for color space conversion
 
 					_color.setRGB(
-						element[ cacheEntry.attrR ] / 255.0,
-						element[ cacheEntry.attrG ] / 255.0,
-						element[ cacheEntry.attrB ] / 255.0,
+						element[ color.names[ 0 ] ] * scale,
+						element[ color.names[ 1 ] ] * scale,
+						element[ color.names[ 2 ] ] * scale,
 						SRGBColorSpace
 					);
 
-					buffer.colors.push( _color.r, _color.g, _color.b );
+					// convert back to original type
+
+					const invScale = 1 / scale;
+
+					buffer.colors.push(
+						isFloat ? _color.r : Math.round( _color.r * invScale ),
+						isFloat ? _color.g : Math.round( _color.g * invScale ),
+						isFloat ? _color.b : Math.round( _color.b * invScale )
+					);
 
 				}
 
@@ -544,17 +681,32 @@ class PLYLoader extends Loader {
 
 				// face colors
 
-				if ( cacheEntry.attrR !== null && cacheEntry.attrG !== null && cacheEntry.attrB !== null ) {
+				const { color } = attributeDescriptor;
+
+				if ( color.usage ) {
+
+					// convert to float for color space conversion
+
+					const scale = getColorScale( color.type );
 
 					_color.setRGB(
-						element[ cacheEntry.attrR ] / 255.0,
-						element[ cacheEntry.attrG ] / 255.0,
-						element[ cacheEntry.attrB ] / 255.0,
+						element[ color.names[ 0 ] ] * scale,
+						element[ color.names[ 1 ] ] * scale,
+						element[ color.names[ 2 ] ] * scale,
 						SRGBColorSpace
 					);
-					buffer.faceVertexColors.push( _color.r, _color.g, _color.b );
-					buffer.faceVertexColors.push( _color.r, _color.g, _color.b );
-					buffer.faceVertexColors.push( _color.r, _color.g, _color.b );
+
+					// convert back to original type
+
+					const invScale = 1 / scale;
+
+					const r = _color.r * invScale;
+					const g = _color.g * invScale;
+					const b = _color.b * invScale;
+
+					buffer.faceVertexColors.push( r, g, b );
+					buffer.faceVertexColors.push( r, g, b );
+					buffer.faceVertexColors.push( r, g, b );
 
 				}
 
@@ -684,7 +836,8 @@ class PLYLoader extends Loader {
 
 				const elementDesc = header.elements[ currentElement ];
 				const properties = elementDesc.properties;
-				const attributeMap = mapElementAttributes( properties );
+				const attributeDescriptor = getAttributeDescriptor( properties );
+				buffer.descriptors[ elementDesc.name ] = attributeDescriptor;
 
 				setPropertyBinaryReaders( properties, body, little_endian );
 
@@ -694,7 +847,7 @@ class PLYLoader extends Loader {
 					loc += result[ 1 ];
 					const element = result[ 0 ];
 
-					handleElement( buffer, elementDesc.name, element, attributeMap );
+					handleElement( buffer, elementDesc.name, element, attributeDescriptor );
 
 				}
 
@@ -779,6 +932,16 @@ class PLYLoader extends Loader {
 
 }
 
+class Float64BufferAttribute extends BufferAttribute {
+
+	constructor( array, itemSize, normalized ) {
+
+		super( new Float64Array( array ), itemSize, normalized );
+
+	}
+
+}
+
 class ArrayStream {
 
 	constructor( arr ) {

粤ICP备19079148号