UNPKG

24.4 kBJavaScriptView Raw
1import { Vector3 } from '../math/Vector3.js';
2import { Box3 } from '../math/Box3.js';
3import { EventDispatcher } from './EventDispatcher.js';
4import { BufferAttribute, Float32BufferAttribute, Uint16BufferAttribute, Uint32BufferAttribute } from './BufferAttribute.js';
5import { Sphere } from '../math/Sphere.js';
6import { DirectGeometry } from './DirectGeometry.js';
7import { Object3D } from './Object3D.js';
8import { Matrix4 } from '../math/Matrix4.js';
9import { Matrix3 } from '../math/Matrix3.js';
10import { MathUtils } from '../math/MathUtils.js';
11import { arrayMax } from '../utils.js';
12
13let _bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id
14
15const _m1 = new Matrix4();
16const _obj = new Object3D();
17const _offset = new Vector3();
18const _box = new Box3();
19const _boxMorphTargets = new Box3();
20const _vector = new Vector3();
21
22function 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
48BufferGeometry.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 // rotate geometry around world x-axis
174
175 _m1.makeRotationX( angle );
176
177 this.applyMatrix4( _m1 );
178
179 return this;
180
181 },
182
183 rotateY: function ( angle ) {
184
185 // rotate geometry around world y-axis
186
187 _m1.makeRotationY( angle );
188
189 this.applyMatrix4( _m1 );
190
191 return this;
192
193 },
194
195 rotateZ: function ( angle ) {
196
197 // rotate geometry around world z-axis
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 // translate geometry
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 // scale geometry
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 // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
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 // groups
487
488 this.groups = geometry.groups;
489
490 // morphs
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 // skinning
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 // process morph attributes if present
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 // first, find the center of the bounding sphere
617
618 const center = this.boundingSphere.center;
619
620 _box.setFromBufferAttribute( position );
621
622 // process morph attributes if present
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 // second, try to find a boundingSphere with a radius smaller than the
653 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
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 // process morph attributes if present
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 // backwards compatibility
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 // reset existing normals to zero
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 // indexed elements
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 // non-indexed elements (unconnected triangle soup)
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 // attributes
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 // morph attributes
921
922 const morphAttributes = this.morphAttributes;
923
924 for ( const name in morphAttributes ) {
925
926 const morphArray = [];
927 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
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 // groups
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 // standard BufferGeometry serialization
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 // Handle primitives
1083
1084 const parameters = this.parameters;
1085
1086 if ( parameters !== undefined ) {
1087
1088 const values = [];
1089
1090 for ( const key in parameters ) {
1091
1092 values.push( parameters[ key ] );
1093
1094 }
1095
1096 const geometry = Object.create( this.constructor.prototype );
1097 this.constructor.apply( geometry, values );
1098 return geometry;
1099
1100 }
1101
1102 return new this.constructor().copy( this );
1103 */
1104
1105 return new BufferGeometry().copy( this );
1106
1107 },
1108
1109 copy: function ( source ) {
1110
1111 // reset
1112
1113 this.index = null;
1114 this.attributes = {};
1115 this.morphAttributes = {};
1116 this.groups = [];
1117 this.boundingBox = null;
1118 this.boundingSphere = null;
1119
1120 // used for storing cloned, shared data
1121
1122 const data = {};
1123
1124 // name
1125
1126 this.name = source.name;
1127
1128 // index
1129
1130 const index = source.index;
1131
1132 if ( index !== null ) {
1133
1134 this.setIndex( index.clone( data ) );
1135
1136 }
1137
1138 // attributes
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 // morph attributes
1150
1151 const morphAttributes = source.morphAttributes;
1152
1153 for ( const name in morphAttributes ) {
1154
1155 const array = [];
1156 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
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 // groups
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 // bounding box
1182
1183 const boundingBox = source.boundingBox;
1184
1185 if ( boundingBox !== null ) {
1186
1187 this.boundingBox = boundingBox.clone();
1188
1189 }
1190
1191 // bounding sphere
1192
1193 const boundingSphere = source.boundingSphere;
1194
1195 if ( boundingSphere !== null ) {
1196
1197 this.boundingSphere = boundingSphere.clone();
1198
1199 }
1200
1201 // draw range
1202
1203 this.drawRange.start = source.drawRange.start;
1204 this.drawRange.count = source.drawRange.count;
1205
1206 // user data
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
1223export { BufferGeometry };