317 lines
6.6 KiB
JavaScript
317 lines
6.6 KiB
JavaScript
|
/**
|
||
|
* @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 };
|