1 | import { Vector3 } from '../math/Vector3.js';
|
2 | import { Box3 } from '../math/Box3.js';
|
3 | import { EventDispatcher } from './EventDispatcher.js';
|
4 | import { BufferAttribute, Float32BufferAttribute, Uint16BufferAttribute, Uint32BufferAttribute } from './BufferAttribute.js';
|
5 | import { Sphere } from '../math/Sphere.js';
|
6 | import { DirectGeometry } from './DirectGeometry.js';
|
7 | import { Object3D } from './Object3D.js';
|
8 | import { Matrix4 } from '../math/Matrix4.js';
|
9 | import { Matrix3 } from '../math/Matrix3.js';
|
10 | import { MathUtils } from '../math/MathUtils.js';
|
11 | import { arrayMax } from '../utils.js';
|
12 |
|
13 | let _bufferGeometryId = 1;
|
14 |
|
15 | const _m1 = new Matrix4();
|
16 | const _obj = new Object3D();
|
17 | const _offset = new Vector3();
|
18 | const _box = new Box3();
|
19 | const _boxMorphTargets = new Box3();
|
20 | const _vector = new Vector3();
|
21 |
|
22 | function BufferGeometry() {
|
23 |
|
24 | Object.defineProperty( this, 'id', { value: _bufferGeometryId += 2 } );
|
25 |
|
26 | this.uuid = MathUtils.generateUUID();
|
27 |
|
28 | this.name = '';
|
29 | this.type = 'BufferGeometry';
|
30 |
|
31 | this.index = null;
|
32 | this.attributes = {};
|
33 |
|
34 | this.morphAttributes = {};
|
35 | this.morphTargetsRelative = false;
|
36 |
|
37 | this.groups = [];
|
38 |
|
39 | this.boundingBox = null;
|
40 | this.boundingSphere = null;
|
41 |
|
42 | this.drawRange = { start: 0, count: Infinity };
|
43 |
|
44 | this.userData = {};
|
45 |
|
46 | }
|
47 |
|
48 | BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
|
49 |
|
50 | constructor: BufferGeometry,
|
51 |
|
52 | isBufferGeometry: true,
|
53 |
|
54 | getIndex: function () {
|
55 |
|
56 | return this.index;
|
57 |
|
58 | },
|
59 |
|
60 | setIndex: function ( index ) {
|
61 |
|
62 | if ( Array.isArray( index ) ) {
|
63 |
|
64 | this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
|
65 |
|
66 | } else {
|
67 |
|
68 | this.index = index;
|
69 |
|
70 | }
|
71 |
|
72 | },
|
73 |
|
74 | getAttribute: function ( name ) {
|
75 |
|
76 | return this.attributes[ name ];
|
77 |
|
78 | },
|
79 |
|
80 | setAttribute: function ( name, attribute ) {
|
81 |
|
82 | this.attributes[ name ] = attribute;
|
83 |
|
84 | return this;
|
85 |
|
86 | },
|
87 |
|
88 | deleteAttribute: function ( name ) {
|
89 |
|
90 | delete this.attributes[ name ];
|
91 |
|
92 | return this;
|
93 |
|
94 | },
|
95 |
|
96 | addGroup: function ( start, count, materialIndex ) {
|
97 |
|
98 | this.groups.push( {
|
99 |
|
100 | start: start,
|
101 | count: count,
|
102 | materialIndex: materialIndex !== undefined ? materialIndex : 0
|
103 |
|
104 | } );
|
105 |
|
106 | },
|
107 |
|
108 | clearGroups: function () {
|
109 |
|
110 | this.groups = [];
|
111 |
|
112 | },
|
113 |
|
114 | setDrawRange: function ( start, count ) {
|
115 |
|
116 | this.drawRange.start = start;
|
117 | this.drawRange.count = count;
|
118 |
|
119 | },
|
120 |
|
121 | applyMatrix4: function ( matrix ) {
|
122 |
|
123 | const position = this.attributes.position;
|
124 |
|
125 | if ( position !== undefined ) {
|
126 |
|
127 | position.applyMatrix4( matrix );
|
128 |
|
129 | position.needsUpdate = true;
|
130 |
|
131 | }
|
132 |
|
133 | const normal = this.attributes.normal;
|
134 |
|
135 | if ( normal !== undefined ) {
|
136 |
|
137 | const normalMatrix = new Matrix3().getNormalMatrix( matrix );
|
138 |
|
139 | normal.applyNormalMatrix( normalMatrix );
|
140 |
|
141 | normal.needsUpdate = true;
|
142 |
|
143 | }
|
144 |
|
145 | const tangent = this.attributes.tangent;
|
146 |
|
147 | if ( tangent !== undefined ) {
|
148 |
|
149 | tangent.transformDirection( matrix );
|
150 |
|
151 | tangent.needsUpdate = true;
|
152 |
|
153 | }
|
154 |
|
155 | if ( this.boundingBox !== null ) {
|
156 |
|
157 | this.computeBoundingBox();
|
158 |
|
159 | }
|
160 |
|
161 | if ( this.boundingSphere !== null ) {
|
162 |
|
163 | this.computeBoundingSphere();
|
164 |
|
165 | }
|
166 |
|
167 | return this;
|
168 |
|
169 | },
|
170 |
|
171 | rotateX: function ( angle ) {
|
172 |
|
173 |
|
174 |
|
175 | _m1.makeRotationX( angle );
|
176 |
|
177 | this.applyMatrix4( _m1 );
|
178 |
|
179 | return this;
|
180 |
|
181 | },
|
182 |
|
183 | rotateY: function ( angle ) {
|
184 |
|
185 |
|
186 |
|
187 | _m1.makeRotationY( angle );
|
188 |
|
189 | this.applyMatrix4( _m1 );
|
190 |
|
191 | return this;
|
192 |
|
193 | },
|
194 |
|
195 | rotateZ: function ( angle ) {
|
196 |
|
197 |
|
198 |
|
199 | _m1.makeRotationZ( angle );
|
200 |
|
201 | this.applyMatrix4( _m1 );
|
202 |
|
203 | return this;
|
204 |
|
205 | },
|
206 |
|
207 | translate: function ( x, y, z ) {
|
208 |
|
209 |
|
210 |
|
211 | _m1.makeTranslation( x, y, z );
|
212 |
|
213 | this.applyMatrix4( _m1 );
|
214 |
|
215 | return this;
|
216 |
|
217 | },
|
218 |
|
219 | scale: function ( x, y, z ) {
|
220 |
|
221 |
|
222 |
|
223 | _m1.makeScale( x, y, z );
|
224 |
|
225 | this.applyMatrix4( _m1 );
|
226 |
|
227 | return this;
|
228 |
|
229 | },
|
230 |
|
231 | lookAt: function ( vector ) {
|
232 |
|
233 | _obj.lookAt( vector );
|
234 |
|
235 | _obj.updateMatrix();
|
236 |
|
237 | this.applyMatrix4( _obj.matrix );
|
238 |
|
239 | return this;
|
240 |
|
241 | },
|
242 |
|
243 | center: function () {
|
244 |
|
245 | this.computeBoundingBox();
|
246 |
|
247 | this.boundingBox.getCenter( _offset ).negate();
|
248 |
|
249 | this.translate( _offset.x, _offset.y, _offset.z );
|
250 |
|
251 | return this;
|
252 |
|
253 | },
|
254 |
|
255 | setFromObject: function ( object ) {
|
256 |
|
257 |
|
258 |
|
259 | const geometry = object.geometry;
|
260 |
|
261 | if ( object.isPoints || object.isLine ) {
|
262 |
|
263 | const positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 );
|
264 | const colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 );
|
265 |
|
266 | this.setAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
|
267 | this.setAttribute( 'color', colors.copyColorsArray( geometry.colors ) );
|
268 |
|
269 | if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {
|
270 |
|
271 | const lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 );
|
272 |
|
273 | this.setAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );
|
274 |
|
275 | }
|
276 |
|
277 | if ( geometry.boundingSphere !== null ) {
|
278 |
|
279 | this.boundingSphere = geometry.boundingSphere.clone();
|
280 |
|
281 | }
|
282 |
|
283 | if ( geometry.boundingBox !== null ) {
|
284 |
|
285 | this.boundingBox = geometry.boundingBox.clone();
|
286 |
|
287 | }
|
288 |
|
289 | } else if ( object.isMesh ) {
|
290 |
|
291 | if ( geometry && geometry.isGeometry ) {
|
292 |
|
293 | this.fromGeometry( geometry );
|
294 |
|
295 | }
|
296 |
|
297 | }
|
298 |
|
299 | return this;
|
300 |
|
301 | },
|
302 |
|
303 | setFromPoints: function ( points ) {
|
304 |
|
305 | const position = [];
|
306 |
|
307 | for ( let i = 0, l = points.length; i < l; i ++ ) {
|
308 |
|
309 | const point = points[ i ];
|
310 | position.push( point.x, point.y, point.z || 0 );
|
311 |
|
312 | }
|
313 |
|
314 | this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
|
315 |
|
316 | return this;
|
317 |
|
318 | },
|
319 |
|
320 | updateFromObject: function ( object ) {
|
321 |
|
322 | let geometry = object.geometry;
|
323 |
|
324 | if ( object.isMesh ) {
|
325 |
|
326 | let direct = geometry.__directGeometry;
|
327 |
|
328 | if ( geometry.elementsNeedUpdate === true ) {
|
329 |
|
330 | direct = undefined;
|
331 | geometry.elementsNeedUpdate = false;
|
332 |
|
333 | }
|
334 |
|
335 | if ( direct === undefined ) {
|
336 |
|
337 | return this.fromGeometry( geometry );
|
338 |
|
339 | }
|
340 |
|
341 | direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
|
342 | direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
|
343 | direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
|
344 | direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
|
345 | direct.groupsNeedUpdate = geometry.groupsNeedUpdate;
|
346 |
|
347 | geometry.verticesNeedUpdate = false;
|
348 | geometry.normalsNeedUpdate = false;
|
349 | geometry.colorsNeedUpdate = false;
|
350 | geometry.uvsNeedUpdate = false;
|
351 | geometry.groupsNeedUpdate = false;
|
352 |
|
353 | geometry = direct;
|
354 |
|
355 | }
|
356 |
|
357 | if ( geometry.verticesNeedUpdate === true ) {
|
358 |
|
359 | const attribute = this.attributes.position;
|
360 |
|
361 | if ( attribute !== undefined ) {
|
362 |
|
363 | attribute.copyVector3sArray( geometry.vertices );
|
364 | attribute.needsUpdate = true;
|
365 |
|
366 | }
|
367 |
|
368 | geometry.verticesNeedUpdate = false;
|
369 |
|
370 | }
|
371 |
|
372 | if ( geometry.normalsNeedUpdate === true ) {
|
373 |
|
374 | const attribute = this.attributes.normal;
|
375 |
|
376 | if ( attribute !== undefined ) {
|
377 |
|
378 | attribute.copyVector3sArray( geometry.normals );
|
379 | attribute.needsUpdate = true;
|
380 |
|
381 | }
|
382 |
|
383 | geometry.normalsNeedUpdate = false;
|
384 |
|
385 | }
|
386 |
|
387 | if ( geometry.colorsNeedUpdate === true ) {
|
388 |
|
389 | const attribute = this.attributes.color;
|
390 |
|
391 | if ( attribute !== undefined ) {
|
392 |
|
393 | attribute.copyColorsArray( geometry.colors );
|
394 | attribute.needsUpdate = true;
|
395 |
|
396 | }
|
397 |
|
398 | geometry.colorsNeedUpdate = false;
|
399 |
|
400 | }
|
401 |
|
402 | if ( geometry.uvsNeedUpdate ) {
|
403 |
|
404 | const attribute = this.attributes.uv;
|
405 |
|
406 | if ( attribute !== undefined ) {
|
407 |
|
408 | attribute.copyVector2sArray( geometry.uvs );
|
409 | attribute.needsUpdate = true;
|
410 |
|
411 | }
|
412 |
|
413 | geometry.uvsNeedUpdate = false;
|
414 |
|
415 | }
|
416 |
|
417 | if ( geometry.lineDistancesNeedUpdate ) {
|
418 |
|
419 | const attribute = this.attributes.lineDistance;
|
420 |
|
421 | if ( attribute !== undefined ) {
|
422 |
|
423 | attribute.copyArray( geometry.lineDistances );
|
424 | attribute.needsUpdate = true;
|
425 |
|
426 | }
|
427 |
|
428 | geometry.lineDistancesNeedUpdate = false;
|
429 |
|
430 | }
|
431 |
|
432 | if ( geometry.groupsNeedUpdate ) {
|
433 |
|
434 | geometry.computeGroups( object.geometry );
|
435 | this.groups = geometry.groups;
|
436 |
|
437 | geometry.groupsNeedUpdate = false;
|
438 |
|
439 | }
|
440 |
|
441 | return this;
|
442 |
|
443 | },
|
444 |
|
445 | fromGeometry: function ( geometry ) {
|
446 |
|
447 | geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry );
|
448 |
|
449 | return this.fromDirectGeometry( geometry.__directGeometry );
|
450 |
|
451 | },
|
452 |
|
453 | fromDirectGeometry: function ( geometry ) {
|
454 |
|
455 | const positions = new Float32Array( geometry.vertices.length * 3 );
|
456 | this.setAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
|
457 |
|
458 | if ( geometry.normals.length > 0 ) {
|
459 |
|
460 | const normals = new Float32Array( geometry.normals.length * 3 );
|
461 | this.setAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );
|
462 |
|
463 | }
|
464 |
|
465 | if ( geometry.colors.length > 0 ) {
|
466 |
|
467 | const colors = new Float32Array( geometry.colors.length * 3 );
|
468 | this.setAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );
|
469 |
|
470 | }
|
471 |
|
472 | if ( geometry.uvs.length > 0 ) {
|
473 |
|
474 | const uvs = new Float32Array( geometry.uvs.length * 2 );
|
475 | this.setAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );
|
476 |
|
477 | }
|
478 |
|
479 | if ( geometry.uvs2.length > 0 ) {
|
480 |
|
481 | const uvs2 = new Float32Array( geometry.uvs2.length * 2 );
|
482 | this.setAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );
|
483 |
|
484 | }
|
485 |
|
486 |
|
487 |
|
488 | this.groups = geometry.groups;
|
489 |
|
490 |
|
491 |
|
492 | for ( const name in geometry.morphTargets ) {
|
493 |
|
494 | const array = [];
|
495 | const morphTargets = geometry.morphTargets[ name ];
|
496 |
|
497 | for ( let i = 0, l = morphTargets.length; i < l; i ++ ) {
|
498 |
|
499 | const morphTarget = morphTargets[ i ];
|
500 |
|
501 | const attribute = new Float32BufferAttribute( morphTarget.data.length * 3, 3 );
|
502 | attribute.name = morphTarget.name;
|
503 |
|
504 | array.push( attribute.copyVector3sArray( morphTarget.data ) );
|
505 |
|
506 | }
|
507 |
|
508 | this.morphAttributes[ name ] = array;
|
509 |
|
510 | }
|
511 |
|
512 |
|
513 |
|
514 | if ( geometry.skinIndices.length > 0 ) {
|
515 |
|
516 | const skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 );
|
517 | this.setAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );
|
518 |
|
519 | }
|
520 |
|
521 | if ( geometry.skinWeights.length > 0 ) {
|
522 |
|
523 | const skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 );
|
524 | this.setAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );
|
525 |
|
526 | }
|
527 |
|
528 |
|
529 |
|
530 | if ( geometry.boundingSphere !== null ) {
|
531 |
|
532 | this.boundingSphere = geometry.boundingSphere.clone();
|
533 |
|
534 | }
|
535 |
|
536 | if ( geometry.boundingBox !== null ) {
|
537 |
|
538 | this.boundingBox = geometry.boundingBox.clone();
|
539 |
|
540 | }
|
541 |
|
542 | return this;
|
543 |
|
544 | },
|
545 |
|
546 | computeBoundingBox: function () {
|
547 |
|
548 | if ( this.boundingBox === null ) {
|
549 |
|
550 | this.boundingBox = new Box3();
|
551 |
|
552 | }
|
553 |
|
554 | const position = this.attributes.position;
|
555 | const morphAttributesPosition = this.morphAttributes.position;
|
556 |
|
557 | if ( position !== undefined ) {
|
558 |
|
559 | this.boundingBox.setFromBufferAttribute( position );
|
560 |
|
561 |
|
562 |
|
563 | if ( morphAttributesPosition ) {
|
564 |
|
565 | for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
|
566 |
|
567 | const morphAttribute = morphAttributesPosition[ i ];
|
568 | _box.setFromBufferAttribute( morphAttribute );
|
569 |
|
570 | if ( this.morphTargetsRelative ) {
|
571 |
|
572 | _vector.addVectors( this.boundingBox.min, _box.min );
|
573 | this.boundingBox.expandByPoint( _vector );
|
574 |
|
575 | _vector.addVectors( this.boundingBox.max, _box.max );
|
576 | this.boundingBox.expandByPoint( _vector );
|
577 |
|
578 | } else {
|
579 |
|
580 | this.boundingBox.expandByPoint( _box.min );
|
581 | this.boundingBox.expandByPoint( _box.max );
|
582 |
|
583 | }
|
584 |
|
585 | }
|
586 |
|
587 | }
|
588 |
|
589 | } else {
|
590 |
|
591 | this.boundingBox.makeEmpty();
|
592 |
|
593 | }
|
594 |
|
595 | if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
|
596 |
|
597 | console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
|
598 |
|
599 | }
|
600 |
|
601 | },
|
602 |
|
603 | computeBoundingSphere: function () {
|
604 |
|
605 | if ( this.boundingSphere === null ) {
|
606 |
|
607 | this.boundingSphere = new Sphere();
|
608 |
|
609 | }
|
610 |
|
611 | const position = this.attributes.position;
|
612 | const morphAttributesPosition = this.morphAttributes.position;
|
613 |
|
614 | if ( position ) {
|
615 |
|
616 |
|
617 |
|
618 | const center = this.boundingSphere.center;
|
619 |
|
620 | _box.setFromBufferAttribute( position );
|
621 |
|
622 |
|
623 |
|
624 | if ( morphAttributesPosition ) {
|
625 |
|
626 | for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
|
627 |
|
628 | const morphAttribute = morphAttributesPosition[ i ];
|
629 | _boxMorphTargets.setFromBufferAttribute( morphAttribute );
|
630 |
|
631 | if ( this.morphTargetsRelative ) {
|
632 |
|
633 | _vector.addVectors( _box.min, _boxMorphTargets.min );
|
634 | _box.expandByPoint( _vector );
|
635 |
|
636 | _vector.addVectors( _box.max, _boxMorphTargets.max );
|
637 | _box.expandByPoint( _vector );
|
638 |
|
639 | } else {
|
640 |
|
641 | _box.expandByPoint( _boxMorphTargets.min );
|
642 | _box.expandByPoint( _boxMorphTargets.max );
|
643 |
|
644 | }
|
645 |
|
646 | }
|
647 |
|
648 | }
|
649 |
|
650 | _box.getCenter( center );
|
651 |
|
652 |
|
653 |
|
654 |
|
655 | let maxRadiusSq = 0;
|
656 |
|
657 | for ( let i = 0, il = position.count; i < il; i ++ ) {
|
658 |
|
659 | _vector.fromBufferAttribute( position, i );
|
660 |
|
661 | maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) );
|
662 |
|
663 | }
|
664 |
|
665 |
|
666 |
|
667 | if ( morphAttributesPosition ) {
|
668 |
|
669 | for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
|
670 |
|
671 | const morphAttribute = morphAttributesPosition[ i ];
|
672 | const morphTargetsRelative = this.morphTargetsRelative;
|
673 |
|
674 | for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
|
675 |
|
676 | _vector.fromBufferAttribute( morphAttribute, j );
|
677 |
|
678 | if ( morphTargetsRelative ) {
|
679 |
|
680 | _offset.fromBufferAttribute( position, j );
|
681 | _vector.add( _offset );
|
682 |
|
683 | }
|
684 |
|
685 | maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) );
|
686 |
|
687 | }
|
688 |
|
689 | }
|
690 |
|
691 | }
|
692 |
|
693 | this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
|
694 |
|
695 | if ( isNaN( this.boundingSphere.radius ) ) {
|
696 |
|
697 | console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
|
698 |
|
699 | }
|
700 |
|
701 | }
|
702 |
|
703 | },
|
704 |
|
705 | computeFaceNormals: function () {
|
706 |
|
707 |
|
708 |
|
709 | },
|
710 |
|
711 | computeVertexNormals: function () {
|
712 |
|
713 | const index = this.index;
|
714 | const positionAttribute = this.getAttribute( 'position' );
|
715 |
|
716 | if ( positionAttribute !== undefined ) {
|
717 |
|
718 | let normalAttribute = this.getAttribute( 'normal' );
|
719 |
|
720 | if ( normalAttribute === undefined ) {
|
721 |
|
722 | normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );
|
723 | this.setAttribute( 'normal', normalAttribute );
|
724 |
|
725 | } else {
|
726 |
|
727 |
|
728 |
|
729 | for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {
|
730 |
|
731 | normalAttribute.setXYZ( i, 0, 0, 0 );
|
732 |
|
733 | }
|
734 |
|
735 | }
|
736 |
|
737 | const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
|
738 | const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
|
739 | const cb = new Vector3(), ab = new Vector3();
|
740 |
|
741 |
|
742 |
|
743 | if ( index ) {
|
744 |
|
745 | for ( let i = 0, il = index.count; i < il; i += 3 ) {
|
746 |
|
747 | const vA = index.getX( i + 0 );
|
748 | const vB = index.getX( i + 1 );
|
749 | const vC = index.getX( i + 2 );
|
750 |
|
751 | pA.fromBufferAttribute( positionAttribute, vA );
|
752 | pB.fromBufferAttribute( positionAttribute, vB );
|
753 | pC.fromBufferAttribute( positionAttribute, vC );
|
754 |
|
755 | cb.subVectors( pC, pB );
|
756 | ab.subVectors( pA, pB );
|
757 | cb.cross( ab );
|
758 |
|
759 | nA.fromBufferAttribute( normalAttribute, vA );
|
760 | nB.fromBufferAttribute( normalAttribute, vB );
|
761 | nC.fromBufferAttribute( normalAttribute, vC );
|
762 |
|
763 | nA.add( cb );
|
764 | nB.add( cb );
|
765 | nC.add( cb );
|
766 |
|
767 | normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );
|
768 | normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );
|
769 | normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );
|
770 |
|
771 | }
|
772 |
|
773 | } else {
|
774 |
|
775 |
|
776 |
|
777 | for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {
|
778 |
|
779 | pA.fromBufferAttribute( positionAttribute, i + 0 );
|
780 | pB.fromBufferAttribute( positionAttribute, i + 1 );
|
781 | pC.fromBufferAttribute( positionAttribute, i + 2 );
|
782 |
|
783 | cb.subVectors( pC, pB );
|
784 | ab.subVectors( pA, pB );
|
785 | cb.cross( ab );
|
786 |
|
787 | normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );
|
788 | normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );
|
789 | normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );
|
790 |
|
791 | }
|
792 |
|
793 | }
|
794 |
|
795 | this.normalizeNormals();
|
796 |
|
797 | normalAttribute.needsUpdate = true;
|
798 |
|
799 | }
|
800 |
|
801 | },
|
802 |
|
803 | merge: function ( geometry, offset ) {
|
804 |
|
805 | if ( ! ( geometry && geometry.isBufferGeometry ) ) {
|
806 |
|
807 | console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
|
808 | return;
|
809 |
|
810 | }
|
811 |
|
812 | if ( offset === undefined ) {
|
813 |
|
814 | offset = 0;
|
815 |
|
816 | console.warn(
|
817 | 'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. '
|
818 | + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.'
|
819 | );
|
820 |
|
821 | }
|
822 |
|
823 | const attributes = this.attributes;
|
824 |
|
825 | for ( const key in attributes ) {
|
826 |
|
827 | if ( geometry.attributes[ key ] === undefined ) continue;
|
828 |
|
829 | const attribute1 = attributes[ key ];
|
830 | const attributeArray1 = attribute1.array;
|
831 |
|
832 | const attribute2 = geometry.attributes[ key ];
|
833 | const attributeArray2 = attribute2.array;
|
834 |
|
835 | const attributeOffset = attribute2.itemSize * offset;
|
836 | const length = Math.min( attributeArray2.length, attributeArray1.length - attributeOffset );
|
837 |
|
838 | for ( let i = 0, j = attributeOffset; i < length; i ++, j ++ ) {
|
839 |
|
840 | attributeArray1[ j ] = attributeArray2[ i ];
|
841 |
|
842 | }
|
843 |
|
844 | }
|
845 |
|
846 | return this;
|
847 |
|
848 | },
|
849 |
|
850 | normalizeNormals: function () {
|
851 |
|
852 | const normals = this.attributes.normal;
|
853 |
|
854 | for ( let i = 0, il = normals.count; i < il; i ++ ) {
|
855 |
|
856 | _vector.fromBufferAttribute( normals, i );
|
857 |
|
858 | _vector.normalize();
|
859 |
|
860 | normals.setXYZ( i, _vector.x, _vector.y, _vector.z );
|
861 |
|
862 | }
|
863 |
|
864 | },
|
865 |
|
866 | toNonIndexed: function () {
|
867 |
|
868 | function convertBufferAttribute( attribute, indices ) {
|
869 |
|
870 | const array = attribute.array;
|
871 | const itemSize = attribute.itemSize;
|
872 | const normalized = attribute.normalized;
|
873 |
|
874 | const array2 = new array.constructor( indices.length * itemSize );
|
875 |
|
876 | let index = 0, index2 = 0;
|
877 |
|
878 | for ( let i = 0, l = indices.length; i < l; i ++ ) {
|
879 |
|
880 | index = indices[ i ] * itemSize;
|
881 |
|
882 | for ( let j = 0; j < itemSize; j ++ ) {
|
883 |
|
884 | array2[ index2 ++ ] = array[ index ++ ];
|
885 |
|
886 | }
|
887 |
|
888 | }
|
889 |
|
890 | return new BufferAttribute( array2, itemSize, normalized );
|
891 |
|
892 | }
|
893 |
|
894 |
|
895 |
|
896 | if ( this.index === null ) {
|
897 |
|
898 | console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' );
|
899 | return this;
|
900 |
|
901 | }
|
902 |
|
903 | const geometry2 = new BufferGeometry();
|
904 |
|
905 | const indices = this.index.array;
|
906 | const attributes = this.attributes;
|
907 |
|
908 |
|
909 |
|
910 | for ( const name in attributes ) {
|
911 |
|
912 | const attribute = attributes[ name ];
|
913 |
|
914 | const newAttribute = convertBufferAttribute( attribute, indices );
|
915 |
|
916 | geometry2.setAttribute( name, newAttribute );
|
917 |
|
918 | }
|
919 |
|
920 |
|
921 |
|
922 | const morphAttributes = this.morphAttributes;
|
923 |
|
924 | for ( const name in morphAttributes ) {
|
925 |
|
926 | const morphArray = [];
|
927 | const morphAttribute = morphAttributes[ name ];
|
928 |
|
929 | for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
|
930 |
|
931 | const attribute = morphAttribute[ i ];
|
932 |
|
933 | const newAttribute = convertBufferAttribute( attribute, indices );
|
934 |
|
935 | morphArray.push( newAttribute );
|
936 |
|
937 | }
|
938 |
|
939 | geometry2.morphAttributes[ name ] = morphArray;
|
940 |
|
941 | }
|
942 |
|
943 | geometry2.morphTargetsRelative = this.morphTargetsRelative;
|
944 |
|
945 |
|
946 |
|
947 | const groups = this.groups;
|
948 |
|
949 | for ( let i = 0, l = groups.length; i < l; i ++ ) {
|
950 |
|
951 | const group = groups[ i ];
|
952 | geometry2.addGroup( group.start, group.count, group.materialIndex );
|
953 |
|
954 | }
|
955 |
|
956 | return geometry2;
|
957 |
|
958 | },
|
959 |
|
960 | toJSON: function () {
|
961 |
|
962 | const data = {
|
963 | metadata: {
|
964 | version: 4.5,
|
965 | type: 'BufferGeometry',
|
966 | generator: 'BufferGeometry.toJSON'
|
967 | }
|
968 | };
|
969 |
|
970 |
|
971 |
|
972 | data.uuid = this.uuid;
|
973 | data.type = this.type;
|
974 | if ( this.name !== '' ) data.name = this.name;
|
975 | if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
|
976 |
|
977 | if ( this.parameters !== undefined ) {
|
978 |
|
979 | const parameters = this.parameters;
|
980 |
|
981 | for ( const key in parameters ) {
|
982 |
|
983 | if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
|
984 |
|
985 | }
|
986 |
|
987 | return data;
|
988 |
|
989 | }
|
990 |
|
991 | data.data = { attributes: {} };
|
992 |
|
993 | const index = this.index;
|
994 |
|
995 | if ( index !== null ) {
|
996 |
|
997 | data.data.index = {
|
998 | type: index.array.constructor.name,
|
999 | array: Array.prototype.slice.call( index.array )
|
1000 | };
|
1001 |
|
1002 | }
|
1003 |
|
1004 | const attributes = this.attributes;
|
1005 |
|
1006 | for ( const key in attributes ) {
|
1007 |
|
1008 | const attribute = attributes[ key ];
|
1009 |
|
1010 | const attributeData = attribute.toJSON( data.data );
|
1011 |
|
1012 | if ( attribute.name !== '' ) attributeData.name = attribute.name;
|
1013 |
|
1014 | data.data.attributes[ key ] = attributeData;
|
1015 |
|
1016 | }
|
1017 |
|
1018 | const morphAttributes = {};
|
1019 | let hasMorphAttributes = false;
|
1020 |
|
1021 | for ( const key in this.morphAttributes ) {
|
1022 |
|
1023 | const attributeArray = this.morphAttributes[ key ];
|
1024 |
|
1025 | const array = [];
|
1026 |
|
1027 | for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
|
1028 |
|
1029 | const attribute = attributeArray[ i ];
|
1030 |
|
1031 | const attributeData = attribute.toJSON( data.data );
|
1032 |
|
1033 | if ( attribute.name !== '' ) attributeData.name = attribute.name;
|
1034 |
|
1035 | array.push( attributeData );
|
1036 |
|
1037 | }
|
1038 |
|
1039 | if ( array.length > 0 ) {
|
1040 |
|
1041 | morphAttributes[ key ] = array;
|
1042 |
|
1043 | hasMorphAttributes = true;
|
1044 |
|
1045 | }
|
1046 |
|
1047 | }
|
1048 |
|
1049 | if ( hasMorphAttributes ) {
|
1050 |
|
1051 | data.data.morphAttributes = morphAttributes;
|
1052 | data.data.morphTargetsRelative = this.morphTargetsRelative;
|
1053 |
|
1054 | }
|
1055 |
|
1056 | const groups = this.groups;
|
1057 |
|
1058 | if ( groups.length > 0 ) {
|
1059 |
|
1060 | data.data.groups = JSON.parse( JSON.stringify( groups ) );
|
1061 |
|
1062 | }
|
1063 |
|
1064 | const boundingSphere = this.boundingSphere;
|
1065 |
|
1066 | if ( boundingSphere !== null ) {
|
1067 |
|
1068 | data.data.boundingSphere = {
|
1069 | center: boundingSphere.center.toArray(),
|
1070 | radius: boundingSphere.radius
|
1071 | };
|
1072 |
|
1073 | }
|
1074 |
|
1075 | return data;
|
1076 |
|
1077 | },
|
1078 |
|
1079 | clone: function () {
|
1080 |
|
1081 | |
1082 |
|
1083 |
|
1084 |
|
1085 |
|
1086 |
|
1087 |
|
1088 |
|
1089 |
|
1090 |
|
1091 |
|
1092 |
|
1093 |
|
1094 |
|
1095 |
|
1096 |
|
1097 |
|
1098 |
|
1099 |
|
1100 |
|
1101 |
|
1102 |
|
1103 |
|
1104 |
|
1105 | return new BufferGeometry().copy( this );
|
1106 |
|
1107 | },
|
1108 |
|
1109 | copy: function ( source ) {
|
1110 |
|
1111 |
|
1112 |
|
1113 | this.index = null;
|
1114 | this.attributes = {};
|
1115 | this.morphAttributes = {};
|
1116 | this.groups = [];
|
1117 | this.boundingBox = null;
|
1118 | this.boundingSphere = null;
|
1119 |
|
1120 |
|
1121 |
|
1122 | const data = {};
|
1123 |
|
1124 |
|
1125 |
|
1126 | this.name = source.name;
|
1127 |
|
1128 |
|
1129 |
|
1130 | const index = source.index;
|
1131 |
|
1132 | if ( index !== null ) {
|
1133 |
|
1134 | this.setIndex( index.clone( data ) );
|
1135 |
|
1136 | }
|
1137 |
|
1138 |
|
1139 |
|
1140 | const attributes = source.attributes;
|
1141 |
|
1142 | for ( const name in attributes ) {
|
1143 |
|
1144 | const attribute = attributes[ name ];
|
1145 | this.setAttribute( name, attribute.clone( data ) );
|
1146 |
|
1147 | }
|
1148 |
|
1149 |
|
1150 |
|
1151 | const morphAttributes = source.morphAttributes;
|
1152 |
|
1153 | for ( const name in morphAttributes ) {
|
1154 |
|
1155 | const array = [];
|
1156 | const morphAttribute = morphAttributes[ name ];
|
1157 |
|
1158 | for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {
|
1159 |
|
1160 | array.push( morphAttribute[ i ].clone( data ) );
|
1161 |
|
1162 | }
|
1163 |
|
1164 | this.morphAttributes[ name ] = array;
|
1165 |
|
1166 | }
|
1167 |
|
1168 | this.morphTargetsRelative = source.morphTargetsRelative;
|
1169 |
|
1170 |
|
1171 |
|
1172 | const groups = source.groups;
|
1173 |
|
1174 | for ( let i = 0, l = groups.length; i < l; i ++ ) {
|
1175 |
|
1176 | const group = groups[ i ];
|
1177 | this.addGroup( group.start, group.count, group.materialIndex );
|
1178 |
|
1179 | }
|
1180 |
|
1181 |
|
1182 |
|
1183 | const boundingBox = source.boundingBox;
|
1184 |
|
1185 | if ( boundingBox !== null ) {
|
1186 |
|
1187 | this.boundingBox = boundingBox.clone();
|
1188 |
|
1189 | }
|
1190 |
|
1191 |
|
1192 |
|
1193 | const boundingSphere = source.boundingSphere;
|
1194 |
|
1195 | if ( boundingSphere !== null ) {
|
1196 |
|
1197 | this.boundingSphere = boundingSphere.clone();
|
1198 |
|
1199 | }
|
1200 |
|
1201 |
|
1202 |
|
1203 | this.drawRange.start = source.drawRange.start;
|
1204 | this.drawRange.count = source.drawRange.count;
|
1205 |
|
1206 |
|
1207 |
|
1208 | this.userData = source.userData;
|
1209 |
|
1210 | return this;
|
1211 |
|
1212 | },
|
1213 |
|
1214 | dispose: function () {
|
1215 |
|
1216 | this.dispatchEvent( { type: 'dispose' } );
|
1217 |
|
1218 | }
|
1219 |
|
1220 | } );
|
1221 |
|
1222 |
|
1223 | export { BufferGeometry };
|