three
Version:
JavaScript 3D library
157 lines (110 loc) • 4.34 kB
JavaScript
/**
* @author Mugen87 / https://github.com/Mugen87
*/
// points - to create a closed torus, one must use a set of points
// like so: [ a, b, c, d, a ], see first is the same as last.
// segments - the number of circumference segments to create
// phiStart - the starting radian
// phiLength - the radian (0 to 2PI) range of the lathed section
// 2PI is a closed lathe, less than 2PI is a portion.
THREE.LatheBufferGeometry = function ( points, segments, phiStart, phiLength ) {
THREE.BufferGeometry.call( this );
this.type = 'LatheBufferGeometry';
this.parameters = {
points: points,
segments: segments,
phiStart: phiStart,
phiLength: phiLength
};
segments = Math.floor( segments ) || 12;
phiStart = phiStart || 0;
phiLength = phiLength || Math.PI * 2;
// clamp phiLength so it's in range of [ 0, 2PI ]
phiLength = THREE.Math.clamp( phiLength, 0, Math.PI * 2 );
// these are used to calculate buffer length
var vertexCount = ( segments + 1 ) * points.length;
var indexCount = segments * points.length * 2 * 3;
// buffers
var indices = new THREE.BufferAttribute( new ( indexCount > 65535 ? Uint32Array : Uint16Array )( indexCount ) , 1 );
var vertices = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 );
var uvs = new THREE.BufferAttribute( new Float32Array( vertexCount * 2 ), 2 );
// helper variables
var index = 0, indexOffset = 0, base;
var inversePointLength = 1.0 / ( points.length - 1 );
var inverseSegments = 1.0 / segments;
var vertex = new THREE.Vector3();
var uv = new THREE.Vector2();
var i, j;
// generate vertices and uvs
for ( i = 0; i <= segments; i ++ ) {
var phi = phiStart + i * inverseSegments * phiLength;
var sin = Math.sin( phi );
var cos = Math.cos( phi );
for ( j = 0; j <= ( points.length - 1 ); j ++ ) {
// vertex
vertex.x = points[ j ].x * sin;
vertex.y = points[ j ].y;
vertex.z = points[ j ].x * cos;
vertices.setXYZ( index, vertex.x, vertex.y, vertex.z );
// uv
uv.x = i / segments;
uv.y = j / ( points.length - 1 );
uvs.setXY( index, uv.x, uv.y );
// increase index
index ++;
}
}
// generate indices
for ( i = 0; i < segments; i ++ ) {
for ( j = 0; j < ( points.length - 1 ); j ++ ) {
base = j + i * points.length;
// indices
var a = base;
var b = base + points.length;
var c = base + points.length + 1;
var d = base + 1;
// face one
indices.setX( indexOffset, a ); indexOffset++;
indices.setX( indexOffset, b ); indexOffset++;
indices.setX( indexOffset, d ); indexOffset++;
// face two
indices.setX( indexOffset, b ); indexOffset++;
indices.setX( indexOffset, c ); indexOffset++;
indices.setX( indexOffset, d ); indexOffset++;
}
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', vertices );
this.addAttribute( 'uv', uvs );
// generate normals
this.computeVertexNormals();
// if the geometry is closed, we need to average the normals along the seam.
// because the corresponding vertices are identical (but still have different UVs).
if( phiLength === Math.PI * 2 ) {
var normals = this.attributes.normal.array;
var n1 = new THREE.Vector3();
var n2 = new THREE.Vector3();
var n = new THREE.Vector3();
// this is the buffer offset for the last line of vertices
base = segments * points.length * 3;
for( i = 0, j = 0; i < points.length; i ++, j += 3 ) {
// select the normal of the vertex in the first line
n1.x = normals[ j + 0 ];
n1.y = normals[ j + 1 ];
n1.z = normals[ j + 2 ];
// select the normal of the vertex in the last line
n2.x = normals[ base + j + 0 ];
n2.y = normals[ base + j + 1 ];
n2.z = normals[ base + j + 2 ];
// average normals
n.addVectors( n1, n2 ).normalize();
// assign the new values to both normals
normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
} // next row
}
};
THREE.LatheBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
THREE.LatheBufferGeometry.prototype.constructor = THREE.LatheBufferGeometry;