Spaces:
Running
Running
/** | |
* @author mrdoob / http://mrdoob.com/ | |
* @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'; | |
// CylinderGeometry | |
function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { | |
Geometry.call( this ); | |
this.type = 'CylinderGeometry'; | |
this.parameters = { | |
radiusTop: radiusTop, | |
radiusBottom: radiusBottom, | |
height: height, | |
radialSegments: radialSegments, | |
heightSegments: heightSegments, | |
openEnded: openEnded, | |
thetaStart: thetaStart, | |
thetaLength: thetaLength | |
}; | |
this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) ); | |
this.mergeVertices(); | |
} | |
CylinderGeometry.prototype = Object.create( Geometry.prototype ); | |
CylinderGeometry.prototype.constructor = CylinderGeometry; | |
// CylinderBufferGeometry | |
function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { | |
BufferGeometry.call( this ); | |
this.type = 'CylinderBufferGeometry'; | |
this.parameters = { | |
radiusTop: radiusTop, | |
radiusBottom: radiusBottom, | |
height: height, | |
radialSegments: radialSegments, | |
heightSegments: heightSegments, | |
openEnded: openEnded, | |
thetaStart: thetaStart, | |
thetaLength: thetaLength | |
}; | |
var scope = this; | |
radiusTop = radiusTop !== undefined ? radiusTop : 1; | |
radiusBottom = radiusBottom !== undefined ? radiusBottom : 1; | |
height = height || 1; | |
radialSegments = Math.floor( radialSegments ) || 8; | |
heightSegments = Math.floor( heightSegments ) || 1; | |
openEnded = openEnded !== undefined ? openEnded : false; | |
thetaStart = thetaStart !== undefined ? thetaStart : 0.0; | |
thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; | |
// buffers | |
var indices = []; | |
var vertices = []; | |
var normals = []; | |
var uvs = []; | |
// helper variables | |
var index = 0; | |
var indexArray = []; | |
var halfHeight = height / 2; | |
var groupStart = 0; | |
// generate geometry | |
generateTorso(); | |
if ( openEnded === false ) { | |
if ( radiusTop > 0 ) generateCap( true ); | |
if ( radiusBottom > 0 ) generateCap( false ); | |
} | |
// build geometry | |
this.setIndex( indices ); | |
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); | |
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); | |
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); | |
function generateTorso() { | |
var x, y; | |
var normal = new Vector3(); | |
var vertex = new Vector3(); | |
var groupCount = 0; | |
// this will be used to calculate the normal | |
var slope = ( radiusBottom - radiusTop ) / height; | |
// generate vertices, normals and uvs | |
for ( y = 0; y <= heightSegments; y ++ ) { | |
var indexRow = []; | |
var v = y / heightSegments; | |
// calculate the radius of the current row | |
var radius = v * ( radiusBottom - radiusTop ) + radiusTop; | |
for ( x = 0; x <= radialSegments; x ++ ) { | |
var u = x / radialSegments; | |
var theta = u * thetaLength + thetaStart; | |
var sinTheta = Math.sin( theta ); | |
var cosTheta = Math.cos( theta ); | |
// vertex | |
vertex.x = radius * sinTheta; | |
vertex.y = - v * height + halfHeight; | |
vertex.z = radius * cosTheta; | |
vertices.push( vertex.x, vertex.y, vertex.z ); | |
// normal | |
normal.set( sinTheta, slope, cosTheta ).normalize(); | |
normals.push( normal.x, normal.y, normal.z ); | |
// uv | |
uvs.push( u, 1 - v ); | |
// save index of vertex in respective row | |
indexRow.push( index ++ ); | |
} | |
// now save vertices of the row in our index array | |
indexArray.push( indexRow ); | |
} | |
// generate indices | |
for ( x = 0; x < radialSegments; x ++ ) { | |
for ( y = 0; y < heightSegments; y ++ ) { | |
// we use the index array to access the correct indices | |
var a = indexArray[ y ][ x ]; | |
var b = indexArray[ y + 1 ][ x ]; | |
var c = indexArray[ y + 1 ][ x + 1 ]; | |
var d = indexArray[ y ][ x + 1 ]; | |
// faces | |
indices.push( a, b, d ); | |
indices.push( b, c, d ); | |
// update group counter | |
groupCount += 6; | |
} | |
} | |
// add a group to the geometry. this will ensure multi material support | |
scope.addGroup( groupStart, groupCount, 0 ); | |
// calculate new start value for groups | |
groupStart += groupCount; | |
} | |
function generateCap( top ) { | |
var x, centerIndexStart, centerIndexEnd; | |
var uv = new Vector2(); | |
var vertex = new Vector3(); | |
var groupCount = 0; | |
var radius = ( top === true ) ? radiusTop : radiusBottom; | |
var sign = ( top === true ) ? 1 : - 1; | |
// save the index of the first center vertex | |
centerIndexStart = index; | |
// first we generate the center vertex data of the cap. | |
// because the geometry needs one set of uvs per face, | |
// we must generate a center vertex per face/segment | |
for ( x = 1; x <= radialSegments; x ++ ) { | |
// vertex | |
vertices.push( 0, halfHeight * sign, 0 ); | |
// normal | |
normals.push( 0, sign, 0 ); | |
// uv | |
uvs.push( 0.5, 0.5 ); | |
// increase index | |
index ++; | |
} | |
// save the index of the last center vertex | |
centerIndexEnd = index; | |
// now we generate the surrounding vertices, normals and uvs | |
for ( x = 0; x <= radialSegments; x ++ ) { | |
var u = x / radialSegments; | |
var theta = u * thetaLength + thetaStart; | |
var cosTheta = Math.cos( theta ); | |
var sinTheta = Math.sin( theta ); | |
// vertex | |
vertex.x = radius * sinTheta; | |
vertex.y = halfHeight * sign; | |
vertex.z = radius * cosTheta; | |
vertices.push( vertex.x, vertex.y, vertex.z ); | |
// normal | |
normals.push( 0, sign, 0 ); | |
// uv | |
uv.x = ( cosTheta * 0.5 ) + 0.5; | |
uv.y = ( sinTheta * 0.5 * sign ) + 0.5; | |
uvs.push( uv.x, uv.y ); | |
// increase index | |
index ++; | |
} | |
// generate indices | |
for ( x = 0; x < radialSegments; x ++ ) { | |
var c = centerIndexStart + x; | |
var i = centerIndexEnd + x; | |
if ( top === true ) { | |
// face top | |
indices.push( i, i + 1, c ); | |
} else { | |
// face bottom | |
indices.push( i + 1, i, c ); | |
} | |
groupCount += 3; | |
} | |
// add a group to the geometry. this will ensure multi material support | |
scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); | |
// calculate new start value for groups | |
groupStart += groupCount; | |
} | |
} | |
CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); | |
CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry; | |
export { CylinderGeometry, CylinderBufferGeometry }; | |