|
@@ -103,7 +103,7 @@ THREE.CTMLoader.prototype.load = function( url, callback, parameters ) {
|
|
|
|
|
|
var binaryData = xhr.responseText;
|
|
|
|
|
|
- //var s = Date.now();
|
|
|
+ var s = Date.now();
|
|
|
|
|
|
if ( parameters.useWorker ) {
|
|
|
|
|
@@ -117,6 +117,9 @@ THREE.CTMLoader.prototype.load = function( url, callback, parameters ) {
|
|
|
|
|
|
var ctmFile = files[ i ];
|
|
|
|
|
|
+ var e1 = Date.now();
|
|
|
+ // console.log( "CTM data parse time [worker]: " + (e1-s) + " ms" );
|
|
|
+
|
|
|
if ( useBuffers ) {
|
|
|
|
|
|
scope.createModelBuffers( ctmFile, callback );
|
|
@@ -127,10 +130,11 @@ THREE.CTMLoader.prototype.load = function( url, callback, parameters ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ var e = Date.now();
|
|
|
+ console.log( "model load time [worker]: " + (e-e1) + " ms, total: " + (e-s));
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- //var e = Date.now();
|
|
|
- //console.log( "CTM data parse time [worker]: " + (e-s) + " ms" );
|
|
|
|
|
|
};
|
|
|
|
|
@@ -209,6 +213,7 @@ THREE.CTMLoader.prototype.createModelBuffers = function ( file, callback ) {
|
|
|
|
|
|
THREE.BufferGeometry.call( this );
|
|
|
|
|
|
+ var s = Date.now();
|
|
|
// init GL buffers
|
|
|
|
|
|
var vertexIndexArray = file.body.indices,
|
|
@@ -218,98 +223,131 @@ THREE.CTMLoader.prototype.createModelBuffers = function ( file, callback ) {
|
|
|
var vertexUvArray, vertexColorArray;
|
|
|
|
|
|
if ( file.body.uvMaps !== undefined && file.body.uvMaps.length > 0 ) {
|
|
|
-
|
|
|
vertexUvArray = file.body.uvMaps[ 0 ].uv;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
if ( file.body.attrMaps !== undefined && file.body.attrMaps.length > 0 && file.body.attrMaps[ 0 ].name === "Color" ) {
|
|
|
-
|
|
|
vertexColorArray = file.body.attrMaps[ 0 ].attr;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
// reorder vertices
|
|
|
// (needed for buffer splitting, to keep together face vertices)
|
|
|
-
|
|
|
if ( reorderVertices ) {
|
|
|
|
|
|
- var newFaces = new Uint32Array( vertexIndexArray.length ),
|
|
|
- newVertices = new Float32Array( vertexPositionArray.length );
|
|
|
-
|
|
|
- var newNormals, newUvs, newColors;
|
|
|
-
|
|
|
- if ( vertexNormalArray ) newNormals = new Float32Array( vertexNormalArray.length );
|
|
|
- if ( vertexUvArray ) newUvs = new Float32Array( vertexUvArray.length );
|
|
|
- if ( vertexColorArray ) newColors = new Float32Array( vertexColorArray.length );
|
|
|
-
|
|
|
- var indexMap = {}, vertexCounter = 0;
|
|
|
-
|
|
|
- function handleVertex( v ) {
|
|
|
+ function copyVertexInfo(v, vt) {
|
|
|
|
|
|
- if ( indexMap[ v ] === undefined ) {
|
|
|
+ var sx = v * 3,
|
|
|
+ sy = v * 3 + 1,
|
|
|
+ sz = v * 3 + 2,
|
|
|
|
|
|
- indexMap[ v ] = vertexCounter;
|
|
|
+ dx = vt * 3,
|
|
|
+ dy = vt * 3 + 1,
|
|
|
+ dz = vt * 3 + 2;
|
|
|
|
|
|
- var sx = v * 3,
|
|
|
- sy = v * 3 + 1,
|
|
|
- sz = v * 3 + 2,
|
|
|
+ newVertices[ dx ] = vertexPositionArray[ sx ];
|
|
|
+ newVertices[ dy ] = vertexPositionArray[ sy ];
|
|
|
+ newVertices[ dz ] = vertexPositionArray[ sz ];
|
|
|
|
|
|
- dx = vertexCounter * 3,
|
|
|
- dy = vertexCounter * 3 + 1,
|
|
|
- dz = vertexCounter * 3 + 2;
|
|
|
+ if ( vertexNormalArray ) {
|
|
|
+ newNormals[ dx ] = vertexNormalArray[ sx ];
|
|
|
+ newNormals[ dy ] = vertexNormalArray[ sy ];
|
|
|
+ newNormals[ dz ] = vertexNormalArray[ sz ];
|
|
|
+ }
|
|
|
|
|
|
- newVertices[ dx ] = vertexPositionArray[ sx ];
|
|
|
- newVertices[ dy ] = vertexPositionArray[ sy ];
|
|
|
- newVertices[ dz ] = vertexPositionArray[ sz ];
|
|
|
+ if ( vertexUvArray ) {
|
|
|
+ newUvs[ vt * 2 ] = vertexUvArray[ v * 2 ];
|
|
|
+ newUvs[ vt * 2 + 1 ] = vertexUvArray[ v * 2 + 1 ];
|
|
|
+ }
|
|
|
|
|
|
- if ( vertexNormalArray ) {
|
|
|
+ if ( vertexColorArray ) {
|
|
|
+ newColors[ vt * 4 ] = vertexColorArray[ v * 4 ];
|
|
|
+ newColors[ vt * 4 + 1 ] = vertexColorArray[ v * 4 + 1 ];
|
|
|
+ newColors[ vt * 4 + 2 ] = vertexColorArray[ v * 4 + 2 ];
|
|
|
+ newColors[ vt * 4 + 3 ] = vertexColorArray[ v * 4 + 3 ];
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- newNormals[ dx ] = vertexNormalArray[ sx ];
|
|
|
- newNormals[ dy ] = vertexNormalArray[ sy ];
|
|
|
- newNormals[ dz ] = vertexNormalArray[ sz ];
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( vertexUvArray ) {
|
|
|
-
|
|
|
- newUvs[ vertexCounter * 2 ] = vertexUvArray[ v * 2 ];
|
|
|
- newUvs[ vertexCounter * 2 + 1 ] = vertexUvArray[ v * 2 + 1 ];
|
|
|
-
|
|
|
- }
|
|
|
+ function handleVertex( v, iMap ) {
|
|
|
|
|
|
- if ( vertexColorArray ) {
|
|
|
+ if ( iMap[ v ] === undefined ) {
|
|
|
|
|
|
- newColors[ vertexCounter * 4 ] = vertexColorArray[ v * 4 ];
|
|
|
- newColors[ vertexCounter * 4 + 1 ] = vertexColorArray[ v * 4 + 1 ];
|
|
|
- newColors[ vertexCounter * 4 + 2 ] = vertexColorArray[ v * 4 + 2 ];
|
|
|
- newColors[ vertexCounter * 4 + 3 ] = vertexColorArray[ v * 4 + 3 ];
|
|
|
+ iMap[ v ] = vertexCounter;
|
|
|
+ reverseIndexMap[vertexCounter] = v;
|
|
|
+ vertexCounter += 1;
|
|
|
+ }
|
|
|
+ return iMap[ v ];
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ var newFaces = new Uint32Array( vertexIndexArray.length );
|
|
|
+ var indexMap = {}, reverseIndexMap = {}, vertexCounter = 0;
|
|
|
|
|
|
- vertexCounter += 1;
|
|
|
+ // in most Reality Capture models < 1% of faces**2 are sprawled, for complex CAD/CAM > 2%
|
|
|
+ var spawledFaceCount = 0,
|
|
|
+ spawledFaceLimit = Math.ceil(vertexIndexArray.length/3000);
|
|
|
+ var sprawledFaces = new Uint32Array( spawledFaceLimit ); // to store sprawled triangle indices
|
|
|
|
|
|
- }
|
|
|
+ for ( var i = 0; i < vertexIndexArray.length; i += 3 ) {
|
|
|
|
|
|
+ var a = vertexIndexArray[ i ];
|
|
|
+ var b = vertexIndexArray[ i + 1 ];
|
|
|
+ var c = vertexIndexArray[ i + 2 ];
|
|
|
+
|
|
|
+ handleVertex( a, indexMap );
|
|
|
+ handleVertex( b, indexMap );
|
|
|
+ handleVertex( c, indexMap );
|
|
|
+
|
|
|
+ // check for sprawled triangles and put them aside to recreate later
|
|
|
+ if ( Math.abs( indexMap[a] - indexMap[b] ) > 65535 ||
|
|
|
+ Math.abs( indexMap[b] - indexMap[c] ) > 65535 ||
|
|
|
+ Math.abs( indexMap[c] - indexMap[a] ) > 65535 ){
|
|
|
+
|
|
|
+ // expand storage when neccessary
|
|
|
+ if (spawledFaceCount >= spawledFaceLimit) {
|
|
|
+ console.warn("reached sprawled faces limit: " + spawledFaceCount);
|
|
|
+ spawledFaceLimit *= 2;
|
|
|
+ var tArr = new Uint32Array( spawledFaceLimit );
|
|
|
+ tArr.set(sprawledFaces);
|
|
|
+ sprawledFaces = tArr;
|
|
|
+ }
|
|
|
+
|
|
|
+ sprawledFaces[ spawledFaceCount ] = i; // starting index in newFaces
|
|
|
+ spawledFaceCount += 1;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+
|
|
|
+ newFaces[ i ] = indexMap[ a ];
|
|
|
+ newFaces[ i + 1 ] = indexMap[ b ];
|
|
|
+ newFaces[ i + 2 ] = indexMap[ c ];
|
|
|
+ }
|
|
|
}
|
|
|
+ console.log("Number of sprawled faces: " + spawledFaceCount + " current limit: " + spawledFaceLimit +
|
|
|
+ " total: " + vertexIndexArray.length/3 + " vertices: " + vertexCounter);
|
|
|
|
|
|
- var a, b, c;
|
|
|
+ // create dublicate vertices and update sprawled faces
|
|
|
+ var indexMap2 = {},
|
|
|
+ noov = vertexCounter; // # of original vertices
|
|
|
|
|
|
- for ( var i = 0; i < vertexIndexArray.length; i += 3 ) {
|
|
|
+ for (var isf = 0; isf < spawledFaceCount; isf++ ) {
|
|
|
+ var i = sprawledFaces[isf];
|
|
|
|
|
|
- a = vertexIndexArray[ i ];
|
|
|
- b = vertexIndexArray[ i + 1 ];
|
|
|
- c = vertexIndexArray[ i + 2 ];
|
|
|
+ for (var j = 0; j < 3; j++) {
|
|
|
+ var v = vertexIndexArray[ i + j ];
|
|
|
+ newFaces[ i + j] = handleVertex(v, indexMap2); // new vertex
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // console.log("Created duplicated vertices: " + (vertexCounter - noov));
|
|
|
|
|
|
- handleVertex( a );
|
|
|
- handleVertex( b );
|
|
|
- handleVertex( c );
|
|
|
+ // copy xyz, uv, normals and colors into new arrays
|
|
|
+ var newVertices = new Float32Array( 3*vertexCounter );
|
|
|
+ var newNormals, newUvs, newColors;
|
|
|
|
|
|
- newFaces[ i ] = indexMap[ a ];
|
|
|
- newFaces[ i + 1 ] = indexMap[ b ];
|
|
|
- newFaces[ i + 2 ] = indexMap[ c ];
|
|
|
+ if ( vertexNormalArray ) newNormals = new Float32Array( 3*vertexCounter );
|
|
|
+ if ( vertexUvArray ) newUvs = new Float32Array( 2*vertexCounter );
|
|
|
+ if ( vertexColorArray ) newColors = new Float32Array( 4*vertexCounter );
|
|
|
|
|
|
- }
|
|
|
+ for (var iv = 0; iv < vertexCounter; iv++) {
|
|
|
+ copyVertexInfo(reverseIndexMap[iv], iv);
|
|
|
+ }
|
|
|
|
|
|
vertexIndexArray = newFaces;
|
|
|
vertexPositionArray = newVertices;
|
|
@@ -317,7 +355,6 @@ THREE.CTMLoader.prototype.createModelBuffers = function ( file, callback ) {
|
|
|
if ( vertexNormalArray ) vertexNormalArray = newNormals;
|
|
|
if ( vertexUvArray ) vertexUvArray = newUvs;
|
|
|
if ( vertexColorArray ) vertexColorArray = newColors;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
// compute offsets
|
|
@@ -346,10 +383,10 @@ THREE.CTMLoader.prototype.createModelBuffers = function ( file, callback ) {
|
|
|
|
|
|
i -= 3;
|
|
|
|
|
|
- for ( var k = start; k < i; ++ k ) {
|
|
|
-
|
|
|
- indices[ k ] -= minPrev;
|
|
|
+ if ( minPrev > 0 ) {
|
|
|
|
|
|
+ for ( var k = start; k < i; ++ k )
|
|
|
+ indices[ k ] -= minPrev;
|
|
|
}
|
|
|
|
|
|
scope.offsets.push( { start: start, count: i - start, index: minPrev } );
|
|
@@ -364,20 +401,20 @@ THREE.CTMLoader.prototype.createModelBuffers = function ( file, callback ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
- for ( var k = start; k < i; ++ k ) {
|
|
|
-
|
|
|
- indices[ k ] -= minPrev;
|
|
|
+ if ( minPrev > 0 ) {
|
|
|
|
|
|
+ for ( var k = start; k < i; ++ k )
|
|
|
+ indices[ k ] -= minPrev;
|
|
|
}
|
|
|
-
|
|
|
scope.offsets.push( { start: start, count: i - start, index: minPrev } );
|
|
|
|
|
|
- // recast CTM 32-bit indices as 16-bit WebGL indices
|
|
|
+ var e = Date.now();
|
|
|
+ console.log( "Vetex reordering time: " + (e-s) + " ms" );
|
|
|
|
|
|
+ // recast CTM 32-bit indices as 16-bit WebGL indices
|
|
|
var vertexIndexArray16 = new Uint16Array( vertexIndexArray );
|
|
|
|
|
|
// attributes
|
|
|
-
|
|
|
var attributes = scope.attributes;
|
|
|
|
|
|
attributes[ "index" ] = { itemSize: 1, array: vertexIndexArray16, numItems: vertexIndexArray16.length };
|