topical media & game development
mobile-query-three-vendor-three.js-modifiers-TessellateModifier.js / js
Break faces with edges longer than maxEdgeLength
- not recursive
author: alteredq / alteredqualia.com/
THREE.TessellateModifier = function ( maxEdgeLength ) {
this.maxEdgeLength = maxEdgeLength;
};
THREE.TessellateModifier.prototype.modify = function ( geometry ) {
var i, il, face,
a, b, c, d,
va, vb, vc, vd,
dab, dbc, dac, dcd, dad,
m, m1, m2,
vm, vm1, vm2,
vnm, vnm1, vnm2,
vcm, vcm1, vcm2,
triA, triB,
quadA, quadB,
edge;
var faces = [];
var faceVertexUvs = [];
var maxEdgeLength = this.maxEdgeLength;
for ( i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {
faceVertexUvs[ i ] = [];
}
for ( i = 0, il = geometry.faces.length; i < il; i ++ ) {
face = geometry.faces[ i ];
if ( face instanceof THREE.Face3 ) {
a = face.a;
b = face.b;
c = face.c;
va = geometry.vertices[ a ];
vb = geometry.vertices[ b ];
vc = geometry.vertices[ c ];
dab = va.distanceTo( vb );
dbc = vb.distanceTo( vc );
dac = va.distanceTo( vc );
if ( dab > maxEdgeLength || dbc > maxEdgeLength || dac > maxEdgeLength ) {
m = geometry.vertices.length;
triA = face.clone();
triB = face.clone();
if ( dab >= dbc && dab >= dac ) {
vm = va.clone();
vm.lerp( vb, 0.5 );
triA.a = a;
triA.b = m;
triA.c = c;
triB.a = m;
triB.b = b;
triB.c = c;
if ( face.vertexNormals.length === 3 ) {
vnm = face.vertexNormals[ 0 ].clone();
vnm.lerp( face.vertexNormals[ 1 ], 0.5 );
triA.vertexNormals[ 1 ].copy( vnm );
triB.vertexNormals[ 0 ].copy( vnm );
}
if ( face.vertexColors.length === 3 ) {
vcm = face.vertexColors[ 0 ].clone();
vcm.lerp( face.vertexColors[ 1 ], 0.5 );
triA.vertexColors[ 1 ].copy( vcm );
triB.vertexColors[ 0 ].copy( vcm );
}
edge = 0;
} else if ( dbc >= dab && dbc >= dac ) {
vm = vb.clone();
vm.lerp( vc, 0.5 );
triA.a = a;
triA.b = b;
triA.c = m;
triB.a = m;
triB.b = c;
triB.c = a;
if ( face.vertexNormals.length === 3 ) {
vnm = face.vertexNormals[ 1 ].clone();
vnm.lerp( face.vertexNormals[ 2 ], 0.5 );
triA.vertexNormals[ 2 ].copy( vnm );
triB.vertexNormals[ 0 ].copy( vnm );
triB.vertexNormals[ 1 ].copy( face.vertexNormals[ 2 ] );
triB.vertexNormals[ 2 ].copy( face.vertexNormals[ 0 ] );
}
if ( face.vertexColors.length === 3 ) {
vcm = face.vertexColors[ 1 ].clone();
vcm.lerp( face.vertexColors[ 2 ], 0.5 );
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 {
vm = va.clone();
vm.lerp( vc, 0.5 );
triA.a = a;
triA.b = b;
triA.c = m;
triB.a = m;
triB.b = b;
triB.c = c;
if ( face.vertexNormals.length === 3 ) {
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 ) {
vcm = face.vertexColors[ 0 ].clone();
vcm.lerp( face.vertexColors[ 2 ], 0.5 );
triA.vertexColors[ 2 ].copy( vcm );
triB.vertexColors[ 0 ].copy( vcm );
}
edge = 2;
}
faces.push( triA, triB );
geometry.vertices.push( vm );
var j, jl, uvs, uvA, uvB, uvC, uvM, uvsTriA, uvsTriB;
for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
if ( geometry.faceVertexUvs[ j ].length ) {
uvs = geometry.faceVertexUvs[ j ][ i ];
uvA = uvs[ 0 ];
uvB = uvs[ 1 ];
uvC = uvs[ 2 ];
// AB
if ( edge === 0 ) {
uvM = uvA.clone();
uvM.lerp( uvB, 0.5 );
uvsTriA = [ uvA.clone(), uvM.clone(), uvC.clone() ];
uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];
// BC
} else if ( edge === 1 ) {
uvM = uvB.clone();
uvM.lerp( uvC, 0.5 );
uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
uvsTriB = [ uvM.clone(), uvC.clone(), uvA.clone() ];
// AC
} else {
uvM = uvA.clone();
uvM.lerp( uvC, 0.5 );
uvsTriA = [ uvA.clone(), uvB.clone(), uvM.clone() ];
uvsTriB = [ uvM.clone(), uvB.clone(), uvC.clone() ];
}
faceVertexUvs[ j ].push( uvsTriA, uvsTriB );
}
}
} else {
faces.push( face );
for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );
}
}
} else {
a = face.a;
b = face.b;
c = face.c;
d = face.d;
va = geometry.vertices[ a ];
vb = geometry.vertices[ b ];
vc = geometry.vertices[ c ];
vd = geometry.vertices[ d ];
dab = va.distanceTo( vb );
dbc = vb.distanceTo( vc );
dcd = vc.distanceTo( vd );
dad = va.distanceTo( vd );
if ( dab > maxEdgeLength || dbc > maxEdgeLength || dcd > maxEdgeLength || dad > maxEdgeLength ) {
m1 = geometry.vertices.length;
m2 = geometry.vertices.length + 1;
quadA = face.clone();
quadB = face.clone();
if ( ( dab >= dbc && dab >= dcd && dab >= dad ) || ( dcd >= dbc && dcd >= dab && dcd >= dad ) ) {
vm1 = va.clone();
vm1.lerp( vb, 0.5 );
vm2 = vc.clone();
vm2.lerp( vd, 0.5 );
quadA.a = a;
quadA.b = m1;
quadA.c = m2;
quadA.d = d;
quadB.a = m1;
quadB.b = b;
quadB.c = c;
quadB.d = m2;
if ( face.vertexNormals.length === 4 ) {
vnm1 = face.vertexNormals[ 0 ].clone();
vnm1.lerp( face.vertexNormals[ 1 ], 0.5 );
vnm2 = face.vertexNormals[ 2 ].clone();
vnm2.lerp( face.vertexNormals[ 3 ], 0.5 );
quadA.vertexNormals[ 1 ].copy( vnm1 );
quadA.vertexNormals[ 2 ].copy( vnm2 );
quadB.vertexNormals[ 0 ].copy( vnm1 );
quadB.vertexNormals[ 3 ].copy( vnm2 );
}
if ( face.vertexColors.length === 4 ) {
vcm1 = face.vertexColors[ 0 ].clone();
vcm1.lerp( face.vertexColors[ 1 ], 0.5 );
vcm2 = face.vertexColors[ 2 ].clone();
vcm2.lerp( face.vertexColors[ 3 ], 0.5 );
quadA.vertexColors[ 1 ].copy( vcm1 );
quadA.vertexColors[ 2 ].copy( vcm2 );
quadB.vertexColors[ 0 ].copy( vcm1 );
quadB.vertexColors[ 3 ].copy( vcm2 );
}
edge = 0;
} else {
vm1 = vb.clone();
vm1.lerp( vc, 0.5 );
vm2 = vd.clone();
vm2.lerp( va, 0.5 );
quadA.a = a;
quadA.b = b;
quadA.c = m1;
quadA.d = m2;
quadB.a = m2;
quadB.b = m1;
quadB.c = c;
quadB.d = d;
if ( face.vertexNormals.length === 4 ) {
vnm1 = face.vertexNormals[ 1 ].clone();
vnm1.lerp( face.vertexNormals[ 2 ], 0.5 );
vnm2 = face.vertexNormals[ 3 ].clone();
vnm2.lerp( face.vertexNormals[ 0 ], 0.5 );
quadA.vertexNormals[ 2 ].copy( vnm1 );
quadA.vertexNormals[ 3 ].copy( vnm2 );
quadB.vertexNormals[ 0 ].copy( vnm2 );
quadB.vertexNormals[ 1 ].copy( vnm1 );
}
if ( face.vertexColors.length === 4 ) {
vcm1 = face.vertexColors[ 1 ].clone();
vcm1.lerp( face.vertexColors[ 2 ], 0.5 );
vcm2 = face.vertexColors[ 3 ].clone();
vcm2.lerp( face.vertexColors[ 0 ], 0.5 );
quadA.vertexColors[ 2 ].copy( vcm1 );
quadA.vertexColors[ 3 ].copy( vcm2 );
quadB.vertexColors[ 0 ].copy( vcm2 );
quadB.vertexColors[ 1 ].copy( vcm1 );
}
edge = 1;
}
faces.push( quadA, quadB );
geometry.vertices.push( vm1, vm2 );
var j, jl, uvs, uvA, uvB, uvC, uvD, uvM1, uvM2, uvsQuadA, uvsQuadB;
for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
if ( geometry.faceVertexUvs[ j ].length ) {
uvs = geometry.faceVertexUvs[ j ][ i ];
uvA = uvs[ 0 ];
uvB = uvs[ 1 ];
uvC = uvs[ 2 ];
uvD = uvs[ 3 ];
// AB + CD
if ( edge === 0 ) {
uvM1 = uvA.clone();
uvM1.lerp( uvB, 0.5 );
uvM2 = uvC.clone();
uvM2.lerp( uvD, 0.5 );
uvsQuadA = [ uvA.clone(), uvM1.clone(), uvM2.clone(), uvD.clone() ];
uvsQuadB = [ uvM1.clone(), uvB.clone(), uvC.clone(), uvM2.clone() ];
// BC + AD
} else {
uvM1 = uvB.clone();
uvM1.lerp( uvC, 0.5 );
uvM2 = uvD.clone();
uvM2.lerp( uvA, 0.5 );
uvsQuadA = [ uvA.clone(), uvB.clone(), uvM1.clone(), uvM2.clone() ];
uvsQuadB = [ uvM2.clone(), uvM1.clone(), uvC.clone(), uvD.clone() ];
}
faceVertexUvs[ j ].push( uvsQuadA, uvsQuadB );
}
}
} else {
faces.push( face );
for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );
}
}
}
}
geometry.faces = faces;
geometry.faceVertexUvs = faceVertexUvs;
}
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.