Pārlūkot izejas kodu

Introduce computeOffsets() and reorderBuffers() to BufferGeometry.

computeOffsets() - Reorder the geometry index buffer and attributes so that all indices are referencing a maximum
reorderBuffers() - Reorder and grow the vertex attributes to adhere to a new index map.
Ref: #3524
Benoit Beausejour 11 gadi atpakaļ
vecāks
revīzija
4462235bb3
1 mainītis faili ar 166 papildinājumiem un 6 dzēšanām
  1. 166 6
      src/core/BufferGeometry.js

+ 166 - 6
src/core/BufferGeometry.js

@@ -273,15 +273,15 @@ THREE.BufferGeometry.prototype = {
 						ab.subVectors( pA, pB );
 						ab.subVectors( pA, pB );
 						cb.cross( ab );
 						cb.cross( ab );
 
 
-						normals[ vA * 3 ]     += cb.x;
+						normals[ vA * 3 ]			+= cb.x;
 						normals[ vA * 3 + 1 ] += cb.y;
 						normals[ vA * 3 + 1 ] += cb.y;
 						normals[ vA * 3 + 2 ] += cb.z;
 						normals[ vA * 3 + 2 ] += cb.z;
 
 
-						normals[ vB * 3 ]     += cb.x;
+						normals[ vB * 3 ]			+= cb.x;
 						normals[ vB * 3 + 1 ] += cb.y;
 						normals[ vB * 3 + 1 ] += cb.y;
 						normals[ vB * 3 + 2 ] += cb.z;
 						normals[ vB * 3 + 2 ] += cb.z;
 
 
-						normals[ vC * 3 ]     += cb.x;
+						normals[ vC * 3 ]			+= cb.x;
 						normals[ vC * 3 + 1 ] += cb.y;
 						normals[ vC * 3 + 1 ] += cb.y;
 						normals[ vC * 3 + 2 ] += cb.z;
 						normals[ vC * 3 + 2 ] += cb.z;
 
 
@@ -314,7 +314,7 @@ THREE.BufferGeometry.prototype = {
 					ab.subVectors( pA, pB );
 					ab.subVectors( pA, pB );
 					cb.cross( ab );
 					cb.cross( ab );
 
 
-					normals[ i ] 	 = cb.x;
+					normals[ i ]	 = cb.x;
 					normals[ i + 1 ] = cb.y;
 					normals[ i + 1 ] = cb.y;
 					normals[ i + 2 ] = cb.z;
 					normals[ i + 2 ] = cb.z;
 
 
@@ -352,7 +352,7 @@ THREE.BufferGeometry.prototype = {
 
 
 			n = 1.0 / Math.sqrt( x * x + y * y + z * z );
 			n = 1.0 / Math.sqrt( x * x + y * y + z * z );
 
 
-			normals[ i ] 	 *= n;
+			normals[ i ]	 *= n;
 			normals[ i + 1 ] *= n;
 			normals[ i + 1 ] *= n;
 			normals[ i + 2 ] *= n;
 			normals[ i + 2 ] *= n;
 
 
@@ -530,7 +530,7 @@ THREE.BufferGeometry.prototype = {
 			test = tmp2.dot( tan2[ v ] );
 			test = tmp2.dot( tan2[ v ] );
 			w = ( test < 0.0 ) ? -1.0 : 1.0;
 			w = ( test < 0.0 ) ? -1.0 : 1.0;
 
 
-			tangents[ v * 4 ]     = tmp.x;
+			tangents[ v * 4 ]			= tmp.x;
 			tangents[ v * 4 + 1 ] = tmp.y;
 			tangents[ v * 4 + 1 ] = tmp.y;
 			tangents[ v * 4 + 2 ] = tmp.z;
 			tangents[ v * 4 + 2 ] = tmp.z;
 			tangents[ v * 4 + 3 ] = w;
 			tangents[ v * 4 + 3 ] = w;
@@ -562,6 +562,166 @@ THREE.BufferGeometry.prototype = {
 
 
 	},
 	},
 
 
+	/*
+		computeOffsets
+		Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.
+		This method will effectively rewrite the index buffer and remap all attributes to match the new indices.
+		WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.
+		indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks.
+	*/
+	computeOffsets: function(indexBufferSize) {
+
+		var size = indexBufferSize;
+		if(indexBufferSize === undefined)
+			size = 65535; //WebGL limits type of index buffer values to 16-bit.
+
+		var s = Date.now();
+
+		var indices = this.attributes['index'].array;
+		var vertices = this.attributes['position'].array;
+
+		var verticesCount = (vertices.length/3);
+		var facesCount = (indices.length/3);
+
+		/*
+		console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length);
+		console.log("Faces to process: "+(indices.length/3));
+		console.log("Reordering "+verticesCount+" vertices.");
+		*/
+
+		var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers
+		var indexPtr = 0;
+		var vertexPtr = 0;
+
+		var offsets = [ { start:0, count:0, index:0 } ];
+		var offset = offsets[0];
+
+		var duplicatedVertices = 0;
+		var newVerticeMaps = 0;
+		var faceVertices = new Int32Array(6);
+		var vertexMap = new Int32Array( vertices.length );
+		var revVertexMap = new Int32Array( vertices.length );
+		for(var j = 0; j < vertices.length; j++) { vertexMap[j] = -1; revVertexMap[j] = -1; }
+
+		/*
+			Traverse every face and reorder vertices in the proper offsets of 65k.
+			We can have more than 65k entries in the index buffer per offset, but only reference 65k values.
+		*/
+		for(var findex = 0; findex < facesCount; findex++) {
+			newVerticeMaps = 0;
+
+			for(var vo = 0; vo < 3; vo++) {
+				var vid = indices[ findex*3 + vo ];
+				if(vertexMap[vid] == -1) {
+					//Unmapped vertice
+					faceVertices[vo*2] = vid;
+					faceVertices[vo*2+1] = -1;
+					newVerticeMaps++;
+				} else if(vertexMap[vid] < offset.index) {
+					//Reused vertices from previous block (duplicate)
+					faceVertices[vo*2] = vid;
+					faceVertices[vo*2+1] = -1;
+					duplicatedVertices++;
+				} else {
+					//Reused vertice in the current block
+					faceVertices[vo*2] = vid;
+					faceVertices[vo*2+1] = vertexMap[vid];
+				}
+			}
+
+			var faceMax = vertexPtr + newVerticeMaps;
+			if(faceMax > (offset.index + size)) {
+				var new_offset = { start:indexPtr, count:0, index:vertexPtr };
+				offsets.push(new_offset);
+				offset = new_offset;
+
+				//Re-evaluate reused vertices in light of new offset.
+				for(var v = 0; v < 6; v+=2) {
+					var new_vid = faceVertices[v+1];
+					if(new_vid > -1 && new_vid < offset.index)
+						faceVertices[v+1] = -1;
+				}
+			}
+
+			//Reindex the face.
+			for(var v = 0; v < 6; v+=2) {
+				var vid = faceVertices[v];
+				var new_vid = faceVertices[v+1];
+
+				if(new_vid === -1)
+					new_vid = vertexPtr++;
+
+				vertexMap[vid] = new_vid;
+				revVertexMap[new_vid] = vid;
+				sortedIndices[indexPtr++] = new_vid - offset.index; //XXX overflows at 16bit
+				offset.count++;
+			}
+		}
+
+		/* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
+		this.reorderBuffers(sortedIndices, revVertexMap, vertexPtr);
+		this.offsets = offsets;
+
+		/*
+		var orderTime = Date.now();
+		console.log("Reorder time: "+(orderTime-s)+"ms");
+		console.log("Duplicated "+duplicatedVertices+" vertices.");
+		console.log("Compute Buffers time: "+(Date.now()-s)+"ms");
+		console.log("Draw offsets: "+offsets.length);
+		*/
+
+		return offsets;
+	},
+
+	/*
+		reoderBuffers:
+		Reorder attributes based on a new indexBuffer and indexMap.
+		indexBuffer - Uint16Array of the new ordered indices.
+		indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.
+		vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).
+	*/
+	reorderBuffers: function(indexBuffer, indexMap, vertexCount) {
+
+		/* Create a copy of all attributes for reordering. */
+		var sortedAttributes = {};
+		var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ];
+		for( var attr in this.attributes ) {
+			if(attr == 'index')
+				continue;
+			var sourceArray = this.attributes[attr].array;
+			for ( var i = 0, il = types.length; i < il; i++ ) {
+				var type = types[i];
+				if (sourceArray instanceof type) {
+					sortedAttributes[attr] = new type( this.attributes[attr].itemSize * vertexCount );
+					break;
+				}
+			}
+		}
+
+		/* Move attribute positions based on the new index map */
+		for(var new_vid = 0; new_vid < vertexCount; new_vid++) {
+			var vid = indexMap[new_vid];
+			for ( var attr in this.attributes ) {
+				if(attr == 'index')
+					continue;
+				var attrArray = this.attributes[attr].array;
+				var attrSize = this.attributes[attr].itemSize;
+				var sortedAttr = sortedAttributes[attr];
+				for(var k = 0; k < attrSize; k++)
+					sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
+			}
+		}
+
+		/* Carry the new sorted buffers locally */
+		this.attributes['index'].array = indexBuffer;
+		for ( var attr in this.attributes ) {
+			if(attr == 'index')
+				continue;
+			this.attributes[attr].array = sortedAttributes[attr];
+			this.attributes[attr].numItems = this.attributes[attr].itemSize * vertexCount;
+		}
+	},
+
 	clone: function () {
 	clone: function () {
 
 
 		var geometry = new THREE.BufferGeometry();
 		var geometry = new THREE.BufferGeometry();