提交 8a8f05dd 编写于 作者: M Mugen87

New CylinderBufferGeometry

CylinderGeometry`s BufferGeometry port
上级 15ee8ac8
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<base href="../../../" />
<script src="list.js"></script>
<script src="page.js"></script>
<link type="text/css" rel="stylesheet" href="page.css" />
</head>
<body>
[page:BufferGeometry] &rarr;
<h1>[name]</h1>
<div class="desc">This is the [page:BufferGeometry] port of [page:CylinderGeometry].</div>
<h2>Example</h2>
<iframe src='scenes/geometry-browser.html#CylinderBufferGeometry'></iframe>
<code>var geometry = new THREE.CylinderBufferGeometry( 5, 5, 20, 32 );
var material = new THREE.MeshBasicMaterial( {color: 0xffff00} );
var cylinder = new THREE.Mesh( geometry, material );
scene.add( cylinder );
</code>
<h2>Constructor</h2>
<h3>[name]([page:Float radiusTop], [page:Float radiusBottom], [page:Float height], [page:Integer radiusSegments], [page:Integer heightSegments], [page:Boolean openEnded], [page:Float thetaStart], [page:Float thetaLength])</h3>
<div>
radiusTop — Radius of the cylinder at the top. Default is 20.<br />
radiusBottom — Radius of the cylinder at the bottom. Default is 20.<br />
height — Height of the cylinder. Default is 100.<br />
radiusSegments — Number of segmented faces around the circumference of the cylinder. Default is 8<br />
heightSegments — Number of rows of faces along the height of the cylinder. Default is 1.<br />
openEnded — A Boolean indicating whether the ends of the cylinder are open or capped. Default is false, meaning capped.<br />
thetaStart — Start angle for first segment, default = 0 (three o'clock position).<br />
thetaLength — The central angle, often called theta, of the circular sector. The default is 2*Pi, which makes for a complete cylinder.
</div>
<h2>Properties</h2>
<div>
Each of the constructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.
</div>
<h2>Source</h2>
[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
</body>
</html>
......@@ -195,6 +195,7 @@ var list = {
[ "BoxGeometry", "api/extras/geometries/BoxGeometry" ],
[ "CircleBufferGeometry", "api/extras/geometries/CircleBufferGeometry" ],
[ "CircleGeometry", "api/extras/geometries/CircleGeometry" ],
[ "CylinderBufferGeometry", "api/extras/geometries/CylinderBufferGeometry" ],
[ "CylinderGeometry", "api/extras/geometries/CylinderGeometry" ],
[ "DodecahedronGeometry", "api/extras/geometries/DodecahedronGeometry" ],
[ "ExtrudeGeometry", "api/extras/geometries/ExtrudeGeometry" ],
......
......@@ -161,6 +161,52 @@ var guis = {
},
CylinderBufferGeometry : function( mesh ) {
var data = {
radiusTop : 5,
radiusBottom : 5,
height : 10,
radiusSegments : 8,
heightSegments : 1,
openEnded : false,
thetaStart : 0,
thetaLength : twoPi,
};
function generateGeometry() {
updateGroupGeometry( mesh,
new THREE.CylinderBufferGeometry(
data.radiusTop,
data.radiusBottom,
data.height,
data.radiusSegments,
data.heightSegments,
data.openEnded,
data.thetaStart,
data.thetaLength
)
);
}
var folder = gui.addFolder( 'THREE.CylinderBufferGeometry' );
folder.add( data, 'radiusTop', 1, 30 ).onChange( generateGeometry );
folder.add( data, 'radiusBottom', 1, 30 ).onChange( generateGeometry );
folder.add( data, 'height', 1, 50 ).onChange( generateGeometry );
folder.add( data, 'radiusSegments', 3, 64 ).step( 1 ).onChange( generateGeometry );
folder.add( data, 'heightSegments', 1, 64 ).step( 1 ).onChange( generateGeometry );
folder.add( data, 'openEnded' ).onChange( generateGeometry );
folder.add( data, 'thetaStart', 0, twoPi ).onChange( generateGeometry );
folder.add( data, 'thetaLength', 0, twoPi ).onChange( generateGeometry );
generateGeometry();
},
CylinderGeometry : function( mesh ) {
var data = {
......
/**
* @author Mugen87 / https://github.com/Mugen87
*/
THREE.CylinderBufferGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
THREE.BufferGeometry.call( this );
this.type = 'CylinderBufferGeometry';
this.parameters = {
radiusTop: radiusTop,
radiusBottom: radiusBottom,
height: height,
radialSegments: radialSegments,
heightSegments: heightSegments,
openEnded: openEnded,
thetaStart: thetaStart,
thetaLength: thetaLength
};
radiusTop = radiusTop !== undefined ? radiusTop : 20;
radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
height = height !== undefined ? height : 100;
radialSegments = Math.floor( radialSegments ) || 8;
heightSegments = Math.floor( heightSegments ) || 1;
openEnded = openEnded !== undefined ? openEnded : false;
thetaStart = thetaStart !== undefined ? thetaStart : 0;
thetaLength = thetaLength !== undefined ? thetaLength : 2 * Math.PI;
// used to calculate buffer length
var vertexCount = calculateVertexCount();
var indexCount = calculateIndexCount();
// buffers
var indices = new THREE.BufferAttribute( new ( indexCount > 65535 ? Uint32Array : Uint16Array )( indexCount ) , 1 );
var vertices = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 );
var normals = 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, indexArray = [], halfHeight = height / 2;
// generate geometry
generateTorso();
if( openEnded === false ) {
if( radiusTop > 0 ) {
generateCap( true );
}
if( radiusBottom > 0 ) {
generateCap( false );
}
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', vertices );
this.addAttribute( 'normal', normals );
this.addAttribute( 'uv', uvs );
// helper functions
function calculateVertexCount () {
var count = ( radialSegments + 1 ) * ( heightSegments + 1 );
if ( openEnded === false ) {
count += ( ( radialSegments + 1 ) * 2 ) + ( radialSegments * 2 );
}
return count;
}
function calculateIndexCount () {
var count = radialSegments * heightSegments * 2 * 3;
if ( openEnded === false ) {
count += radialSegments * 2 * 3;
}
return count;
}
function generateTorso () {
var x, y;
var normal = new THREE.Vector3();
var vertex = new THREE.Vector3();
// this will be used to calculate the normal
var tanTheta = ( 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;
// vertex
vertex.x = radius * Math.sin( u * thetaLength + thetaStart );
vertex.y = - v * height + halfHeight;
vertex.z = radius * Math.cos( u * thetaLength + thetaStart );
vertices.setXYZ( index, vertex.x, vertex.y, vertex.z );
// normal
normal.copy( vertex );
normal.setY( Math.sqrt( normal.x * normal.x + normal.z * normal.z ) * tanTheta ).normalize();
normals.setXYZ( index, normal.x, normal.y, normal.z );
// uv
uvs.setXY( index, u, 1 - v );
// save index of vertex in respective row
indexRow.push( index );
// increase index
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 i1 = indexArray[ y ][ x ];
var i2 = indexArray[ y + 1 ][ x ];
var i3 = indexArray[ y + 1 ][ x + 1 ];
var i4 = indexArray[ y ][ x + 1 ];
// face one
indices.setX( indexOffset, i1 ); indexOffset++;
indices.setX( indexOffset, i2 ); indexOffset++;
indices.setX( indexOffset, i4 ); indexOffset++;
// face two
indices.setX( indexOffset, i2 ); indexOffset++;
indices.setX( indexOffset, i3 ); indexOffset++;
indices.setX( indexOffset, i4 ); indexOffset++;
}
}
}
function generateCap ( top ) {
var x, centerIndexStart, centerIndexEnd;
var uv = new THREE.Vector2();
var vertex = new THREE.Vector3();
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.setXYZ( index, 0, halfHeight * sign, 0 );
// normal
normals.setXYZ( index, 0, sign, 0 );
// uv
if( top === true ) {
uv.x = x / radialSegments;
uv.y = 0;
} else {
uv.x = ( x - 1 ) / radialSegments;
uv.y = 1;
}
uvs.setXY( index, uv.x, uv.y );
// 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;
// vertex
vertex.x = radius * Math.sin( u * thetaLength + thetaStart );
vertex.y = halfHeight * sign;
vertex.z = radius * Math.cos( u * thetaLength + thetaStart );
vertices.setXYZ( index, vertex.x, vertex.y, vertex.z );
// normal
normals.setXYZ( index, 0, sign, 0 );
// uv
uvs.setXY( index, u, ( top === true ) ? 1 : 0 );
// 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.setX( indexOffset, i ); indexOffset++;
indices.setX( indexOffset, i + 1 ); indexOffset++;
indices.setX( indexOffset, c ); indexOffset++;
} else {
// face bottom
indices.setX( indexOffset, i + 1); indexOffset++;
indices.setX( indexOffset, i ); indexOffset++;
indices.setX( indexOffset, c ); indexOffset++;
}
}
}
};
THREE.CylinderBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
THREE.CylinderBufferGeometry.prototype.constructor = THREE.CylinderBufferGeometry;
......@@ -19,152 +19,8 @@ THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegme
thetaLength: thetaLength
};
radiusTop = radiusTop !== undefined ? radiusTop : 20;
radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
height = height !== undefined ? height : 100;
radialSegments = radialSegments || 8;
heightSegments = heightSegments || 1;
openEnded = openEnded !== undefined ? openEnded : false;
thetaStart = thetaStart !== undefined ? thetaStart : 0;
thetaLength = thetaLength !== undefined ? thetaLength : 2 * Math.PI;
var heightHalf = height / 2;
var x, y, vertices = [], uvs = [];
for ( y = 0; y <= heightSegments; y ++ ) {
var verticesRow = [];
var uvsRow = [];
var v = y / heightSegments;
var radius = v * ( radiusBottom - radiusTop ) + radiusTop;
for ( x = 0; x <= radialSegments; x ++ ) {
var u = x / radialSegments;
var vertex = new THREE.Vector3();
vertex.x = radius * Math.sin( u * thetaLength + thetaStart );
vertex.y = - v * height + heightHalf;
vertex.z = radius * Math.cos( u * thetaLength + thetaStart );
this.vertices.push( vertex );
verticesRow.push( this.vertices.length - 1 );
uvsRow.push( new THREE.Vector2( u, 1 - v ) );
}
vertices.push( verticesRow );
uvs.push( uvsRow );
}
var tanTheta = ( radiusBottom - radiusTop ) / height;
var na, nb;
for ( x = 0; x < radialSegments; x ++ ) {
if ( radiusTop !== 0 ) {
na = this.vertices[ vertices[ 0 ][ x ] ].clone();
nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone();
} else {
na = this.vertices[ vertices[ 1 ][ x ] ].clone();
nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone();
}
na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize();
nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize();
for ( y = 0; y < heightSegments; y ++ ) {
var v1 = vertices[ y ][ x ];
var v2 = vertices[ y + 1 ][ x ];
var v3 = vertices[ y + 1 ][ x + 1 ];
var v4 = vertices[ y ][ x + 1 ];
var n1 = na.clone();
var n2 = na.clone();
var n3 = nb.clone();
var n4 = nb.clone();
var uv1 = uvs[ y ][ x ].clone();
var uv2 = uvs[ y + 1 ][ x ].clone();
var uv3 = uvs[ y + 1 ][ x + 1 ].clone();
var uv4 = uvs[ y ][ x + 1 ].clone();
this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) );
this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] );
this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) );
this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] );
}
}
// top cap
if ( openEnded === false && radiusTop > 0 ) {
this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) );
for ( x = 0; x < radialSegments; x ++ ) {
var v1 = vertices[ 0 ][ x ];
var v2 = vertices[ 0 ][ x + 1 ];
var v3 = this.vertices.length - 1;
var n1 = new THREE.Vector3( 0, 1, 0 );
var n2 = new THREE.Vector3( 0, 1, 0 );
var n3 = new THREE.Vector3( 0, 1, 0 );
var uv1 = uvs[ 0 ][ x ].clone();
var uv2 = uvs[ 0 ][ x + 1 ].clone();
var uv3 = new THREE.Vector2( uv2.x, 0 );
this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ], undefined, 1 ) );
this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );
}
}
// bottom cap
if ( openEnded === false && radiusBottom > 0 ) {
this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) );
for ( x = 0; x < radialSegments; x ++ ) {
var v1 = vertices[ heightSegments ][ x + 1 ];
var v2 = vertices[ heightSegments ][ x ];
var v3 = this.vertices.length - 1;
var n1 = new THREE.Vector3( 0, - 1, 0 );
var n2 = new THREE.Vector3( 0, - 1, 0 );
var n3 = new THREE.Vector3( 0, - 1, 0 );
var uv1 = uvs[ heightSegments ][ x + 1 ].clone();
var uv2 = uvs[ heightSegments ][ x ].clone();
var uv3 = new THREE.Vector2( uv2.x, 1 );
this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ], undefined, 2 ) );
this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );
}
}
this.computeFaceNormals();
this.fromBufferGeometry( new THREE.CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );
this.mergeVertices();
};
......
......@@ -23,6 +23,7 @@
"src/extras/geometries/BoxBufferGeometry.js",
"src/extras/geometries/CircleGeometry.js",
"src/extras/geometries/CircleBufferGeometry.js",
"src/extras/geometries/CylinderBufferGeometry.js",
"src/extras/geometries/CylinderGeometry.js",
"src/extras/geometries/EdgesGeometry.js",
"src/extras/geometries/ExtrudeGeometry.js",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册