|
@@ -0,0 +1,100 @@
|
|
|
|
+/**
|
|
|
|
+ * @author oosmoxiecode
|
|
|
|
+ * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+var Torusknot = function (radius, tube, segmentsR, segmentsT, p, q, heightScale) {
|
|
|
|
+ var scope = this;
|
|
|
|
+ THREE.Geometry.call(this);
|
|
|
|
+
|
|
|
|
+ this.radius = radius || 200;
|
|
|
|
+ this.tube = tube || 40;
|
|
|
|
+ this.segmentsR = segmentsR || 64;
|
|
|
|
+ this.segmentsT = segmentsT || 8;
|
|
|
|
+ this.p = p || 2;
|
|
|
|
+ this.q = q || 3;
|
|
|
|
+ this.heightScale = heightScale || 1;
|
|
|
|
+ this.grid = new Array(this.segmentsR);
|
|
|
|
+
|
|
|
|
+ var tang = new THREE.Vector3();
|
|
|
|
+ var n = new THREE.Vector3();
|
|
|
|
+ var bitan = new THREE.Vector3();
|
|
|
|
+
|
|
|
|
+ for (var i=0; i<this.segmentsR; ++i) {
|
|
|
|
+ this.grid[i] = new Array(this.segmentsT);
|
|
|
|
+ for (var j=0; j<this.segmentsT; ++j) {
|
|
|
|
+ var u = i / this.segmentsR * 2 * this.p * Math.PI;
|
|
|
|
+ var v = j / this.segmentsT * 2 * Math.PI;
|
|
|
|
+ var p = getPos(u, v, this.q, this.p, this.radius, this.heightScale);
|
|
|
|
+ var p2 = getPos(u+.01, v, this.q, this.p, this.radius, this.heightScale);
|
|
|
|
+ var cx, cy;
|
|
|
|
+
|
|
|
|
+ tang.x = p2.x - p.x; tang.y = p2.y - p.y; tang.z = p2.z - p.z;
|
|
|
|
+ n.x = p2.x + p.x; n.y = p2.y + p.y; n.z = p2.z + p.z;
|
|
|
|
+ bitan.cross(tang, n);
|
|
|
|
+ n.cross(bitan, tang);
|
|
|
|
+ bitan.normalize();
|
|
|
|
+ n.normalize();
|
|
|
|
+
|
|
|
|
+ cx = this.tube*Math.cos(v); cy = this.tube*Math.sin(v);
|
|
|
|
+ p.x += cx * n.x + cy * bitan.x;
|
|
|
|
+ p.y += cx * n.y + cy * bitan.y;
|
|
|
|
+ p.z += cx * n.z + cy * bitan.z;
|
|
|
|
+
|
|
|
|
+ this.grid[i][j] = vert(p.x, p.y, p.z);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (var i=0; i<this.segmentsR; ++i) {
|
|
|
|
+ for (var j=0; j<this.segmentsT; ++j) {
|
|
|
|
+ var ip = (i+1) % this.segmentsR;
|
|
|
|
+ var jp = (j+1) % this.segmentsT;
|
|
|
|
+ var a = this.grid[i][j];
|
|
|
|
+ var b = this.grid[ip][j];
|
|
|
|
+ var c = this.grid[i][jp];
|
|
|
|
+ var d = this.grid[ip][jp];
|
|
|
|
+
|
|
|
|
+ var uva = new THREE.UV(i / this.segmentsR, j / this.segmentsT);
|
|
|
|
+ var uvb = new THREE.UV((i+1) / this.segmentsR, j / this.segmentsT);
|
|
|
|
+ var uvc = new THREE.UV(i / this.segmentsR, (j+1) / this.segmentsT);
|
|
|
|
+ var uvd = new THREE.UV((i+1) / this.segmentsR, (j+1) / this.segmentsT);
|
|
|
|
+
|
|
|
|
+ f3(a, b, c);
|
|
|
|
+ this.uvs.push( [uva,uvb,uvc] );
|
|
|
|
+ f3(d, c, b);
|
|
|
|
+ this.uvs.push( [uvd,uvc,uvb] );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.computeCentroids();
|
|
|
|
+ this.computeFaceNormals();
|
|
|
|
+ this.computeVertexNormals();
|
|
|
|
+ this.sortFacesByMaterial();
|
|
|
|
+
|
|
|
|
+ function vert( x, y, z ) {
|
|
|
|
+ var i = scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );
|
|
|
|
+ return i-1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function f3( a, b, c ) {
|
|
|
|
+ scope.faces.push( new THREE.Face3( a, b, c ) );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function getPos(u, v, in_q, in_p, radius, heightScale ) {
|
|
|
|
+ var cu = Math.cos(u);
|
|
|
|
+ var cv = Math.cos(v);
|
|
|
|
+ var su = Math.sin(u);
|
|
|
|
+ var quOverP = in_q/in_p*u;
|
|
|
|
+ var cs = Math.cos(quOverP);
|
|
|
|
+
|
|
|
|
+ var tx = radius*(2+cs)*.5 * cu;
|
|
|
|
+ var ty = radius*(2+cs)*su*.5;
|
|
|
|
+ var tz = heightScale*radius*Math.sin(quOverP)*.5;
|
|
|
|
+
|
|
|
|
+ return new THREE.Vector3(tx,ty,tz);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Torusknot.prototype = new THREE.Geometry();
|
|
|
|
+Torusknot.prototype.constructor = Torusknot;
|