/** * @author WestLangley / https://github.com/WestLangley * @author zz85 / https://github.com/zz85 * @author miningold / https://github.com/miningold * @author jonobr1 / https://github.com/jonobr1 * * Modified from the TorusKnotGeometry by @oosmoxiecode * * Creates a tube which extrudes along a 3d spline * * Uses parallel transport frames as described in * http://www.cs.indiana.edu/pub/techreports/TR425.pdf */ export class TubeGeometry { // THREE.TubeGeometry = function(path, segments, radius, radialSegments, closed, taper) { // THREE.Geometry.call(this); // this.type = 'TubeGeometry'; // this.parameters = { // path: path, // segments: segments, // radius: radius, // radialSegments: radialSegments, // closed: closed, // taper: taper // }; // segments = segments || 64; // radius = radius || 1; // radialSegments = radialSegments || 8; // closed = closed || false; // taper = taper || THREE.TubeGeometry.NoTaper; // var grid = []; // var scope = this, // tangent, // normal, // binormal, // numpoints = segments + 1, // u, v, r, // cx, cy, // pos, pos2 = new THREE.Vector3(), // i, j, // ip, jp, // a, b, c, d, // uva, uvb, uvc, uvd; // var frames = new THREE.TubeGeometry.FrenetFrames(path, segments, closed), // tangents = frames.tangents, // normals = frames.normals, // binormals = frames.binormals; // // proxy internals // this.tangents = tangents; // this.normals = normals; // this.binormals = binormals; // function vert(x, y, z) { // return scope.vertices.push(new THREE.Vector3(x, y, z)) - 1; // } // // construct the grid // for (i = 0; i < numpoints; i++) { // grid[i] = []; // u = i / (numpoints - 1); // pos = path.getPointAt(u); // tangent = tangents[i]; // normal = normals[i]; // binormal = binormals[i]; // r = radius * taper(u); // for (j = 0; j < radialSegments; j++) { // v = j / radialSegments * 2 * Math.PI; // cx = - r * Math.cos(v); // TODO: Hack: Negating it so it faces outside. // cy = r * Math.sin(v); // pos2.copy(pos); // pos2.x += cx * normal.x + cy * binormal.x; // pos2.y += cx * normal.y + cy * binormal.y; // pos2.z += cx * normal.z + cy * binormal.z; // grid[i][j] = vert(pos2.x, pos2.y, pos2.z); // } // } // // construct the mesh // for (i = 0; i < segments; i++) { // for (j = 0; j < radialSegments; j++) { // ip = (closed) ? (i + 1) % segments : i + 1; // jp = (j + 1) % radialSegments; // a = grid[i][j]; // *** NOT NECESSARILY PLANAR ! *** // b = grid[ip][j]; // c = grid[ip][jp]; // d = grid[i][jp]; // uva = new THREE.Vector2(i / segments, j / radialSegments); // uvb = new THREE.Vector2((i + 1) / segments, j / radialSegments); // uvc = new THREE.Vector2((i + 1) / segments, (j + 1) / radialSegments); // uvd = new THREE.Vector2(i / segments, (j + 1) / radialSegments); // 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(); // }; // THREE.TubeGeometry.prototype = Object.create(THREE.Geometry.prototype); // THREE.TubeGeometry.prototype.constructor = THREE.TubeGeometry; // THREE.TubeGeometry.NoTaper = function(u) { // return 1; // }; // THREE.TubeGeometry.SinusoidalTaper = function(u) { // return Math.sin(Math.PI * u); // }; // // For computing of Frenet frames, exposing the tangents, normals and binormals the spline // THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) { // var normal = new THREE.Vector3(), // tangents = [], // normals = [], // binormals = [], // vec = new THREE.Vector3(), // mat = new THREE.Matrix4(), // numpoints = segments + 1, // theta, // smallest, // tx, ty, tz, // i, u; // // expose internals // this.tangents = tangents; // this.normals = normals; // this.binormals = binormals; // // compute the tangent vectors for each segment on the path // for (i = 0; i < numpoints; i++) { // u = i / (numpoints - 1); // tangents[i] = path.getTangentAt(u); // tangents[i].normalize(); // } // initialNormal3(); // /* // function initialNormal1(lastBinormal) { // // fixed start binormal. Has dangers of 0 vectors // normals[ 0 ] = new THREE.Vector3(); // binormals[ 0 ] = new THREE.Vector3(); // if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); // normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); // binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); // } // function initialNormal2() { // // This uses the Frenet-Serret formula for deriving binormal // var t2 = path.getTangentAt( epsilon ); // normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); // binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); // normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent // binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); // } // */ // function initialNormal3() { // // select an initial normal vector perpendicular to the first tangent vector, // // and in the direction of the smallest tangent xyz component // normals[0] = new THREE.Vector3(); // binormals[0] = new THREE.Vector3(); // smallest = Number.MAX_VALUE; // tx = Math.abs(tangents[0].x); // ty = Math.abs(tangents[0].y); // tz = Math.abs(tangents[0].z); // if (tx <= smallest) { // smallest = tx; // normal.set(1, 0, 0); // } // if (ty <= smallest) { // smallest = ty; // normal.set(0, 1, 0); // } // if (tz <= smallest) { // normal.set(0, 0, 1); // } // vec.crossVectors(tangents[0], normal).normalize(); // normals[0].crossVectors(tangents[0], vec); // binormals[0].crossVectors(tangents[0], normals[0]); // } // // compute the slowly-varying normal and binormal vectors for each segment on the path // for (i = 1; i < numpoints; i++) { // normals[i] = normals[i - 1].clone(); // binormals[i] = binormals[i - 1].clone(); // vec.crossVectors(tangents[i - 1], tangents[i]); // if (vec.length() > Number.EPSILON) { // vec.normalize(); // theta = Math.acos(THREE.Math.clamp(tangents[i - 1].dot(tangents[i]), - 1, 1)); // clamp for floating pt errors // normals[i].applyMatrix4(mat.makeRotationAxis(vec, theta)); // } // binormals[i].crossVectors(tangents[i], normals[i]); // } // // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same // if (closed) { // theta = Math.acos(THREE.Math.clamp(normals[0].dot(normals[numpoints - 1]), - 1, 1)); // theta /= (numpoints - 1); // if (tangents[0].dot(vec.crossVectors(normals[0], normals[numpoints - 1])) > 0) { // theta = - theta; // } // for (i = 1; i < numpoints; i++) { // // twist a little... // normals[i].applyMatrix4(mat.makeRotationAxis(tangents[i], theta * i)); // binormals[i].crossVectors(tangents[i], normals[i]); // } // } // }; }