Spaces:
Running
Running
| /** | |
| * @author clockworkgeek / https://github.com/clockworkgeek | |
| * @author timothypratley / https://github.com/timothypratley | |
| * @author WestLangley / http://github.com/WestLangley | |
| * @author Mugen87 / https://github.com/Mugen87 | |
| */ | |
| import { Geometry } from '../core/Geometry.js'; | |
| import { BufferGeometry } from '../core/BufferGeometry.js'; | |
| import { Float32BufferAttribute } from '../core/BufferAttribute.js'; | |
| import { Vector3 } from '../math/Vector3.js'; | |
| import { Vector2 } from '../math/Vector2.js'; | |
| // PolyhedronGeometry | |
| function PolyhedronGeometry( vertices, indices, radius, detail ) { | |
| Geometry.call( this ); | |
| this.type = 'PolyhedronGeometry'; | |
| this.parameters = { | |
| vertices: vertices, | |
| indices: indices, | |
| radius: radius, | |
| detail: detail | |
| }; | |
| this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) ); | |
| this.mergeVertices(); | |
| } | |
| PolyhedronGeometry.prototype = Object.create( Geometry.prototype ); | |
| PolyhedronGeometry.prototype.constructor = PolyhedronGeometry; | |
| // PolyhedronBufferGeometry | |
| function PolyhedronBufferGeometry( vertices, indices, radius, detail ) { | |
| BufferGeometry.call( this ); | |
| this.type = 'PolyhedronBufferGeometry'; | |
| this.parameters = { | |
| vertices: vertices, | |
| indices: indices, | |
| radius: radius, | |
| detail: detail | |
| }; | |
| radius = radius || 1; | |
| detail = detail || 0; | |
| // default buffer data | |
| var vertexBuffer = []; | |
| var uvBuffer = []; | |
| // the subdivision creates the vertex buffer data | |
| subdivide( detail ); | |
| // all vertices should lie on a conceptual sphere with a given radius | |
| appplyRadius( radius ); | |
| // finally, create the uv data | |
| generateUVs(); | |
| // build non-indexed geometry | |
| this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); | |
| this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); | |
| this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); | |
| if ( detail === 0 ) { | |
| this.computeVertexNormals(); // flat normals | |
| } else { | |
| this.normalizeNormals(); // smooth normals | |
| } | |
| // helper functions | |
| function subdivide( detail ) { | |
| var a = new Vector3(); | |
| var b = new Vector3(); | |
| var c = new Vector3(); | |
| // iterate over all faces and apply a subdivison with the given detail value | |
| for ( var i = 0; i < indices.length; i += 3 ) { | |
| // get the vertices of the face | |
| getVertexByIndex( indices[ i + 0 ], a ); | |
| getVertexByIndex( indices[ i + 1 ], b ); | |
| getVertexByIndex( indices[ i + 2 ], c ); | |
| // perform subdivision | |
| subdivideFace( a, b, c, detail ); | |
| } | |
| } | |
| function subdivideFace( a, b, c, detail ) { | |
| var cols = Math.pow( 2, detail ); | |
| // we use this multidimensional array as a data structure for creating the subdivision | |
| var v = []; | |
| var i, j; | |
| // construct all of the vertices for this subdivision | |
| for ( i = 0; i <= cols; i ++ ) { | |
| v[ i ] = []; | |
| var aj = a.clone().lerp( c, i / cols ); | |
| var bj = b.clone().lerp( c, i / cols ); | |
| var rows = cols - i; | |
| for ( j = 0; j <= rows; j ++ ) { | |
| if ( j === 0 && i === cols ) { | |
| v[ i ][ j ] = aj; | |
| } else { | |
| v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); | |
| } | |
| } | |
| } | |
| // construct all of the faces | |
| for ( i = 0; i < cols; i ++ ) { | |
| for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { | |
| var k = Math.floor( j / 2 ); | |
| if ( j % 2 === 0 ) { | |
| pushVertex( v[ i ][ k + 1 ] ); | |
| pushVertex( v[ i + 1 ][ k ] ); | |
| pushVertex( v[ i ][ k ] ); | |
| } else { | |
| pushVertex( v[ i ][ k + 1 ] ); | |
| pushVertex( v[ i + 1 ][ k + 1 ] ); | |
| pushVertex( v[ i + 1 ][ k ] ); | |
| } | |
| } | |
| } | |
| } | |
| function appplyRadius( radius ) { | |
| var vertex = new Vector3(); | |
| // iterate over the entire buffer and apply the radius to each vertex | |
| for ( var i = 0; i < vertexBuffer.length; i += 3 ) { | |
| vertex.x = vertexBuffer[ i + 0 ]; | |
| vertex.y = vertexBuffer[ i + 1 ]; | |
| vertex.z = vertexBuffer[ i + 2 ]; | |
| vertex.normalize().multiplyScalar( radius ); | |
| vertexBuffer[ i + 0 ] = vertex.x; | |
| vertexBuffer[ i + 1 ] = vertex.y; | |
| vertexBuffer[ i + 2 ] = vertex.z; | |
| } | |
| } | |
| function generateUVs() { | |
| var vertex = new Vector3(); | |
| for ( var i = 0; i < vertexBuffer.length; i += 3 ) { | |
| vertex.x = vertexBuffer[ i + 0 ]; | |
| vertex.y = vertexBuffer[ i + 1 ]; | |
| vertex.z = vertexBuffer[ i + 2 ]; | |
| var u = azimuth( vertex ) / 2 / Math.PI + 0.5; | |
| var v = inclination( vertex ) / Math.PI + 0.5; | |
| uvBuffer.push( u, 1 - v ); | |
| } | |
| correctUVs(); | |
| correctSeam(); | |
| } | |
| function correctSeam() { | |
| // handle case when face straddles the seam, see #3269 | |
| for ( var i = 0; i < uvBuffer.length; i += 6 ) { | |
| // uv data of a single face | |
| var x0 = uvBuffer[ i + 0 ]; | |
| var x1 = uvBuffer[ i + 2 ]; | |
| var x2 = uvBuffer[ i + 4 ]; | |
| var max = Math.max( x0, x1, x2 ); | |
| var min = Math.min( x0, x1, x2 ); | |
| // 0.9 is somewhat arbitrary | |
| if ( max > 0.9 && min < 0.1 ) { | |
| if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; | |
| if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; | |
| if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; | |
| } | |
| } | |
| } | |
| function pushVertex( vertex ) { | |
| vertexBuffer.push( vertex.x, vertex.y, vertex.z ); | |
| } | |
| function getVertexByIndex( index, vertex ) { | |
| var stride = index * 3; | |
| vertex.x = vertices[ stride + 0 ]; | |
| vertex.y = vertices[ stride + 1 ]; | |
| vertex.z = vertices[ stride + 2 ]; | |
| } | |
| function correctUVs() { | |
| var a = new Vector3(); | |
| var b = new Vector3(); | |
| var c = new Vector3(); | |
| var centroid = new Vector3(); | |
| var uvA = new Vector2(); | |
| var uvB = new Vector2(); | |
| var uvC = new Vector2(); | |
| for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { | |
| a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); | |
| b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); | |
| c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); | |
| uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); | |
| uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); | |
| uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); | |
| centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); | |
| var azi = azimuth( centroid ); | |
| correctUV( uvA, j + 0, a, azi ); | |
| correctUV( uvB, j + 2, b, azi ); | |
| correctUV( uvC, j + 4, c, azi ); | |
| } | |
| } | |
| function correctUV( uv, stride, vector, azimuth ) { | |
| if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { | |
| uvBuffer[ stride ] = uv.x - 1; | |
| } | |
| if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { | |
| uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; | |
| } | |
| } | |
| // 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 ) ) ); | |
| } | |
| } | |
| PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); | |
| PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry; | |
| export { PolyhedronGeometry, PolyhedronBufferGeometry }; | |