|
@@ -298,6 +298,40 @@ class PLYLoader extends Loader {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function mapElementAttributes( properties ) {
|
|
|
+
|
|
|
+ const elementNames = properties.map( property => { return property.name } );
|
|
|
+
|
|
|
+ function findAttrName( names ) {
|
|
|
+
|
|
|
+ for ( let i = 0, l = names.length; i < l; i ++ ) {
|
|
|
+
|
|
|
+ const name = names[ i ];
|
|
|
+
|
|
|
+ if ( name in elementNames ) return name;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ 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' ] ),
|
|
|
+ };
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
function parseASCII( data, header ) {
|
|
|
|
|
|
// PLY ascii format specification, as per http://en.wikipedia.org/wiki/PLY_(file_format)
|
|
@@ -317,6 +351,8 @@ class PLYLoader extends Loader {
|
|
|
const lines = body.split( /\r\n|\r|\n/ );
|
|
|
let currentElement = 0;
|
|
|
let currentElementCount = 0;
|
|
|
+ let elementDesc = header.elements[ currentElement ];
|
|
|
+ let attributeMap = mapElementAttributes( elementDesc.properties );
|
|
|
|
|
|
for ( let i = 0; i < lines.length; i ++ ) {
|
|
|
|
|
@@ -328,16 +364,19 @@ class PLYLoader extends Loader {
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( currentElementCount >= header.elements[ currentElement ].count ) {
|
|
|
+ if ( currentElementCount >= elementDesc.count ) {
|
|
|
|
|
|
currentElement ++;
|
|
|
currentElementCount = 0;
|
|
|
+ elementDesc = header.elements[ currentElement ];
|
|
|
+
|
|
|
+ attributeMap = mapElementAttributes( elementDesc.properties );
|
|
|
|
|
|
}
|
|
|
|
|
|
- const element = parseASCIIElement( header.elements[ currentElement ].properties, line );
|
|
|
+ const element = parseASCIIElement( elementDesc.properties, line );
|
|
|
|
|
|
- handleElement( buffer, header.elements[ currentElement ].name, element );
|
|
|
+ handleElement( buffer, elementDesc.name, element, attributeMap );
|
|
|
|
|
|
currentElementCount ++;
|
|
|
|
|
@@ -412,56 +451,30 @@ class PLYLoader extends Loader {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function handleElement( buffer, elementName, element ) {
|
|
|
-
|
|
|
- function findAttrName( names ) {
|
|
|
-
|
|
|
- for ( let i = 0, l = names.length; i < l; i ++ ) {
|
|
|
-
|
|
|
- const name = names[ i ];
|
|
|
-
|
|
|
- if ( name in element ) return name;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return null;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- const attrX = findAttrName( [ 'x', 'px', 'posx' ] ) || 'x';
|
|
|
- const attrY = findAttrName( [ 'y', 'py', 'posy' ] ) || 'y';
|
|
|
- const attrZ = findAttrName( [ 'z', 'pz', 'posz' ] ) || 'z';
|
|
|
- const attrNX = findAttrName( [ 'nx', 'normalx' ] );
|
|
|
- const attrNY = findAttrName( [ 'ny', 'normaly' ] );
|
|
|
- const attrNZ = findAttrName( [ 'nz', 'normalz' ] );
|
|
|
- const attrS = findAttrName( [ 's', 'u', 'texture_u', 'tx' ] );
|
|
|
- const attrT = findAttrName( [ 't', 'v', 'texture_v', 'ty' ] );
|
|
|
- const attrR = findAttrName( [ 'red', 'diffuse_red', 'r', 'diffuse_r' ] );
|
|
|
- const attrG = findAttrName( [ 'green', 'diffuse_green', 'g', 'diffuse_g' ] );
|
|
|
- const attrB = findAttrName( [ 'blue', 'diffuse_blue', 'b', 'diffuse_b' ] );
|
|
|
+ function handleElement( buffer, elementName, element, cacheEntry ) {
|
|
|
|
|
|
if ( elementName === 'vertex' ) {
|
|
|
|
|
|
- buffer.vertices.push( element[ attrX ], element[ attrY ], element[ attrZ ] );
|
|
|
+ buffer.vertices.push( element[ cacheEntry.attrX ], element[ cacheEntry.attrY ], element[ cacheEntry.attrZ ] );
|
|
|
|
|
|
- if ( attrNX !== null && attrNY !== null && attrNZ !== null ) {
|
|
|
+ if ( cacheEntry.attrNX !== null && cacheEntry.attrNY !== null && cacheEntry.attrNZ !== null ) {
|
|
|
|
|
|
- buffer.normals.push( element[ attrNX ], element[ attrNY ], element[ attrNZ ] );
|
|
|
+ buffer.normals.push( element[ cacheEntry.attrNX ], element[ cacheEntry.attrNY ], element[ cacheEntry.attrNZ ] );
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( attrS !== null && attrT !== null ) {
|
|
|
+ if ( cacheEntry.attrS !== null && cacheEntry.attrT !== null ) {
|
|
|
|
|
|
- buffer.uvs.push( element[ attrS ], element[ attrT ] );
|
|
|
+ buffer.uvs.push( element[ cacheEntry.attrS ], element[ cacheEntry.attrT ] );
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( attrR !== null && attrG !== null && attrB !== null ) {
|
|
|
+ if ( cacheEntry.attrR !== null && cacheEntry.attrG !== null && cacheEntry.attrB !== null ) {
|
|
|
|
|
|
_color.setRGB(
|
|
|
- element[ attrR ] / 255.0,
|
|
|
- element[ attrG ] / 255.0,
|
|
|
- element[ attrB ] / 255.0
|
|
|
+ element[ cacheEntry.attrR ] / 255.0,
|
|
|
+ element[ cacheEntry.attrG ] / 255.0,
|
|
|
+ element[ cacheEntry.attrB ] / 255.0
|
|
|
).convertSRGBToLinear();
|
|
|
|
|
|
buffer.colors.push( _color.r, _color.g, _color.b );
|
|
@@ -573,13 +586,16 @@ class PLYLoader extends Loader {
|
|
|
|
|
|
for ( let currentElement = 0; currentElement < header.elements.length; currentElement ++ ) {
|
|
|
|
|
|
- for ( let currentElementCount = 0; currentElementCount < header.elements[ currentElement ].count; currentElementCount ++ ) {
|
|
|
+ const elementDesc = header.elements[ currentElement ];
|
|
|
+ const attributeMap = mapElementAttributes( elementDesc.properties );
|
|
|
|
|
|
- result = binaryReadElement( body, loc, header.elements[ currentElement ].properties, little_endian );
|
|
|
+ for ( let currentElementCount = 0; currentElementCount < elementDesc.count; currentElementCount ++ ) {
|
|
|
+
|
|
|
+ result = binaryReadElement( body, loc, elementDesc.properties, little_endian );
|
|
|
loc += result[ 1 ];
|
|
|
const element = result[ 0 ];
|
|
|
|
|
|
- handleElement( buffer, header.elements[ currentElement ].name, element );
|
|
|
+ handleElement( buffer, elementDesc.name, element, attributeMap );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -589,6 +605,40 @@ class PLYLoader extends Loader {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function extractHeaderText( bytes ) {
|
|
|
+
|
|
|
+ let i = 0;
|
|
|
+ let cont = true;
|
|
|
+
|
|
|
+ let line = '';
|
|
|
+ const lines = [];
|
|
|
+
|
|
|
+ do {
|
|
|
+
|
|
|
+ const c = String.fromCharCode( bytes[ i++ ] );
|
|
|
+
|
|
|
+ if ( c !== "\n" && c !== "\r" ) {
|
|
|
+
|
|
|
+ line += c;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ if ( line === 'end_header' ) cont = false;
|
|
|
+ if ( line !== '' ) {
|
|
|
+
|
|
|
+ lines.push( line );
|
|
|
+ line = '';
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } while ( cont && i < bytes.length );
|
|
|
+
|
|
|
+ return lines.join( "\r" ) + "\r";
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
//
|
|
|
|
|
|
let geometry;
|
|
@@ -596,10 +646,21 @@ class PLYLoader extends Loader {
|
|
|
|
|
|
if ( data instanceof ArrayBuffer ) {
|
|
|
|
|
|
- const text = LoaderUtils.decodeText( new Uint8Array( data ) );
|
|
|
- const header = parseHeader( text );
|
|
|
+ const bytes = new Uint8Array( data );
|
|
|
+ const headerText = extractHeaderText( bytes );
|
|
|
+ const header = parseHeader( headerText );
|
|
|
+
|
|
|
+ if ( header.format === 'ascii' ) {
|
|
|
+
|
|
|
+ const text = LoaderUtils.decodeText( bytes );
|
|
|
+
|
|
|
+ geometry = parseASCII( text, header );
|
|
|
|
|
|
- geometry = header.format === 'ascii' ? parseASCII( text, header ) : parseBinary( data, header );
|
|
|
+ } else {
|
|
|
+
|
|
|
+ geometry = parseBinary( data, header );
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
} else {
|
|
|
|