UNPKG

three

Version:

JavaScript 3D library

159 lines (99 loc) 3.9 kB
import { Geometry } from '../core/Geometry.js'; import { BufferGeometry } from '../core/BufferGeometry.js'; import { Float32BufferAttribute } from '../core/BufferAttribute.js'; import { Vector3 } from '../math/Vector3.js'; // SphereGeometry function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { Geometry.call( this ); this.type = 'SphereGeometry'; this.parameters = { radius: radius, widthSegments: widthSegments, heightSegments: heightSegments, phiStart: phiStart, phiLength: phiLength, thetaStart: thetaStart, thetaLength: thetaLength }; this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); this.mergeVertices(); } SphereGeometry.prototype = Object.create( Geometry.prototype ); SphereGeometry.prototype.constructor = SphereGeometry; // SphereBufferGeometry function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { BufferGeometry.call( this ); this.type = 'SphereBufferGeometry'; this.parameters = { radius: radius, widthSegments: widthSegments, heightSegments: heightSegments, phiStart: phiStart, phiLength: phiLength, thetaStart: thetaStart, thetaLength: thetaLength }; radius = radius || 1; widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); phiStart = phiStart !== undefined ? phiStart : 0; phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; thetaStart = thetaStart !== undefined ? thetaStart : 0; thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); let index = 0; const grid = []; const vertex = new Vector3(); const normal = new Vector3(); // buffers const indices = []; const vertices = []; const normals = []; const uvs = []; // generate vertices, normals and uvs for ( let iy = 0; iy <= heightSegments; iy ++ ) { const verticesRow = []; const v = iy / heightSegments; // special case for the poles let uOffset = 0; if ( iy == 0 && thetaStart == 0 ) { uOffset = 0.5 / widthSegments; } else if ( iy == heightSegments && thetaEnd == Math.PI ) { uOffset = - 0.5 / widthSegments; } for ( let ix = 0; ix <= widthSegments; ix ++ ) { const u = ix / widthSegments; // vertex vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); vertices.push( vertex.x, vertex.y, vertex.z ); // normal normal.copy( vertex ).normalize(); normals.push( normal.x, normal.y, normal.z ); // uv uvs.push( u + uOffset, 1 - v ); verticesRow.push( index ++ ); } grid.push( verticesRow ); } // indices for ( let iy = 0; iy < heightSegments; iy ++ ) { for ( let ix = 0; ix < widthSegments; ix ++ ) { const a = grid[ iy ][ ix + 1 ]; const b = grid[ iy ][ ix ]; const c = grid[ iy + 1 ][ ix ]; const d = grid[ iy + 1 ][ ix + 1 ]; if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); } } // build geometry this.setIndex( indices ); this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); } SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); SphereBufferGeometry.prototype.constructor = SphereBufferGeometry; export { SphereGeometry, SphereBufferGeometry };