Browse Source

Converted TessellateModifier to recursive and normalized API with SubdivisionModifier

Aki Rodic 4 years ago
parent
commit
d7c2335cbc

+ 13 - 3
examples/js/modifiers/SubdivisionModifier.js

@@ -20,7 +20,9 @@ THREE.SubdivisionModifier = function ( subdivisions ) {
 // Applies the "modify" pattern
 THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {
 
-	if ( geometry.isBufferGeometry ) {
+	var isBufferGeometry = geometry.isBufferGeometry;
+
+	if ( isBufferGeometry ) {
 
 		geometry = new THREE.Geometry().fromBufferGeometry( geometry );
 
@@ -30,7 +32,7 @@ THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {
 
 	}
 
-	geometry.mergeVertices();
+	geometry.mergeVertices( 6 );
 
 	var repeats = this.subdivisions;
 
@@ -43,7 +45,15 @@ THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {
 	geometry.computeFaceNormals();
 	geometry.computeVertexNormals();
 
-	return geometry;
+	if ( isBufferGeometry ) {
+
+		return new THREE.BufferGeometry().fromGeometry( geometry );
+
+	} else {
+
+		return geometry;
+
+	}
 
 };
 

+ 163 - 129
examples/js/modifiers/TessellateModifier.js

@@ -1,224 +1,248 @@
 /**
  * Break faces with edges longer than maxEdgeLength
- * - not recursive
  */
 
 THREE.TessellateModifier = function ( maxEdgeLength ) {
 
-	this.maxEdgeLength = maxEdgeLength;
+	this.maxEdgeLength = ( maxEdgeLength === undefined ) ? 0.1 : maxEdgeLength;
 
 };
 
+// Applies the "modify" pattern
 THREE.TessellateModifier.prototype.modify = function ( geometry ) {
 
-	var edge;
+	const isBufferGeometry = geometry.isBufferGeometry;
 
-	var faces = [];
-	var faceVertexUvs = [];
-	var maxEdgeLengthSquared = this.maxEdgeLength * this.maxEdgeLength;
+	if ( isBufferGeometry ) {
 
-	for ( var i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {
+		geometry = new THREE.Geometry().fromBufferGeometry( geometry );
 
-		faceVertexUvs[ i ] = [];
+	} else {
+
+		geometry = geometry.clone();
 
 	}
 
-	for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {
+	geometry.mergeVertices( 6 );
 
-		var face = geometry.faces[ i ];
+	let finalized = false;
+	const maxEdgeLengthSquared = this.maxEdgeLength * this.maxEdgeLength;
 
-		if ( face instanceof THREE.Face3 ) {
+	let edge;
 
-			var a = face.a;
-			var b = face.b;
-			var c = face.c;
+	while ( ! finalized ) {
 
-			var va = geometry.vertices[ a ];
-			var vb = geometry.vertices[ b ];
-			var vc = geometry.vertices[ c ];
+		const faces = [];
+		const faceVertexUvs = [];
 
-			var dab = va.distanceToSquared( vb );
-			var dbc = vb.distanceToSquared( vc );
-			var dac = va.distanceToSquared( vc );
+		finalized = true;
 
-			if ( dab > maxEdgeLengthSquared || dbc > maxEdgeLengthSquared || dac > maxEdgeLengthSquared ) {
+		for ( var i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {
 
-				var m = geometry.vertices.length;
+			faceVertexUvs[ i ] = [];
 
-				var triA = face.clone();
-				var triB = face.clone();
+		}
 
-				if ( dab >= dbc && dab >= dac ) {
+		for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {
 
-					var vm = va.clone();
-					vm.lerp( vb, 0.5 );
+			const face = geometry.faces[ i ];
 
-					triA.a = a;
-					triA.b = m;
-					triA.c = c;
+			if ( face instanceof THREE.Face3 ) {
 
-					triB.a = m;
-					triB.b = b;
-					triB.c = c;
+				const a = face.a;
+				const b = face.b;
+				const c = face.c;
 
-					if ( face.vertexNormals.length === 3 ) {
+				const va = geometry.vertices[ a ];
+				const vb = geometry.vertices[ b ];
+				const vc = geometry.vertices[ c ];
 
-						var vnm = face.vertexNormals[ 0 ].clone();
-						vnm.lerp( face.vertexNormals[ 1 ], 0.5 );
+				const dab = va.distanceToSquared( vb );
+				const dbc = vb.distanceToSquared( vc );
+				const dac = va.distanceToSquared( vc );
 
-						triA.vertexNormals[ 1 ].copy( vnm );
-						triB.vertexNormals[ 0 ].copy( vnm );
+				if ( dab > maxEdgeLengthSquared || dbc > maxEdgeLengthSquared || dac > maxEdgeLengthSquared ) {
 
-					}
+					finalized = false;
 
-					if ( face.vertexColors.length === 3 ) {
+					const m = geometry.vertices.length;
 
-						var vcm = face.vertexColors[ 0 ].clone();
-						vcm.lerp( face.vertexColors[ 1 ], 0.5 );
+					const triA = face.clone();
+					const triB = face.clone();
 
-						triA.vertexColors[ 1 ].copy( vcm );
-						triB.vertexColors[ 0 ].copy( vcm );
+					if ( dab >= dbc && dab >= dac ) {
 
-					}
+						var vm = va.clone();
+						vm.lerp( vb, 0.5 );
 
-					edge = 0;
+						triA.a = a;
+						triA.b = m;
+						triA.c = c;
 
-				} else if ( dbc >= dab && dbc >= dac ) {
+						triB.a = m;
+						triB.b = b;
+						triB.c = c;
 
-					var vm = vb.clone();
-					vm.lerp( vc, 0.5 );
+						if ( face.vertexNormals.length === 3 ) {
 
-					triA.a = a;
-					triA.b = b;
-					triA.c = m;
+							var vnm = face.vertexNormals[ 0 ].clone();
+							vnm.lerp( face.vertexNormals[ 1 ], 0.5 );
 
-					triB.a = m;
-					triB.b = c;
-					triB.c = a;
+							triA.vertexNormals[ 1 ].copy( vnm );
+							triB.vertexNormals[ 0 ].copy( vnm );
 
-					if ( face.vertexNormals.length === 3 ) {
+						}
 
-						var vnm = face.vertexNormals[ 1 ].clone();
-						vnm.lerp( face.vertexNormals[ 2 ], 0.5 );
+						if ( face.vertexColors.length === 3 ) {
 
-						triA.vertexNormals[ 2 ].copy( vnm );
+							var vcm = face.vertexColors[ 0 ].clone();
+							vcm.lerp( face.vertexColors[ 1 ], 0.5 );
 
-						triB.vertexNormals[ 0 ].copy( vnm );
-						triB.vertexNormals[ 1 ].copy( face.vertexNormals[ 2 ] );
-						triB.vertexNormals[ 2 ].copy( face.vertexNormals[ 0 ] );
+							triA.vertexColors[ 1 ].copy( vcm );
+							triB.vertexColors[ 0 ].copy( vcm );
 
-					}
+						}
 
-					if ( face.vertexColors.length === 3 ) {
+						edge = 0;
 
-						var vcm = face.vertexColors[ 1 ].clone();
-						vcm.lerp( face.vertexColors[ 2 ], 0.5 );
+					} else if ( dbc >= dab && dbc >= dac ) {
 
-						triA.vertexColors[ 2 ].copy( vcm );
+						var vm = vb.clone();
+						vm.lerp( vc, 0.5 );
 
-						triB.vertexColors[ 0 ].copy( vcm );
-						triB.vertexColors[ 1 ].copy( face.vertexColors[ 2 ] );
-						triB.vertexColors[ 2 ].copy( face.vertexColors[ 0 ] );
+						triA.a = a;
+						triA.b = b;
+						triA.c = m;
 
-					}
+						triB.a = m;
+						triB.b = c;
+						triB.c = a;
 
-					edge = 1;
+						if ( face.vertexNormals.length === 3 ) {
 
-				} else {
+							var vnm = face.vertexNormals[ 1 ].clone();
+							vnm.lerp( face.vertexNormals[ 2 ], 0.5 );
 
-					var vm = va.clone();
-					vm.lerp( vc, 0.5 );
+							triA.vertexNormals[ 2 ].copy( vnm );
 
-					triA.a = a;
-					triA.b = b;
-					triA.c = m;
+							triB.vertexNormals[ 0 ].copy( vnm );
+							triB.vertexNormals[ 1 ].copy( face.vertexNormals[ 2 ] );
+							triB.vertexNormals[ 2 ].copy( face.vertexNormals[ 0 ] );
 
-					triB.a = m;
-					triB.b = b;
-					triB.c = c;
+						}
 
-					if ( face.vertexNormals.length === 3 ) {
+						if ( face.vertexColors.length === 3 ) {
 
-						var vnm = face.vertexNormals[ 0 ].clone();
-						vnm.lerp( face.vertexNormals[ 2 ], 0.5 );
+							var vcm = face.vertexColors[ 1 ].clone();
+							vcm.lerp( face.vertexColors[ 2 ], 0.5 );
 
-						triA.vertexNormals[ 2 ].copy( vnm );
-						triB.vertexNormals[ 0 ].copy( vnm );
+							triA.vertexColors[ 2 ].copy( vcm );
 
-					}
+							triB.vertexColors[ 0 ].copy( vcm );
+							triB.vertexColors[ 1 ].copy( face.vertexColors[ 2 ] );
+							triB.vertexColors[ 2 ].copy( face.vertexColors[ 0 ] );
+
+						}
+
+						edge = 1;
+
+					} else {
 
-					if ( face.vertexColors.length === 3 ) {
+						var vm = va.clone();
+						vm.lerp( vc, 0.5 );
 
-						var vcm = face.vertexColors[ 0 ].clone();
-						vcm.lerp( face.vertexColors[ 2 ], 0.5 );
+						triA.a = a;
+						triA.b = b;
+						triA.c = m;
 
-						triA.vertexColors[ 2 ].copy( vcm );
-						triB.vertexColors[ 0 ].copy( vcm );
+						triB.a = m;
+						triB.b = b;
+						triB.c = c;
+
+						if ( face.vertexNormals.length === 3 ) {
+
+							var vnm = face.vertexNormals[ 0 ].clone();
+							vnm.lerp( face.vertexNormals[ 2 ], 0.5 );
+
+							triA.vertexNormals[ 2 ].copy( vnm );
+							triB.vertexNormals[ 0 ].copy( vnm );
+
+						}
+
+						if ( face.vertexColors.length === 3 ) {
+
+							var vcm = face.vertexColors[ 0 ].clone();
+							vcm.lerp( face.vertexColors[ 2 ], 0.5 );
+
+							triA.vertexColors[ 2 ].copy( vcm );
+							triB.vertexColors[ 0 ].copy( vcm );
+
+						}
+
+						edge = 2;
 
 					}
 
-					edge = 2;
+					faces.push( triA, triB );
+					geometry.vertices.push( vm );
 
-				}
+					for ( var j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
 
-				faces.push( triA, triB );
-				geometry.vertices.push( vm );
+						if ( geometry.faceVertexUvs[ j ].length ) {
 
-				for ( var j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
+							const uvs = geometry.faceVertexUvs[ j ][ i ];
 
-					if ( geometry.faceVertexUvs[ j ].length ) {
+							const uvA = uvs[ 0 ];
+							const uvB = uvs[ 1 ];
+							const uvC = uvs[ 2 ];
 
-						var uvs = geometry.faceVertexUvs[ j ][ i ];
+							// AB
 
-						var uvA = uvs[ 0 ];
-						var uvB = uvs[ 1 ];
-						var uvC = uvs[ 2 ];
+							if ( edge === 0 ) {
 
-						// AB
+								var uvM = uvA.clone();
+								uvM.lerp( uvB, 0.5 );
 
-						if ( edge === 0 ) {
+								var uvsTriA = [ uvA.clone(), uvM.clone(), uvC.clone() ];
+								var uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];
 
-							var uvM = uvA.clone();
-							uvM.lerp( uvB, 0.5 );
+								// BC
 
-							var uvsTriA = [ uvA.clone(), uvM.clone(), uvC.clone() ];
-							var uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];
+							} else if ( edge === 1 ) {
 
-							// BC
+								var uvM = uvB.clone();
+								uvM.lerp( uvC, 0.5 );
 
-						} else if ( edge === 1 ) {
+								var uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
+								var uvsTriB = [ uvM.clone(), uvC.clone(), uvA.clone() ];
 
-							var uvM = uvB.clone();
-							uvM.lerp( uvC, 0.5 );
+								// AC
 
-							var uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
-							var uvsTriB = [ uvM.clone(), uvC.clone(), uvA.clone() ];
+							} else {
 
-							// AC
+								var uvM = uvA.clone();
+								uvM.lerp( uvC, 0.5 );
 
-						} else {
+								var uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
+								var uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];
 
-							var uvM = uvA.clone();
-							uvM.lerp( uvC, 0.5 );
+							}
 
-							var uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
-							var uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];
+							faceVertexUvs[ j ].push( uvsTriA, uvsTriB );
 
 						}
 
-						faceVertexUvs[ j ].push( uvsTriA, uvsTriB );
-
 					}
 
-				}
+				} else {
 
-			} else {
+					faces.push( face );
 
-				faces.push( face );
+					for ( var j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
 
-				for ( var j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
+						faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );
 
-					faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );
+					}
 
 				}
 
@@ -226,9 +250,19 @@ THREE.TessellateModifier.prototype.modify = function ( geometry ) {
 
 		}
 
+		geometry.faces = faces;
+		geometry.faceVertexUvs = faceVertexUvs;
+
 	}
 
-	geometry.faces = faces;
-	geometry.faceVertexUvs = faceVertexUvs;
+	if ( isBufferGeometry ) {
+
+		return new THREE.BufferGeometry().fromGeometry(geometry);
+
+	} else {
+
+		return geometry;
+
+	}
 
 };

+ 1 - 1
examples/jsm/modifiers/SubdivisionModifier.d.ts

@@ -8,7 +8,7 @@ export class SubdivisionModifier {
 	constructor( subdivisions?: number );
 	subdivisions: number;
 
-	modify( geometry: BufferGeometry | Geometry ): Geometry;
+	modify( geometry: Geometry | BufferGeometry ): Geometry | BufferGeometry;
 	smooth( geometry: Geometry ): void;
 
 }

+ 14 - 3
examples/jsm/modifiers/SubdivisionModifier.js

@@ -1,4 +1,5 @@
 import {
+	BufferGeometry,
 	Face3,
 	Geometry,
 	Vector2,
@@ -27,7 +28,9 @@ var SubdivisionModifier = function ( subdivisions ) {
 // Applies the "modify" pattern
 SubdivisionModifier.prototype.modify = function ( geometry ) {
 
-	if ( geometry.isBufferGeometry ) {
+	var isBufferGeometry = geometry.isBufferGeometry;
+
+	if ( isBufferGeometry ) {
 
 		geometry = new Geometry().fromBufferGeometry( geometry );
 
@@ -37,7 +40,7 @@ SubdivisionModifier.prototype.modify = function ( geometry ) {
 
 	}
 
-	geometry.mergeVertices();
+	geometry.mergeVertices( 6 );
 
 	var repeats = this.subdivisions;
 
@@ -50,7 +53,15 @@ SubdivisionModifier.prototype.modify = function ( geometry ) {
 	geometry.computeFaceNormals();
 	geometry.computeVertexNormals();
 
-	return geometry;
+	if ( isBufferGeometry ) {
+
+		return new BufferGeometry().fromGeometry( geometry );
+
+	} else {
+
+		return geometry;
+
+	}
 
 };
 

+ 3 - 2
examples/jsm/modifiers/TessellateModifier.d.ts

@@ -1,5 +1,6 @@
 import {
-	Geometry
+	Geometry,
+	BufferGeometry
 } from '../../../src/Three';
 
 export class TessellateModifier {
@@ -7,6 +8,6 @@ export class TessellateModifier {
 	constructor( maxEdgeLength: number );
 	maxEdgeLength: number;
 
-	modify( geometry: Geometry ): void;
+	modify( geometry: Geometry | BufferGeometry ): Geometry | BufferGeometry;
 
 }

+ 166 - 130
examples/jsm/modifiers/TessellateModifier.js

@@ -1,228 +1,254 @@
 import {
-	Face3
+	BufferGeometry,
+	Face3,
+	Geometry
 } from "../../../build/three.module.js";
 
 /**
  * Break faces with edges longer than maxEdgeLength
- * - not recursive
  */
 
 var TessellateModifier = function ( maxEdgeLength ) {
 
-	this.maxEdgeLength = maxEdgeLength;
+	this.maxEdgeLength = ( maxEdgeLength === undefined ) ? 0.1 : maxEdgeLength;
 
 };
 
+// Applies the "modify" pattern
 TessellateModifier.prototype.modify = function ( geometry ) {
 
-	var edge;
+	const isBufferGeometry = geometry.isBufferGeometry;
 
-	var faces = [];
-	var faceVertexUvs = [];
-	var maxEdgeLengthSquared = this.maxEdgeLength * this.maxEdgeLength;
+	if ( isBufferGeometry ) {
 
-	for ( var i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {
+		geometry = new Geometry().fromBufferGeometry( geometry );
 
-		faceVertexUvs[ i ] = [];
+	} else {
+
+		geometry = geometry.clone();
 
 	}
 
-	for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {
+	geometry.mergeVertices( 6 );
 
-		var face = geometry.faces[ i ];
+	let finalized = false;
+	const maxEdgeLengthSquared = this.maxEdgeLength * this.maxEdgeLength;
 
-		if ( face instanceof Face3 ) {
+	let edge;
 
-			var a = face.a;
-			var b = face.b;
-			var c = face.c;
+	while ( ! finalized ) {
 
-			var va = geometry.vertices[ a ];
-			var vb = geometry.vertices[ b ];
-			var vc = geometry.vertices[ c ];
+		const faces = [];
+		const faceVertexUvs = [];
 
-			var dab = va.distanceToSquared( vb );
-			var dbc = vb.distanceToSquared( vc );
-			var dac = va.distanceToSquared( vc );
+		finalized = true;
 
-			if ( dab > maxEdgeLengthSquared || dbc > maxEdgeLengthSquared || dac > maxEdgeLengthSquared ) {
+		for ( var i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {
 
-				var m = geometry.vertices.length;
+			faceVertexUvs[ i ] = [];
 
-				var triA = face.clone();
-				var triB = face.clone();
+		}
 
-				if ( dab >= dbc && dab >= dac ) {
+		for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {
 
-					var vm = va.clone();
-					vm.lerp( vb, 0.5 );
+			const face = geometry.faces[ i ];
 
-					triA.a = a;
-					triA.b = m;
-					triA.c = c;
+			if ( face instanceof Face3 ) {
 
-					triB.a = m;
-					triB.b = b;
-					triB.c = c;
+				const a = face.a;
+				const b = face.b;
+				const c = face.c;
 
-					if ( face.vertexNormals.length === 3 ) {
+				const va = geometry.vertices[ a ];
+				const vb = geometry.vertices[ b ];
+				const vc = geometry.vertices[ c ];
 
-						var vnm = face.vertexNormals[ 0 ].clone();
-						vnm.lerp( face.vertexNormals[ 1 ], 0.5 );
+				const dab = va.distanceToSquared( vb );
+				const dbc = vb.distanceToSquared( vc );
+				const dac = va.distanceToSquared( vc );
 
-						triA.vertexNormals[ 1 ].copy( vnm );
-						triB.vertexNormals[ 0 ].copy( vnm );
+				if ( dab > maxEdgeLengthSquared || dbc > maxEdgeLengthSquared || dac > maxEdgeLengthSquared ) {
 
-					}
+					finalized = false;
 
-					if ( face.vertexColors.length === 3 ) {
+					const m = geometry.vertices.length;
 
-						var vcm = face.vertexColors[ 0 ].clone();
-						vcm.lerp( face.vertexColors[ 1 ], 0.5 );
+					const triA = face.clone();
+					const triB = face.clone();
 
-						triA.vertexColors[ 1 ].copy( vcm );
-						triB.vertexColors[ 0 ].copy( vcm );
+					if ( dab >= dbc && dab >= dac ) {
 
-					}
+						var vm = va.clone();
+						vm.lerp( vb, 0.5 );
 
-					edge = 0;
+						triA.a = a;
+						triA.b = m;
+						triA.c = c;
 
-				} else if ( dbc >= dab && dbc >= dac ) {
+						triB.a = m;
+						triB.b = b;
+						triB.c = c;
 
-					var vm = vb.clone();
-					vm.lerp( vc, 0.5 );
+						if ( face.vertexNormals.length === 3 ) {
 
-					triA.a = a;
-					triA.b = b;
-					triA.c = m;
+							var vnm = face.vertexNormals[ 0 ].clone();
+							vnm.lerp( face.vertexNormals[ 1 ], 0.5 );
 
-					triB.a = m;
-					triB.b = c;
-					triB.c = a;
+							triA.vertexNormals[ 1 ].copy( vnm );
+							triB.vertexNormals[ 0 ].copy( vnm );
 
-					if ( face.vertexNormals.length === 3 ) {
+						}
 
-						var vnm = face.vertexNormals[ 1 ].clone();
-						vnm.lerp( face.vertexNormals[ 2 ], 0.5 );
+						if ( face.vertexColors.length === 3 ) {
 
-						triA.vertexNormals[ 2 ].copy( vnm );
+							var vcm = face.vertexColors[ 0 ].clone();
+							vcm.lerp( face.vertexColors[ 1 ], 0.5 );
 
-						triB.vertexNormals[ 0 ].copy( vnm );
-						triB.vertexNormals[ 1 ].copy( face.vertexNormals[ 2 ] );
-						triB.vertexNormals[ 2 ].copy( face.vertexNormals[ 0 ] );
+							triA.vertexColors[ 1 ].copy( vcm );
+							triB.vertexColors[ 0 ].copy( vcm );
 
-					}
+						}
 
-					if ( face.vertexColors.length === 3 ) {
+						edge = 0;
 
-						var vcm = face.vertexColors[ 1 ].clone();
-						vcm.lerp( face.vertexColors[ 2 ], 0.5 );
+					} else if ( dbc >= dab && dbc >= dac ) {
 
-						triA.vertexColors[ 2 ].copy( vcm );
+						var vm = vb.clone();
+						vm.lerp( vc, 0.5 );
 
-						triB.vertexColors[ 0 ].copy( vcm );
-						triB.vertexColors[ 1 ].copy( face.vertexColors[ 2 ] );
-						triB.vertexColors[ 2 ].copy( face.vertexColors[ 0 ] );
+						triA.a = a;
+						triA.b = b;
+						triA.c = m;
 
-					}
+						triB.a = m;
+						triB.b = c;
+						triB.c = a;
 
-					edge = 1;
+						if ( face.vertexNormals.length === 3 ) {
 
-				} else {
+							var vnm = face.vertexNormals[ 1 ].clone();
+							vnm.lerp( face.vertexNormals[ 2 ], 0.5 );
 
-					var vm = va.clone();
-					vm.lerp( vc, 0.5 );
+							triA.vertexNormals[ 2 ].copy( vnm );
 
-					triA.a = a;
-					triA.b = b;
-					triA.c = m;
+							triB.vertexNormals[ 0 ].copy( vnm );
+							triB.vertexNormals[ 1 ].copy( face.vertexNormals[ 2 ] );
+							triB.vertexNormals[ 2 ].copy( face.vertexNormals[ 0 ] );
 
-					triB.a = m;
-					triB.b = b;
-					triB.c = c;
+						}
 
-					if ( face.vertexNormals.length === 3 ) {
+						if ( face.vertexColors.length === 3 ) {
 
-						var vnm = face.vertexNormals[ 0 ].clone();
-						vnm.lerp( face.vertexNormals[ 2 ], 0.5 );
+							var vcm = face.vertexColors[ 1 ].clone();
+							vcm.lerp( face.vertexColors[ 2 ], 0.5 );
 
-						triA.vertexNormals[ 2 ].copy( vnm );
-						triB.vertexNormals[ 0 ].copy( vnm );
+							triA.vertexColors[ 2 ].copy( vcm );
 
-					}
+							triB.vertexColors[ 0 ].copy( vcm );
+							triB.vertexColors[ 1 ].copy( face.vertexColors[ 2 ] );
+							triB.vertexColors[ 2 ].copy( face.vertexColors[ 0 ] );
+
+						}
+
+						edge = 1;
+
+					} else {
 
-					if ( face.vertexColors.length === 3 ) {
+						var vm = va.clone();
+						vm.lerp( vc, 0.5 );
 
-						var vcm = face.vertexColors[ 0 ].clone();
-						vcm.lerp( face.vertexColors[ 2 ], 0.5 );
+						triA.a = a;
+						triA.b = b;
+						triA.c = m;
 
-						triA.vertexColors[ 2 ].copy( vcm );
-						triB.vertexColors[ 0 ].copy( vcm );
+						triB.a = m;
+						triB.b = b;
+						triB.c = c;
+
+						if ( face.vertexNormals.length === 3 ) {
+
+							var vnm = face.vertexNormals[ 0 ].clone();
+							vnm.lerp( face.vertexNormals[ 2 ], 0.5 );
+
+							triA.vertexNormals[ 2 ].copy( vnm );
+							triB.vertexNormals[ 0 ].copy( vnm );
+
+						}
+
+						if ( face.vertexColors.length === 3 ) {
+
+							var vcm = face.vertexColors[ 0 ].clone();
+							vcm.lerp( face.vertexColors[ 2 ], 0.5 );
+
+							triA.vertexColors[ 2 ].copy( vcm );
+							triB.vertexColors[ 0 ].copy( vcm );
+
+						}
+
+						edge = 2;
 
 					}
 
-					edge = 2;
+					faces.push( triA, triB );
+					geometry.vertices.push( vm );
 
-				}
+					for ( var j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
 
-				faces.push( triA, triB );
-				geometry.vertices.push( vm );
+						if ( geometry.faceVertexUvs[ j ].length ) {
 
-				for ( var j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
+							const uvs = geometry.faceVertexUvs[ j ][ i ];
 
-					if ( geometry.faceVertexUvs[ j ].length ) {
+							const uvA = uvs[ 0 ];
+							const uvB = uvs[ 1 ];
+							const uvC = uvs[ 2 ];
 
-						var uvs = geometry.faceVertexUvs[ j ][ i ];
+							// AB
 
-						var uvA = uvs[ 0 ];
-						var uvB = uvs[ 1 ];
-						var uvC = uvs[ 2 ];
+							if ( edge === 0 ) {
 
-						// AB
+								var uvM = uvA.clone();
+								uvM.lerp( uvB, 0.5 );
 
-						if ( edge === 0 ) {
+								var uvsTriA = [ uvA.clone(), uvM.clone(), uvC.clone() ];
+								var uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];
 
-							var uvM = uvA.clone();
-							uvM.lerp( uvB, 0.5 );
+								// BC
 
-							var uvsTriA = [ uvA.clone(), uvM.clone(), uvC.clone() ];
-							var uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];
+							} else if ( edge === 1 ) {
 
-							// BC
+								var uvM = uvB.clone();
+								uvM.lerp( uvC, 0.5 );
 
-						} else if ( edge === 1 ) {
+								var uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
+								var uvsTriB = [ uvM.clone(), uvC.clone(), uvA.clone() ];
 
-							var uvM = uvB.clone();
-							uvM.lerp( uvC, 0.5 );
+								// AC
 
-							var uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
-							var uvsTriB = [ uvM.clone(), uvC.clone(), uvA.clone() ];
+							} else {
 
-							// AC
+								var uvM = uvA.clone();
+								uvM.lerp( uvC, 0.5 );
 
-						} else {
+								var uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
+								var uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];
 
-							var uvM = uvA.clone();
-							uvM.lerp( uvC, 0.5 );
+							}
 
-							var uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
-							var uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];
+							faceVertexUvs[ j ].push( uvsTriA, uvsTriB );
 
 						}
 
-						faceVertexUvs[ j ].push( uvsTriA, uvsTriB );
-
 					}
 
-				}
+				} else {
 
-			} else {
+					faces.push( face );
 
-				faces.push( face );
+					for ( var j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
 
-				for ( var j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
+						faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );
 
-					faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );
+					}
 
 				}
 
@@ -230,10 +256,20 @@ TessellateModifier.prototype.modify = function ( geometry ) {
 
 		}
 
+		geometry.faces = faces;
+		geometry.faceVertexUvs = faceVertexUvs;
+
 	}
 
-	geometry.faces = faces;
-	geometry.faceVertexUvs = faceVertexUvs;
+	if ( isBufferGeometry ) {
+
+		return new BufferGeometry().fromGeometry(geometry);
+
+	} else {
+
+		return geometry;
+
+	}
 
 };
 

+ 1 - 5
examples/webgl_modifier_tessellation.html

@@ -107,11 +107,7 @@
 
 				const tessellateModifier = new TessellateModifier( 8 );
 
-				for ( let i = 0; i < 6; i ++ ) {
-
-					tessellateModifier.modify( geometry );
-
-				}
+				geometry = tessellateModifier.modify( geometry );
 
 				//
 

+ 2 - 2
src/core/Geometry.d.ts

@@ -242,10 +242,10 @@ export class Geometry extends EventDispatcher {
 	mergeMesh( mesh: Mesh ): void;
 
 	/**
-	 * Checks for duplicate vertices using hashmap.
+	 * Checks for duplicate vertices using hashmap for specified number of decimal points, e.g. 4 for epsilon of 0.0001
 	 * Duplicated vertices are removed and faces' vertices are updated.
 	 */
-	mergeVertices(): number;
+	mergeVertices( precisionPoints: number ): number;
 
 	setFromPoints( points: Array<Vector2> | Array<Vector3> ): this;
 

+ 2 - 2
src/core/Geometry.js

@@ -769,12 +769,12 @@ Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 	 * and faces' vertices are updated.
 	 */
 
-	mergeVertices: function () {
+	mergeVertices: function ( precisionPoints ) {
 
 		const verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)
 		const unique = [], changes = [];
 
-		const precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001
+		precisionPoints = precisionPoints || 4;
 		const precision = Math.pow( 10, precisionPoints );
 
 		for ( let i = 0, il = this.vertices.length; i < il; i ++ ) {