UNPKG

7 kBJavaScriptView Raw
1/**
2 * @author clockworkgeek / https://github.com/clockworkgeek
3 * @author timothypratley / https://github.com/timothypratley
4 * @author WestLangley / http://github.com/WestLangley
5 * @author Mugen87 / https://github.com/Mugen87
6 */
7
8import { Geometry } from '../core/Geometry.js';
9import { BufferGeometry } from '../core/BufferGeometry.js';
10import { Float32BufferAttribute } from '../core/BufferAttribute.js';
11import { Vector3 } from '../math/Vector3.js';
12import { Vector2 } from '../math/Vector2.js';
13
14// PolyhedronGeometry
15
16function PolyhedronGeometry( vertices, indices, radius, detail ) {
17
18 Geometry.call( this );
19
20 this.type = 'PolyhedronGeometry';
21
22 this.parameters = {
23 vertices: vertices,
24 indices: indices,
25 radius: radius,
26 detail: detail
27 };
28
29 this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
30 this.mergeVertices();
31
32}
33
34PolyhedronGeometry.prototype = Object.create( Geometry.prototype );
35PolyhedronGeometry.prototype.constructor = PolyhedronGeometry;
36
37// PolyhedronBufferGeometry
38
39function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
40
41 BufferGeometry.call( this );
42
43 this.type = 'PolyhedronBufferGeometry';
44
45 this.parameters = {
46 vertices: vertices,
47 indices: indices,
48 radius: radius,
49 detail: detail
50 };
51
52 radius = radius || 1;
53 detail = detail || 0;
54
55 // default buffer data
56
57 var vertexBuffer = [];
58 var uvBuffer = [];
59
60 // the subdivision creates the vertex buffer data
61
62 subdivide( detail );
63
64 // all vertices should lie on a conceptual sphere with a given radius
65
66 appplyRadius( radius );
67
68 // finally, create the uv data
69
70 generateUVs();
71
72 // build non-indexed geometry
73
74 this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
75 this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
76 this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
77
78 if ( detail === 0 ) {
79
80 this.computeVertexNormals(); // flat normals
81
82 } else {
83
84 this.normalizeNormals(); // smooth normals
85
86 }
87
88 // helper functions
89
90 function subdivide( detail ) {
91
92 var a = new Vector3();
93 var b = new Vector3();
94 var c = new Vector3();
95
96 // iterate over all faces and apply a subdivison with the given detail value
97
98 for ( var i = 0; i < indices.length; i += 3 ) {
99
100 // get the vertices of the face
101
102 getVertexByIndex( indices[ i + 0 ], a );
103 getVertexByIndex( indices[ i + 1 ], b );
104 getVertexByIndex( indices[ i + 2 ], c );
105
106 // perform subdivision
107
108 subdivideFace( a, b, c, detail );
109
110 }
111
112 }
113
114 function subdivideFace( a, b, c, detail ) {
115
116 var cols = Math.pow( 2, detail );
117
118 // we use this multidimensional array as a data structure for creating the subdivision
119
120 var v = [];
121
122 var i, j;
123
124 // construct all of the vertices for this subdivision
125
126 for ( i = 0; i <= cols; i ++ ) {
127
128 v[ i ] = [];
129
130 var aj = a.clone().lerp( c, i / cols );
131 var bj = b.clone().lerp( c, i / cols );
132
133 var rows = cols - i;
134
135 for ( j = 0; j <= rows; j ++ ) {
136
137 if ( j === 0 && i === cols ) {
138
139 v[ i ][ j ] = aj;
140
141 } else {
142
143 v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
144
145 }
146
147 }
148
149 }
150
151 // construct all of the faces
152
153 for ( i = 0; i < cols; i ++ ) {
154
155 for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
156
157 var k = Math.floor( j / 2 );
158
159 if ( j % 2 === 0 ) {
160
161 pushVertex( v[ i ][ k + 1 ] );
162 pushVertex( v[ i + 1 ][ k ] );
163 pushVertex( v[ i ][ k ] );
164
165 } else {
166
167 pushVertex( v[ i ][ k + 1 ] );
168 pushVertex( v[ i + 1 ][ k + 1 ] );
169 pushVertex( v[ i + 1 ][ k ] );
170
171 }
172
173 }
174
175 }
176
177 }
178
179 function appplyRadius( radius ) {
180
181 var vertex = new Vector3();
182
183 // iterate over the entire buffer and apply the radius to each vertex
184
185 for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
186
187 vertex.x = vertexBuffer[ i + 0 ];
188 vertex.y = vertexBuffer[ i + 1 ];
189 vertex.z = vertexBuffer[ i + 2 ];
190
191 vertex.normalize().multiplyScalar( radius );
192
193 vertexBuffer[ i + 0 ] = vertex.x;
194 vertexBuffer[ i + 1 ] = vertex.y;
195 vertexBuffer[ i + 2 ] = vertex.z;
196
197 }
198
199 }
200
201 function generateUVs() {
202
203 var vertex = new Vector3();
204
205 for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
206
207 vertex.x = vertexBuffer[ i + 0 ];
208 vertex.y = vertexBuffer[ i + 1 ];
209 vertex.z = vertexBuffer[ i + 2 ];
210
211 var u = azimuth( vertex ) / 2 / Math.PI + 0.5;
212 var v = inclination( vertex ) / Math.PI + 0.5;
213 uvBuffer.push( u, 1 - v );
214
215 }
216
217 correctUVs();
218
219 correctSeam();
220
221 }
222
223 function correctSeam() {
224
225 // handle case when face straddles the seam, see #3269
226
227 for ( var i = 0; i < uvBuffer.length; i += 6 ) {
228
229 // uv data of a single face
230
231 var x0 = uvBuffer[ i + 0 ];
232 var x1 = uvBuffer[ i + 2 ];
233 var x2 = uvBuffer[ i + 4 ];
234
235 var max = Math.max( x0, x1, x2 );
236 var min = Math.min( x0, x1, x2 );
237
238 // 0.9 is somewhat arbitrary
239
240 if ( max > 0.9 && min < 0.1 ) {
241
242 if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
243 if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
244 if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
245
246 }
247
248 }
249
250 }
251
252 function pushVertex( vertex ) {
253
254 vertexBuffer.push( vertex.x, vertex.y, vertex.z );
255
256 }
257
258 function getVertexByIndex( index, vertex ) {
259
260 var stride = index * 3;
261
262 vertex.x = vertices[ stride + 0 ];
263 vertex.y = vertices[ stride + 1 ];
264 vertex.z = vertices[ stride + 2 ];
265
266 }
267
268 function correctUVs() {
269
270 var a = new Vector3();
271 var b = new Vector3();
272 var c = new Vector3();
273
274 var centroid = new Vector3();
275
276 var uvA = new Vector2();
277 var uvB = new Vector2();
278 var uvC = new Vector2();
279
280 for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
281
282 a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
283 b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
284 c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
285
286 uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
287 uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
288 uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
289
290 centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
291
292 var azi = azimuth( centroid );
293
294 correctUV( uvA, j + 0, a, azi );
295 correctUV( uvB, j + 2, b, azi );
296 correctUV( uvC, j + 4, c, azi );
297
298 }
299
300 }
301
302 function correctUV( uv, stride, vector, azimuth ) {
303
304 if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
305
306 uvBuffer[ stride ] = uv.x - 1;
307
308 }
309
310 if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
311
312 uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
313
314 }
315
316 }
317
318 // Angle around the Y axis, counter-clockwise when looking from above.
319
320 function azimuth( vector ) {
321
322 return Math.atan2( vector.z, - vector.x );
323
324 }
325
326
327 // Angle above the XZ plane.
328
329 function inclination( vector ) {
330
331 return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
332
333 }
334
335}
336
337PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
338PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;
339
340
341export { PolyhedronGeometry, PolyhedronBufferGeometry };