提交 4c69baa9 编写于 作者: M Mugen87

New TorusKnotBufferGeometry

上级 bd30acb5
<!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:TorusKnotGeometry].</div>
<iframe src='scenes/geometry-browser.html#TorusKnotBufferGeometry'></iframe>
<h2>Example</h2>
<code>var geometry = new THREE.TorusKnotBufferGeometry( 10, 3, 100, 16 );
var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
var torusKnot = new THREE.Mesh( geometry, material );
scene.add( torusKnot );
</code>
<h2>Constructor</h2>
<h3>[name]([page:Float radius], [page:Float tube], [page:Integer radialSegments], [page:Integer tubularSegments], [page:Integer p], [page:Integer q], [page:Float heightScale], [page:Float arc])</h3>
<div>
<ul>
<li>radius — Default is 100.</li>
<li>tube — Diameter of the tube. Default is 40.</li>
<li>radialSegments — Default is 64.</li>
<li>tubularSegments — Default is 8.</li>
<li>p — This value determines, how many times the geometry winds around its axis of rotational symmetry. Default is 2.</li>
<li>q — This value determines, how many times the geometry winds around a circle in the interior of the torus. Default is 3.</li>
<li>heightScale — Default is 1.</li>
<li>arc — Central angle. Default is Math.PI * 2.</li>
</ul>
</div>
<h2>Properties</h2>
<div>
Each of the contructor 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>
......@@ -29,15 +29,18 @@
<h2>Constructor</h2>
<h3>[name]([page:Float radius], [page:Float tube], [page:Integer radialSegments], [page:Integer tubularSegments], [page:Integer p], [page:Integer q], [page:Float heightScale])</h3>
<h3>[name]([page:Float radius], [page:Float tube], [page:Integer radialSegments], [page:Integer tubularSegments], [page:Integer p], [page:Integer q], [page:Float heightScale], [page:Float arc])</h3>
<div>
radius — Default is 100. <br />
tube — Default is 40. <br />
radialSegments — Default is 64. <br />
tubularSegments — Default is 8. <br />
p — Default is 2. <br />
q — Default is 3. <br />
heightScale — Default is 1.
<ul>
<li>radius — Default is 100.</li>
<li>tube — Diameter of the tube. Default is 40.</li>
<li>radialSegments — Default is 64.</li>
<li>tubularSegments — Default is 8.</li>
<li>p — This value determines, how many times the geometry winds around its axis of rotational symmetry. Default is 2.</li>
<li>q — This value determines, how many times the geometry winds around a circle in the interior of the torus. Default is 3.</li>
<li>heightScale — Default is 1.</li>
<li>arc — Central angle. Default is Math.PI * 2.</li>
</ul>
</div>
......
......@@ -215,6 +215,7 @@ var list = {
[ "TextGeometry", "api/extras/geometries/TextGeometry" ],
[ "TorusBufferGeometry", "api/extras/geometries/TorusBufferGeometry" ],
[ "TorusGeometry", "api/extras/geometries/TorusGeometry" ],
[ "TorusKnotBufferGeometry", "api/extras/geometries/TorusKnotBufferGeometry" ],
[ "TorusKnotGeometry", "api/extras/geometries/TorusKnotGeometry" ],
[ "TubeGeometry", "api/extras/geometries/TubeGeometry" ]
],
......
......@@ -747,6 +747,45 @@ var guis = {
},
TorusKnotBufferGeometry : function( mesh ) {
var data = {
radius : 10,
tube : 3,
radialSegments : 64,
tubularSegments : 8,
p : 2,
q : 3,
heightScale : 1,
arc : twoPi
};
function generateGeometry() {
updateGroupGeometry( mesh,
new THREE.TorusKnotBufferGeometry(
data.radius, data.tube, data.radialSegments, data.tubularSegments,
data.p, data.q, data.heightScale, data.arc
)
);
}
var folder = gui.addFolder( 'THREE.TorusKnotBufferGeometry' );
folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
folder.add( data, 'tube', 0.1, 10 ).onChange( generateGeometry );
folder.add( data, 'radialSegments', 3, 300 ).step( 1 ).onChange( generateGeometry );
folder.add( data, 'tubularSegments', 3, 20 ).step( 1 ).onChange( generateGeometry );
folder.add( data, 'p', 1, 20 ).step( 1 ).onChange( generateGeometry );
folder.add( data, 'q', 1, 20 ).step( 1 ).onChange( generateGeometry );
folder.add( data, 'heightScale', 1, 20 ).onChange( generateGeometry );
folder.add( data, 'arc', 0.1, twoPi ).onChange( generateGeometry );
generateGeometry();
},
TorusKnotGeometry : function( mesh ) {
var data = {
......@@ -756,7 +795,8 @@ var guis = {
tubularSegments : 8,
p : 2,
q : 3,
heightScale : 1
heightScale : 1,
arc : twoPi
};
function generateGeometry() {
......@@ -764,13 +804,13 @@ var guis = {
updateGroupGeometry( mesh,
new THREE.TorusKnotGeometry(
data.radius, data.tube, data.radialSegments, data.tubularSegments,
data.p, data.q, data.heightScale
data.p, data.q, data.heightScale, data.arc
)
);
}
var folder = gui.addFolder( 'THREE.TorusGeometry' );
var folder = gui.addFolder( 'THREE.TorusKnotGeometry' );
folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
folder.add( data, 'tube', 0.1, 10 ).onChange( generateGeometry );
......@@ -779,6 +819,7 @@ var guis = {
folder.add( data, 'p', 1, 20 ).step( 1 ).onChange( generateGeometry );
folder.add( data, 'q', 1, 20 ).step( 1 ).onChange( generateGeometry );
folder.add( data, 'heightScale', 1, 20 ).onChange( generateGeometry );
folder.add( data, 'arc', 0.1, twoPi ).onChange( generateGeometry );
generateGeometry();
......
/**
* @author Mugen87 / https://github.com/Mugen87
*
* see: http://www.blackpawn.com/texts/pqtorus/
*/
THREE.TorusKnotBufferGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale, arc ) {
THREE.BufferGeometry.call( this );
this.type = 'TorusKnotBufferGeometry';
this.parameters = {
radius: radius,
tube: tube,
radialSegments: radialSegments,
tubularSegments: tubularSegments,
p: p,
q: q,
heightScale: heightScale,
arc: arc
};
radius = radius || 100;
tube = tube || 40;
radialSegments = Math.floor( radialSegments ) || 64;
tubularSegments = Math.floor( tubularSegments ) || 6;
p = p || 2;
q = q || 3;
heightScale = heightScale || 1;
arc = arc || Math.PI * 2;
// used to calculate buffer length
var vertexCount = ( ( radialSegments + 1 ) * ( tubularSegments + 1 ) );
var indexCount = radialSegments * tubularSegments * 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 normals = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 );
var uvs = new THREE.BufferAttribute( new Float32Array( vertexCount * 2 ), 2 );
// helper variables
var i, j, index = 0, indexOffset = 0;
var vertex = new THREE.Vector3();
var normal = new THREE.Vector3();
var uv = new THREE.Vector2();
var P1 = new THREE.Vector3();
var P2 = new THREE.Vector3();
var B = new THREE.Vector3();
var T = new THREE.Vector3();
var N = new THREE.Vector3();
// generate vertices, normals and uvs
for ( i = 0; i <= radialSegments; ++ i ) {
// the radian "u" is used to calculate the position on the torus curve of the current radial segement
var u = i / radialSegments * p * arc;
// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
// these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
calculatePositionOnCurve( u, p, q, radius, heightScale, P1 );
calculatePositionOnCurve( u + 0.01, p, q, radius, heightScale, P2 );
// calculate orthonormal basis
T.subVectors( P2, P1 );
N.addVectors( P2, P1 );
B.crossVectors( T, N );
N.crossVectors( B, T );
// normalize B, N. T can be ignored, we don't use it
B.normalize();
N.normalize();
for ( j = 0; j <= tubularSegments; ++ j ) {
// now calculate the vertices. they are nothing more than an extrusion of the torus curve.
// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
var v = j / tubularSegments * Math.PI * 2;
var cx = - tube * Math.cos( v );
var cy = tube * Math.sin( v );
// now calculate the final vertex position.
// first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
vertex.x = P1.x + ( cx * N.x + cy * B.x );
vertex.y = P1.y + ( cx * N.y + cy * B.y );
vertex.z = P1.z + ( cx * N.z + cy * B.z );
// vertex
vertices.setXYZ( index, vertex.x, vertex.y, vertex.z );
// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
normal.subVectors( vertex, P1 ).normalize();
normals.setXYZ( index, normal.x, normal.y, normal.z );
// uv
uv.x = i / radialSegments;
uv.y = j / tubularSegments;
uvs.setXY( index, uv.x, uv.y );
// increase index
index ++;
}
}
// generate indices
for ( j = 1; j <= radialSegments; j ++ ) {
for ( i = 1; i <= tubularSegments; i ++ ) {
// indices
var a = ( tubularSegments + 1 ) * ( j - 1 ) + ( i - 1 );
var b = ( tubularSegments + 1 ) * j + ( i - 1 );
var c = ( tubularSegments + 1 ) * j + i;
var d = ( tubularSegments + 1 ) * ( j - 1 ) + i;
// 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( 'normal', normals );
this.addAttribute( 'uv', uvs );
// this function calculates the current position on the torus curve
function calculatePositionOnCurve( u, p, q, radius, heightScale, position ) {
var cu = Math.cos( u );
var su = Math.sin( u );
var quOverP = q / p * u;
var cs = Math.cos( quOverP );
position.x = radius * ( 2 + cs ) * 0.5 * cu;
position.y = radius * ( 2 + cs ) * su * 0.5;
position.z = heightScale * radius * Math.sin( quOverP ) * 0.5;
}
};
THREE.TorusKnotBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
THREE.TorusKnotBufferGeometry.prototype.constructor = THREE.TorusKnotBufferGeometry;
/**
* @author oosmoxiecode
* based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473
*/
THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) {
THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale, arc ) {
THREE.Geometry.call( this );
......@@ -16,97 +15,12 @@ THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegmen
tubularSegments: tubularSegments,
p: p,
q: q,
heightScale: heightScale
heightScale: heightScale,
arc: arc
};
radius = radius || 100;
tube = tube || 40;
radialSegments = radialSegments || 64;
tubularSegments = tubularSegments || 8;
p = p || 2;
q = q || 3;
heightScale = heightScale || 1;
var grid = new Array( radialSegments );
var tang = new THREE.Vector3();
var n = new THREE.Vector3();
var bitan = new THREE.Vector3();
for ( var i = 0; i < radialSegments; ++ i ) {
grid[ i ] = new Array( tubularSegments );
var u = i / radialSegments * 2 * p * Math.PI;
var p1 = getPos( u, q, p, radius, heightScale );
var p2 = getPos( u + 0.01, q, p, radius, heightScale );
tang.subVectors( p2, p1 );
n.addVectors( p2, p1 );
bitan.crossVectors( tang, n );
n.crossVectors( bitan, tang );
bitan.normalize();
n.normalize();
for ( var j = 0; j < tubularSegments; ++ j ) {
var v = j / tubularSegments * 2 * Math.PI;
var cx = - tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
var cy = tube * Math.sin( v );
var pos = new THREE.Vector3();
pos.x = p1.x + cx * n.x + cy * bitan.x;
pos.y = p1.y + cx * n.y + cy * bitan.y;
pos.z = p1.z + cx * n.z + cy * bitan.z;
grid[ i ][ j ] = this.vertices.push( pos ) - 1;
}
}
for ( var i = 0; i < radialSegments; ++ i ) {
for ( var j = 0; j < tubularSegments; ++ j ) {
var ip = ( i + 1 ) % radialSegments;
var jp = ( j + 1 ) % tubularSegments;
var a = grid[ i ][ j ];
var b = grid[ ip ][ j ];
var c = grid[ ip ][ jp ];
var d = grid[ i ][ jp ];
var uva = new THREE.Vector2( i / radialSegments, j / tubularSegments );
var uvb = new THREE.Vector2( ( i + 1 ) / radialSegments, j / tubularSegments );
var uvc = new THREE.Vector2( ( i + 1 ) / radialSegments, ( j + 1 ) / tubularSegments );
var uvd = new THREE.Vector2( i / radialSegments, ( j + 1 ) / tubularSegments );
this.faces.push( new THREE.Face3( a, b, d ) );
this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );
this.faces.push( new THREE.Face3( b, c, d ) );
this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );
}
}
this.computeFaceNormals();
this.computeVertexNormals();
function getPos( u, in_q, in_p, radius, heightScale ) {
var cu = Math.cos( u );
var su = Math.sin( u );
var quOverP = in_q / in_p * u;
var cs = Math.cos( quOverP );
var tx = radius * ( 2 + cs ) * 0.5 * cu;
var ty = radius * ( 2 + cs ) * su * 0.5;
var tz = heightScale * radius * Math.sin( quOverP ) * 0.5;
return new THREE.Vector3( tx, ty, tz );
}
this.fromBufferGeometry( new THREE.TorusKnotBufferGeometry( radius, tube, radialSegments, tubularSegments, p, q, heightScale, arc ) );
this.mergeVertices();
};
......
......@@ -38,6 +38,7 @@
"src/extras/geometries/TextGeometry.js",
"src/extras/geometries/TorusBufferGeometry.js",
"src/extras/geometries/TorusGeometry.js",
"src/extras/geometries/TorusKnotBufferGeometry.js",
"src/extras/geometries/TorusKnotGeometry.js",
"src/extras/geometries/TubeGeometry.js",
"src/extras/geometries/PolyhedronGeometry.js",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册