Skip to content

Commit 4c69baa

Browse files
committed
New TorusKnotBufferGeometry
1 parent bd30acb commit 4c69baa

7 files changed

Lines changed: 289 additions & 102 deletions

File tree

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<base href="../../../" />
6+
<script src="list.js"></script>
7+
<script src="page.js"></script>
8+
<link type="text/css" rel="stylesheet" href="page.css" />
9+
</head>
10+
<body>
11+
[page:BufferGeometry] &rarr;
12+
13+
<h1>[name]</h1>
14+
15+
<div class="desc">This is the [page:BufferGeometry] port of [page:TorusKnotGeometry].</div>
16+
17+
<iframe src='scenes/geometry-browser.html#TorusKnotBufferGeometry'></iframe>
18+
19+
20+
<h2>Example</h2>
21+
22+
<code>var geometry = new THREE.TorusKnotBufferGeometry( 10, 3, 100, 16 );
23+
var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
24+
var torusKnot = new THREE.Mesh( geometry, material );
25+
scene.add( torusKnot );
26+
</code>
27+
28+
29+
<h2>Constructor</h2>
30+
31+
32+
<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>
33+
<div>
34+
<ul>
35+
<li>radius — Default is 100.</li>
36+
<li>tube — Diameter of the tube. Default is 40.</li>
37+
<li>radialSegments — Default is 64.</li>
38+
<li>tubularSegments — Default is 8.</li>
39+
<li>p — This value determines, how many times the geometry winds around its axis of rotational symmetry. Default is 2.</li>
40+
<li>q — This value determines, how many times the geometry winds around a circle in the interior of the torus. Default is 3.</li>
41+
<li>heightScale — Default is 1.</li>
42+
<li>arc — Central angle. Default is Math.PI * 2.</li>
43+
</ul>
44+
</div>
45+
46+
47+
<h2>Properties</h2>
48+
49+
50+
<div>
51+
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.
52+
</div>
53+
54+
55+
<h2>Source</h2>
56+
57+
[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
58+
</body>
59+
</html>

docs/api/extras/geometries/TorusKnotGeometry.html

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,18 @@ <h2>Example</h2>
2929
<h2>Constructor</h2>
3030

3131

32-
<h3>[name]([page:Float radius], [page:Float tube], [page:Integer radialSegments], [page:Integer tubularSegments], [page:Integer p], [page:Integer q], [page:Float heightScale])</h3>
32+
<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>
3333
<div>
34-
radius — Default is 100. <br />
35-
tube — Default is 40. <br />
36-
radialSegments — Default is 64. <br />
37-
tubularSegments — Default is 8. <br />
38-
p — Default is 2. <br />
39-
q — Default is 3. <br />
40-
heightScale — Default is 1.
34+
<ul>
35+
<li>radius — Default is 100.</li>
36+
<li>tube — Diameter of the tube. Default is 40.</li>
37+
<li>radialSegments — Default is 64.</li>
38+
<li>tubularSegments — Default is 8.</li>
39+
<li>p — This value determines, how many times the geometry winds around its axis of rotational symmetry. Default is 2.</li>
40+
<li>q — This value determines, how many times the geometry winds around a circle in the interior of the torus. Default is 3.</li>
41+
<li>heightScale — Default is 1.</li>
42+
<li>arc — Central angle. Default is Math.PI * 2.</li>
43+
</ul>
4144
</div>
4245

4346

docs/list.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ var list = {
215215
[ "TextGeometry", "api/extras/geometries/TextGeometry" ],
216216
[ "TorusBufferGeometry", "api/extras/geometries/TorusBufferGeometry" ],
217217
[ "TorusGeometry", "api/extras/geometries/TorusGeometry" ],
218+
[ "TorusKnotBufferGeometry", "api/extras/geometries/TorusKnotBufferGeometry" ],
218219
[ "TorusKnotGeometry", "api/extras/geometries/TorusKnotGeometry" ],
219220
[ "TubeGeometry", "api/extras/geometries/TubeGeometry" ]
220221
],

docs/scenes/js/geometry.js

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,45 @@ var guis = {
747747

748748
},
749749

750+
TorusKnotBufferGeometry : function( mesh ) {
751+
752+
var data = {
753+
radius : 10,
754+
tube : 3,
755+
radialSegments : 64,
756+
tubularSegments : 8,
757+
p : 2,
758+
q : 3,
759+
heightScale : 1,
760+
arc : twoPi
761+
};
762+
763+
function generateGeometry() {
764+
765+
updateGroupGeometry( mesh,
766+
new THREE.TorusKnotBufferGeometry(
767+
data.radius, data.tube, data.radialSegments, data.tubularSegments,
768+
data.p, data.q, data.heightScale, data.arc
769+
)
770+
);
771+
772+
}
773+
774+
var folder = gui.addFolder( 'THREE.TorusKnotBufferGeometry' );
775+
776+
folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
777+
folder.add( data, 'tube', 0.1, 10 ).onChange( generateGeometry );
778+
folder.add( data, 'radialSegments', 3, 300 ).step( 1 ).onChange( generateGeometry );
779+
folder.add( data, 'tubularSegments', 3, 20 ).step( 1 ).onChange( generateGeometry );
780+
folder.add( data, 'p', 1, 20 ).step( 1 ).onChange( generateGeometry );
781+
folder.add( data, 'q', 1, 20 ).step( 1 ).onChange( generateGeometry );
782+
folder.add( data, 'heightScale', 1, 20 ).onChange( generateGeometry );
783+
folder.add( data, 'arc', 0.1, twoPi ).onChange( generateGeometry );
784+
785+
generateGeometry();
786+
787+
},
788+
750789
TorusKnotGeometry : function( mesh ) {
751790

752791
var data = {
@@ -756,21 +795,22 @@ var guis = {
756795
tubularSegments : 8,
757796
p : 2,
758797
q : 3,
759-
heightScale : 1
798+
heightScale : 1,
799+
arc : twoPi
760800
};
761801

762802
function generateGeometry() {
763803

764804
updateGroupGeometry( mesh,
765805
new THREE.TorusKnotGeometry(
766806
data.radius, data.tube, data.radialSegments, data.tubularSegments,
767-
data.p, data.q, data.heightScale
807+
data.p, data.q, data.heightScale, data.arc
768808
)
769809
);
770810

771811
}
772812

773-
var folder = gui.addFolder( 'THREE.TorusGeometry' );
813+
var folder = gui.addFolder( 'THREE.TorusKnotGeometry' );
774814

775815
folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
776816
folder.add( data, 'tube', 0.1, 10 ).onChange( generateGeometry );
@@ -779,6 +819,7 @@ var guis = {
779819
folder.add( data, 'p', 1, 20 ).step( 1 ).onChange( generateGeometry );
780820
folder.add( data, 'q', 1, 20 ).step( 1 ).onChange( generateGeometry );
781821
folder.add( data, 'heightScale', 1, 20 ).onChange( generateGeometry );
822+
folder.add( data, 'arc', 0.1, twoPi ).onChange( generateGeometry );
782823

783824
generateGeometry();
784825

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/**
2+
* @author Mugen87 / https://github.com/Mugen87
3+
*
4+
* see: http://www.blackpawn.com/texts/pqtorus/
5+
*/
6+
THREE.TorusKnotBufferGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale, arc ) {
7+
8+
THREE.BufferGeometry.call( this );
9+
10+
this.type = 'TorusKnotBufferGeometry';
11+
12+
this.parameters = {
13+
radius: radius,
14+
tube: tube,
15+
radialSegments: radialSegments,
16+
tubularSegments: tubularSegments,
17+
p: p,
18+
q: q,
19+
heightScale: heightScale,
20+
arc: arc
21+
};
22+
23+
radius = radius || 100;
24+
tube = tube || 40;
25+
radialSegments = Math.floor( radialSegments ) || 64;
26+
tubularSegments = Math.floor( tubularSegments ) || 6;
27+
p = p || 2;
28+
q = q || 3;
29+
heightScale = heightScale || 1;
30+
arc = arc || Math.PI * 2;
31+
32+
// used to calculate buffer length
33+
var vertexCount = ( ( radialSegments + 1 ) * ( tubularSegments + 1 ) );
34+
var indexCount = radialSegments * tubularSegments * 2 * 3;
35+
36+
// buffers
37+
var indices = new THREE.BufferAttribute( new ( indexCount > 65535 ? Uint32Array : Uint16Array )( indexCount ) , 1 );
38+
var vertices = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 );
39+
var normals = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 );
40+
var uvs = new THREE.BufferAttribute( new Float32Array( vertexCount * 2 ), 2 );
41+
42+
// helper variables
43+
var i, j, index = 0, indexOffset = 0;
44+
45+
var vertex = new THREE.Vector3();
46+
var normal = new THREE.Vector3();
47+
var uv = new THREE.Vector2();
48+
49+
var P1 = new THREE.Vector3();
50+
var P2 = new THREE.Vector3();
51+
52+
var B = new THREE.Vector3();
53+
var T = new THREE.Vector3();
54+
var N = new THREE.Vector3();
55+
56+
// generate vertices, normals and uvs
57+
58+
for ( i = 0; i <= radialSegments; ++ i ) {
59+
60+
// the radian "u" is used to calculate the position on the torus curve of the current radial segement
61+
62+
var u = i / radialSegments * p * arc;
63+
64+
// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
65+
// these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
66+
67+
calculatePositionOnCurve( u, p, q, radius, heightScale, P1 );
68+
calculatePositionOnCurve( u + 0.01, p, q, radius, heightScale, P2 );
69+
70+
// calculate orthonormal basis
71+
72+
T.subVectors( P2, P1 );
73+
N.addVectors( P2, P1 );
74+
B.crossVectors( T, N );
75+
N.crossVectors( B, T );
76+
77+
// normalize B, N. T can be ignored, we don't use it
78+
79+
B.normalize();
80+
N.normalize();
81+
82+
for ( j = 0; j <= tubularSegments; ++ j ) {
83+
84+
// now calculate the vertices. they are nothing more than an extrusion of the torus curve.
85+
// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
86+
87+
var v = j / tubularSegments * Math.PI * 2;
88+
var cx = - tube * Math.cos( v );
89+
var cy = tube * Math.sin( v );
90+
91+
// now calculate the final vertex position.
92+
// first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
93+
94+
vertex.x = P1.x + ( cx * N.x + cy * B.x );
95+
vertex.y = P1.y + ( cx * N.y + cy * B.y );
96+
vertex.z = P1.z + ( cx * N.z + cy * B.z );
97+
98+
// vertex
99+
vertices.setXYZ( index, vertex.x, vertex.y, vertex.z );
100+
101+
// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
102+
normal.subVectors( vertex, P1 ).normalize();
103+
normals.setXYZ( index, normal.x, normal.y, normal.z );
104+
105+
// uv
106+
uv.x = i / radialSegments;
107+
uv.y = j / tubularSegments;
108+
uvs.setXY( index, uv.x, uv.y );
109+
110+
// increase index
111+
index ++;
112+
113+
}
114+
115+
}
116+
117+
// generate indices
118+
119+
for ( j = 1; j <= radialSegments; j ++ ) {
120+
121+
for ( i = 1; i <= tubularSegments; i ++ ) {
122+
123+
// indices
124+
var a = ( tubularSegments + 1 ) * ( j - 1 ) + ( i - 1 );
125+
var b = ( tubularSegments + 1 ) * j + ( i - 1 );
126+
var c = ( tubularSegments + 1 ) * j + i;
127+
var d = ( tubularSegments + 1 ) * ( j - 1 ) + i;
128+
129+
// face one
130+
indices.setX( indexOffset, a ); indexOffset++;
131+
indices.setX( indexOffset, b ); indexOffset++;
132+
indices.setX( indexOffset, d ); indexOffset++;
133+
134+
// face two
135+
indices.setX( indexOffset, b ); indexOffset++;
136+
indices.setX( indexOffset, c ); indexOffset++;
137+
indices.setX( indexOffset, d ); indexOffset++;
138+
139+
}
140+
141+
}
142+
143+
// build geometry
144+
145+
this.setIndex( indices );
146+
this.addAttribute( 'position', vertices );
147+
this.addAttribute( 'normal', normals );
148+
this.addAttribute( 'uv', uvs );
149+
150+
// this function calculates the current position on the torus curve
151+
152+
function calculatePositionOnCurve( u, p, q, radius, heightScale, position ) {
153+
154+
var cu = Math.cos( u );
155+
var su = Math.sin( u );
156+
var quOverP = q / p * u;
157+
var cs = Math.cos( quOverP );
158+
159+
position.x = radius * ( 2 + cs ) * 0.5 * cu;
160+
position.y = radius * ( 2 + cs ) * su * 0.5;
161+
position.z = heightScale * radius * Math.sin( quOverP ) * 0.5;
162+
163+
}
164+
165+
};
166+
167+
THREE.TorusKnotBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
168+
THREE.TorusKnotBufferGeometry.prototype.constructor = THREE.TorusKnotBufferGeometry;

0 commit comments

Comments
 (0)