|
@@ -0,0 +1,138 @@
|
|
|
|
+/**
|
|
|
|
+ * Octahedrons have 8 sides. This octahedron supports subdivision.
|
|
|
|
+ *
|
|
|
|
+ * Vertices have 'smooth' normals,
|
|
|
|
+ * to make a sharp edge choose a material that uses face normals instead.
|
|
|
|
+ *
|
|
|
|
+ * @author [email protected]
|
|
|
|
+ * @param radius
|
|
|
|
+ * @param detail Final number of triangles = 4^detail * 8
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+THREE.OctahedronGeometry = function ( radius, detail ) {
|
|
|
|
+
|
|
|
|
+ THREE.Geometry.call( this );
|
|
|
|
+
|
|
|
|
+ detail = isFinite(detail) ? detail : 3; // allow a zero value
|
|
|
|
+
|
|
|
|
+ var that = this; // ugly scope hack
|
|
|
|
+
|
|
|
|
+ prepare( new THREE.Vector3( +1, 0, 0 ) ); // right
|
|
|
|
+ prepare( new THREE.Vector3( -1, 0, 0 ) ); // left
|
|
|
|
+ prepare( new THREE.Vector3( 0, +1, 0 ) ); // up
|
|
|
|
+ prepare( new THREE.Vector3( 0, -1, 0 ) ); // down
|
|
|
|
+ prepare( new THREE.Vector3( 0, 0, +1 ) ); // front
|
|
|
|
+ prepare( new THREE.Vector3( 0, 0, -1 ) ); // back
|
|
|
|
+ var midpoints = [], p = this.vertices;
|
|
|
|
+
|
|
|
|
+ // careful to output faces counter-clockwise, that is required for meshes
|
|
|
|
+ make( p[0], p[2], p[4], detail );
|
|
|
|
+ make( p[0], p[4], p[3], detail );
|
|
|
|
+ make( p[0], p[3], p[5], detail );
|
|
|
|
+ make( p[0], p[5], p[2], detail );
|
|
|
|
+ make( p[1], p[2], p[5], detail );
|
|
|
|
+ make( p[1], p[5], p[3], detail );
|
|
|
|
+ make( p[1], p[3], p[4], detail );
|
|
|
|
+ make( p[1], p[4], p[2], detail );
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Project vector onto sphere's surface
|
|
|
|
+ */
|
|
|
|
+ function prepare( vector ) {
|
|
|
|
+
|
|
|
|
+ var normal = vector.clone().normalize();
|
|
|
|
+ var vertex = new THREE.Vertex( normal.clone().multiplyScalar( radius ) );
|
|
|
|
+ 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.UV( u, v );
|
|
|
|
+
|
|
|
|
+ return vertex;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Approximate a curved face with recursively sub-divided triangles.
|
|
|
|
+ */
|
|
|
|
+ function make( v1, v2, v3, detail ) {
|
|
|
|
+
|
|
|
|
+ if ( detail < 1 ) {
|
|
|
|
+
|
|
|
|
+ var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.position, v2.position, v3.position ] );
|
|
|
|
+ face.centroid.addSelf( v1.position ).addSelf( v2.position ).addSelf( v3.position ).divideScalar( 3 );
|
|
|
|
+ face.normal = face.centroid.clone().normalize();
|
|
|
|
+ that.faces.push( face );
|
|
|
|
+
|
|
|
|
+ var azi = azimuth( face.centroid );
|
|
|
|
+ that.faceVertexUvs[ 0 ].push( [
|
|
|
|
+ correctUV( v1.uv, v1.position, azi ),
|
|
|
|
+ correctUV( v2.uv, v2.position, azi ),
|
|
|
|
+ correctUV( v3.uv, v3.position, azi )
|
|
|
|
+ ] );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+
|
|
|
|
+ detail -= 1;
|
|
|
|
+ // split triangle into 4 smaller triangles
|
|
|
|
+ make( v1, midpoint( v1, v2 ), midpoint( v1, v3 ), detail ); // top quadrant
|
|
|
|
+ make( midpoint( v1, v2 ), v2, midpoint( v2, v3 ), detail ); // left quadrant
|
|
|
|
+ make( midpoint( v1, v3 ), midpoint( v2, v3 ), v3, detail ); // right quadrant
|
|
|
|
+ make( midpoint( v1, v2 ), midpoint( v2, v3 ), midpoint( v1, v3 ), detail ); // center quadrant
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function midpoint( v1, v2 ) {
|
|
|
|
+
|
|
|
|
+ if ( !midpoints[ v1.index ] ) midpoints[ v1.index ] = [];
|
|
|
|
+ if ( !midpoints[ v2.index ] ) midpoints[ v2.index ] = [];
|
|
|
|
+ var mid = midpoints[ v1.index ][ v2.index ];
|
|
|
|
+ if ( mid === undefined ) {
|
|
|
|
+ // generate mean point and project to surface with prepare()
|
|
|
|
+ midpoints[ v1.index ][ v2.index ] = midpoints[ v2.index ][ v1.index ] = mid = prepare(
|
|
|
|
+ new THREE.Vector3().add( v1.position, v2.position ).divideScalar( 2 )
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ return mid;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 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.u === 1) ) uv = new THREE.UV( uv.u - 1, uv.v );
|
|
|
|
+ if ( (vector.x === 0) && (vector.z === 0) ) uv = new THREE.UV( azimuth / 2 / Math.PI + 0.5, uv.v );
|
|
|
|
+ return uv;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.boundingSphere = { radius: radius };
|
|
|
|
+
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+THREE.OctahedronGeometry.prototype = new THREE.Geometry();
|
|
|
|
+THREE.OctahedronGeometry.prototype.constructor = THREE.OctahedronGeometry;
|