source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Content/Web/mrdoob-three.js-4862f5f/src/extras/geometries/TubeGeometry.js@ 28897

Last change on this file since 28897 was 28897, checked in by davidb, 10 years ago

GUI front-end to server base plus web page content

File size: 6.5 KB
Line 
1/**
2 * @author WestLangley / https://github.com/WestLangley
3 * @author zz85 / https://github.com/zz85
4 * @author miningold / https://github.com/miningold
5 *
6 * Modified from the TorusKnotGeometry by @oosmoxiecode
7 *
8 * Creates a tube which extrudes along a 3d spline
9 *
10 * Uses parallel transport frames as described in
11 * http://www.cs.indiana.edu/pub/techreports/TR425.pdf
12 */
13
14THREE.TubeGeometry = function( path, segments, radius, radialSegments, closed ) {
15
16 THREE.Geometry.call( this );
17
18 this.path = path;
19 this.segments = segments || 64;
20 this.radius = radius || 1;
21 this.radialSegments = radialSegments || 8;
22 this.closed = closed || false;
23
24 this.grid = [];
25
26 var scope = this,
27
28 tangent,
29 normal,
30 binormal,
31
32 numpoints = this.segments + 1,
33
34 x, y, z,
35 tx, ty, tz,
36 u, v,
37
38 cx, cy,
39 pos, pos2 = new THREE.Vector3(),
40 i, j,
41 ip, jp,
42 a, b, c, d,
43 uva, uvb, uvc, uvd;
44
45 var frames = new THREE.TubeGeometry.FrenetFrames( this.path, this.segments, this.closed ),
46 tangents = frames.tangents,
47 normals = frames.normals,
48 binormals = frames.binormals;
49
50 // proxy internals
51 this.tangents = tangents;
52 this.normals = normals;
53 this.binormals = binormals;
54
55 function vert( x, y, z ) {
56
57 return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1;
58
59 }
60
61
62 // consruct the grid
63
64 for ( i = 0; i < numpoints; i++ ) {
65
66 this.grid[ i ] = [];
67
68 u = i / ( numpoints - 1 );
69
70 pos = path.getPointAt( u );
71
72 tangent = tangents[ i ];
73 normal = normals[ i ];
74 binormal = binormals[ i ];
75
76 for ( j = 0; j < this.radialSegments; j++ ) {
77
78 v = j / this.radialSegments * 2 * Math.PI;
79
80 cx = -this.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
81 cy = this.radius * Math.sin( v );
82
83 pos2.copy( pos );
84 pos2.x += cx * normal.x + cy * binormal.x;
85 pos2.y += cx * normal.y + cy * binormal.y;
86 pos2.z += cx * normal.z + cy * binormal.z;
87
88 this.grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z );
89
90 }
91 }
92
93
94 // construct the mesh
95
96 for ( i = 0; i < this.segments; i++ ) {
97
98 for ( j = 0; j < this.radialSegments; j++ ) {
99
100 ip = ( this.closed ) ? (i + 1) % this.segments : i + 1;
101 jp = (j + 1) % this.radialSegments;
102
103 a = this.grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! ***
104 b = this.grid[ ip ][ j ];
105 c = this.grid[ ip ][ jp ];
106 d = this.grid[ i ][ jp ];
107
108 uva = new THREE.Vector2( i / this.segments, j / this.radialSegments );
109 uvb = new THREE.Vector2( ( i + 1 ) / this.segments, j / this.radialSegments );
110 uvc = new THREE.Vector2( ( i + 1 ) / this.segments, ( j + 1 ) / this.radialSegments );
111 uvd = new THREE.Vector2( i / this.segments, ( j + 1 ) / this.radialSegments );
112
113 this.faces.push( new THREE.Face3( a, b, d ) );
114 this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );
115
116 this.faces.push( new THREE.Face3( b, c, d ) );
117 this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );
118
119 }
120 }
121
122 this.computeCentroids();
123 this.computeFaceNormals();
124 this.computeVertexNormals();
125
126};
127
128THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype );
129
130
131// For computing of Frenet frames, exposing the tangents, normals and binormals the spline
132THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) {
133
134 var tangent = new THREE.Vector3(),
135 normal = new THREE.Vector3(),
136 binormal = new THREE.Vector3(),
137
138 tangents = [],
139 normals = [],
140 binormals = [],
141
142 vec = new THREE.Vector3(),
143 mat = new THREE.Matrix4(),
144
145 numpoints = segments + 1,
146 theta,
147 epsilon = 0.0001,
148 smallest,
149
150 tx, ty, tz,
151 i, u, v;
152
153
154 // expose internals
155 this.tangents = tangents;
156 this.normals = normals;
157 this.binormals = binormals;
158
159 // compute the tangent vectors for each segment on the path
160
161 for ( i = 0; i < numpoints; i++ ) {
162
163 u = i / ( numpoints - 1 );
164
165 tangents[ i ] = path.getTangentAt( u );
166 tangents[ i ].normalize();
167
168 }
169
170 initialNormal3();
171
172 function initialNormal1(lastBinormal) {
173 // fixed start binormal. Has dangers of 0 vectors
174 normals[ 0 ] = new THREE.Vector3();
175 binormals[ 0 ] = new THREE.Vector3();
176 if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 );
177 normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize();
178 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize();
179 }
180
181 function initialNormal2() {
182
183 // This uses the Frenet-Serret formula for deriving binormal
184 var t2 = path.getTangentAt( epsilon );
185
186 normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize();
187 binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] );
188
189 normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent
190 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize();
191
192 }
193
194 function initialNormal3() {
195 // select an initial normal vector perpenicular to the first tangent vector,
196 // and in the direction of the smallest tangent xyz component
197
198 normals[ 0 ] = new THREE.Vector3();
199 binormals[ 0 ] = new THREE.Vector3();
200 smallest = Number.MAX_VALUE;
201 tx = Math.abs( tangents[ 0 ].x );
202 ty = Math.abs( tangents[ 0 ].y );
203 tz = Math.abs( tangents[ 0 ].z );
204
205 if ( tx <= smallest ) {
206 smallest = tx;
207 normal.set( 1, 0, 0 );
208 }
209
210 if ( ty <= smallest ) {
211 smallest = ty;
212 normal.set( 0, 1, 0 );
213 }
214
215 if ( tz <= smallest ) {
216 normal.set( 0, 0, 1 );
217 }
218
219 vec.crossVectors( tangents[ 0 ], normal ).normalize();
220
221 normals[ 0 ].crossVectors( tangents[ 0 ], vec );
222 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
223 }
224
225
226 // compute the slowly-varying normal and binormal vectors for each segment on the path
227
228 for ( i = 1; i < numpoints; i++ ) {
229
230 normals[ i ] = normals[ i-1 ].clone();
231
232 binormals[ i ] = binormals[ i-1 ].clone();
233
234 vec.crossVectors( tangents[ i-1 ], tangents[ i ] );
235
236 if ( vec.length() > epsilon ) {
237
238 vec.normalize();
239
240 theta = Math.acos( THREE.Math.clamp( tangents[ i-1 ].dot( tangents[ i ] ), -1, 1 ) ); // clamp for floating pt errors
241
242 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
243
244 }
245
246 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
247
248 }
249
250
251 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
252
253 if ( closed ) {
254
255 theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints-1 ] ), -1, 1 ) );
256 theta /= ( numpoints - 1 );
257
258 if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) {
259
260 theta = -theta;
261
262 }
263
264 for ( i = 1; i < numpoints; i++ ) {
265
266 // twist a little...
267 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
268 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
269
270 }
271
272 }
273};
Note: See TracBrowser for help on using the repository browser.