235 lines
4.6 KiB
JavaScript
235 lines
4.6 KiB
JavaScript
/**
|
|
* @author clockworkgeek / https://github.com/clockworkgeek
|
|
* @author timothypratley / https://github.com/timothypratley
|
|
* @author WestLangley / http://github.com/WestLangley
|
|
*/
|
|
|
|
THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) {
|
|
|
|
THREE.Geometry.call( this );
|
|
|
|
this.type = 'PolyhedronGeometry';
|
|
|
|
this.parameters = {
|
|
vertices: vertices,
|
|
indices: indices,
|
|
radius: radius,
|
|
detail: detail
|
|
};
|
|
|
|
radius = radius || 1;
|
|
detail = detail || 0;
|
|
|
|
var that = this;
|
|
|
|
for ( var i = 0, l = vertices.length; i < l; i += 3 ) {
|
|
|
|
prepare( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) );
|
|
|
|
}
|
|
|
|
var p = this.vertices;
|
|
|
|
var faces = [];
|
|
|
|
for ( var i = 0, j = 0, l = indices.length; i < l; i += 3, j ++ ) {
|
|
|
|
var v1 = p[ indices[ i ] ];
|
|
var v2 = p[ indices[ i + 1 ] ];
|
|
var v3 = p[ indices[ i + 2 ] ];
|
|
|
|
faces[ j ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] );
|
|
|
|
}
|
|
|
|
var centroid = new THREE.Vector3();
|
|
|
|
for ( var i = 0, l = faces.length; i < l; i ++ ) {
|
|
|
|
subdivide( faces[ i ], detail );
|
|
|
|
}
|
|
|
|
|
|
// Handle case when face straddles the seam
|
|
|
|
for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) {
|
|
|
|
var uvs = this.faceVertexUvs[ 0 ][ i ];
|
|
|
|
var x0 = uvs[ 0 ].x;
|
|
var x1 = uvs[ 1 ].x;
|
|
var x2 = uvs[ 2 ].x;
|
|
|
|
var max = Math.max( x0, Math.max( x1, x2 ) );
|
|
var min = Math.min( x0, Math.min( x1, x2 ) );
|
|
|
|
if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary
|
|
|
|
if ( x0 < 0.2 ) uvs[ 0 ].x += 1;
|
|
if ( x1 < 0.2 ) uvs[ 1 ].x += 1;
|
|
if ( x2 < 0.2 ) uvs[ 2 ].x += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// Apply radius
|
|
|
|
for ( var i = 0, l = this.vertices.length; i < l; i ++ ) {
|
|
|
|
this.vertices[ i ].multiplyScalar( radius );
|
|
|
|
}
|
|
|
|
|
|
// Merge vertices
|
|
|
|
this.mergeVertices();
|
|
|
|
this.computeFaceNormals();
|
|
|
|
this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
|
|
|
|
|
|
// Project vector onto sphere's surface
|
|
|
|
function prepare( vector ) {
|
|
|
|
var vertex = vector.normalize().clone();
|
|
vertex.index = that.vertices.push( vertex ) - 1;
|
|
|
|
// Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle.
|
|
|
|
var u = azimuth( vector ) / 2 / Math.PI + 0.5;
|
|
var v = inclination( vector ) / Math.PI + 0.5;
|
|
vertex.uv = new THREE.Vector2( u, 1 - v );
|
|
|
|
return vertex;
|
|
|
|
}
|
|
|
|
|
|
// Approximate a curved face with recursively sub-divided triangles.
|
|
|
|
function make( v1, v2, v3 ) {
|
|
|
|
var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] );
|
|
that.faces.push( face );
|
|
|
|
centroid.copy( v1 ).add( v2 ).add( v3 ).divideScalar( 3 );
|
|
|
|
var azi = azimuth( centroid );
|
|
|
|
that.faceVertexUvs[ 0 ].push( [
|
|
correctUV( v1.uv, v1, azi ),
|
|
correctUV( v2.uv, v2, azi ),
|
|
correctUV( v3.uv, v3, azi )
|
|
] );
|
|
|
|
}
|
|
|
|
|
|
// Analytically subdivide a face to the required detail level.
|
|
|
|
function subdivide( face, detail ) {
|
|
|
|
var cols = Math.pow(2, detail);
|
|
var a = prepare( that.vertices[ face.a ] );
|
|
var b = prepare( that.vertices[ face.b ] );
|
|
var c = prepare( that.vertices[ face.c ] );
|
|
var v = [];
|
|
|
|
// Construct all of the vertices for this subdivision.
|
|
|
|
for ( var i = 0 ; i <= cols; i ++ ) {
|
|
|
|
v[ i ] = [];
|
|
|
|
var aj = prepare( a.clone().lerp( c, i / cols ) );
|
|
var bj = prepare( b.clone().lerp( c, i / cols ) );
|
|
var rows = cols - i;
|
|
|
|
for ( var j = 0; j <= rows; j ++) {
|
|
|
|
if ( j == 0 && i == cols ) {
|
|
|
|
v[ i ][ j ] = aj;
|
|
|
|
} else {
|
|
|
|
v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Construct all of the faces.
|
|
|
|
for ( var i = 0; i < cols ; i ++ ) {
|
|
|
|
for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) {
|
|
|
|
var k = Math.floor( j / 2 );
|
|
|
|
if ( j % 2 == 0 ) {
|
|
|
|
make(
|
|
v[ i ][ k + 1],
|
|
v[ i + 1 ][ k ],
|
|
v[ i ][ k ]
|
|
);
|
|
|
|
} else {
|
|
|
|
make(
|
|
v[ i ][ k + 1 ],
|
|
v[ i + 1][ k + 1],
|
|
v[ i + 1 ][ k ]
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// Angle around the Y axis, counter-clockwise when looking from above.
|
|
|
|
function azimuth( vector ) {
|
|
|
|
return Math.atan2( vector.z, - vector.x );
|
|
|
|
}
|
|
|
|
|
|
// Angle above the XZ plane.
|
|
|
|
function inclination( vector ) {
|
|
|
|
return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
|
|
|
|
}
|
|
|
|
|
|
// Texture fixing helper. Spheres have some odd behaviours.
|
|
|
|
function correctUV( uv, vector, azimuth ) {
|
|
|
|
if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y );
|
|
if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y );
|
|
return uv.clone();
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype );
|
|
THREE.PolyhedronGeometry.prototype.constructor = THREE.PolyhedronGeometry;
|