11import { BufferGeometry } from '../core/BufferGeometry.js' ;
22import { Float32BufferAttribute } from '../core/BufferAttribute.js' ;
3- import { Geometry } from '../core/Geometry.js' ;
43import { MathUtils } from '../math/MathUtils.js' ;
4+ import { Triangle } from '../math/Triangle.js' ;
5+ import { Vector3 } from '../math/Vector3.js' ;
6+
7+ const _v0 = new Vector3 ( ) ;
8+ const _v1 = new Vector3 ( ) ;
9+ const _normal = new Vector3 ( ) ;
10+ const _triangle = new Triangle ( ) ;
511
612class EdgesGeometry extends BufferGeometry {
713
@@ -17,94 +23,123 @@ class EdgesGeometry extends BufferGeometry {
1723
1824 thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1 ;
1925
20- // buffer
26+ if ( geometry . isGeometry ) {
2127
22- const vertices = [ ] ;
28+ geometry = new BufferGeometry ( ) . fromGeometry ( geometry ) ;
2329
24- // helper variables
30+ }
2531
32+ const precisionPoints = 4 ;
33+ const precision = Math . pow ( 10 , precisionPoints ) ;
2634 const thresholdDot = Math . cos ( MathUtils . DEG2RAD * thresholdAngle ) ;
27- const edge = [ 0 , 0 ] , edges = { } ;
28- let edge1 , edge2 , key ;
29- const keys = [ 'a' , 'b' , 'c' ] ;
3035
31- // prepare source geometry
36+ const indexAttr = geometry . getIndex ( ) ;
37+ const positionAttr = geometry . getAttribute ( 'position' ) ;
38+ const indexCount = indexAttr ? indexAttr . count : positionAttr . count ;
3239
33- let geometry2 ;
40+ const indexArr = [ 0 , 0 , 0 ] ;
41+ const vertKeys = [ 'a' , 'b' , 'c' ] ;
42+ const hashes = new Array ( 3 ) ;
3443
35- if ( geometry . isBufferGeometry ) {
44+ const edgeData = { } ;
45+ const vertices = [ ] ;
46+ for ( let i = 0 ; i < indexCount ; i += 3 ) {
3647
37- geometry2 = new Geometry ( ) ;
38- geometry2 . fromBufferGeometry ( geometry ) ;
48+ if ( indexAttr ) {
3949
40- } else {
50+ indexArr [ 0 ] = indexAttr . getX ( i ) ;
51+ indexArr [ 1 ] = indexAttr . getX ( i + 1 ) ;
52+ indexArr [ 2 ] = indexAttr . getX ( i + 2 ) ;
4153
42- geometry2 = geometry . clone ( ) ;
54+ } else {
4355
44- }
56+ indexArr [ 0 ] = i ;
57+ indexArr [ 1 ] = i + 1 ;
58+ indexArr [ 2 ] = i + 2 ;
4559
46- geometry2 . mergeVertices ( ) ;
47- geometry2 . computeFaceNormals ( ) ;
60+ }
61+
62+ const { a, b, c } = _triangle ;
63+ a . fromBufferAttribute ( positionAttr , indexArr [ 0 ] ) ;
64+ b . fromBufferAttribute ( positionAttr , indexArr [ 1 ] ) ;
65+ c . fromBufferAttribute ( positionAttr , indexArr [ 2 ] ) ;
66+ _triangle . getNormal ( _normal ) ;
4867
49- const sourceVertices = geometry2 . vertices ;
50- const faces = geometry2 . faces ;
68+ // create hashes for the edge from the vertices
69+ hashes [ 0 ] = `${ Math . round ( a . x * precision ) } ,${ Math . round ( a . y * precision ) } ,${ Math . round ( a . z * precision ) } ` ;
70+ hashes [ 1 ] = `${ Math . round ( b . x * precision ) } ,${ Math . round ( b . y * precision ) } ,${ Math . round ( b . z * precision ) } ` ;
71+ hashes [ 2 ] = `${ Math . round ( c . x * precision ) } ,${ Math . round ( c . y * precision ) } ,${ Math . round ( c . z * precision ) } ` ;
5172
52- // now create a data structure where each entry represents an edge with its adjoining faces
73+ // skip degenerate triangles
74+ if ( hashes [ 0 ] === hashes [ 1 ] || hashes [ 1 ] === hashes [ 2 ] || hashes [ 2 ] === hashes [ 0 ] ) {
5375
54- for ( let i = 0 , l = faces . length ; i < l ; i ++ ) {
76+ continue ;
5577
56- const face = faces [ i ] ;
78+ }
5779
80+ // iterate over every edge
5881 for ( let j = 0 ; j < 3 ; j ++ ) {
5982
60- edge1 = face [ keys [ j ] ] ;
61- edge2 = face [ keys [ ( j + 1 ) % 3 ] ] ;
62- edge [ 0 ] = Math . min ( edge1 , edge2 ) ;
63- edge [ 1 ] = Math . max ( edge1 , edge2 ) ;
83+ // get the first and next vertex making up the edge
84+ const jNext = ( j + 1 ) % 3 ;
85+ const vecHash0 = hashes [ j ] ;
86+ const vecHash1 = hashes [ jNext ] ;
87+ const v0 = _triangle [ vertKeys [ j ] ] ;
88+ const v1 = _triangle [ vertKeys [ jNext ] ] ;
6489
65- key = edge [ 0 ] + ',' + edge [ 1 ] ;
90+ const hash = `${ vecHash0 } _${ vecHash1 } ` ;
91+ const reverseHash = `${ vecHash1 } _${ vecHash0 } ` ;
6692
67- if ( edges [ key ] === undefined ) {
93+ if ( reverseHash in edgeData && edgeData [ reverseHash ] ) {
6894
69- edges [ key ] = { index1 : edge [ 0 ] , index2 : edge [ 1 ] , face1 : i , face2 : undefined } ;
95+ // if we found a sibling edge add it into the vertex array if
96+ // it meets the angle threshold and delete the edge from the map.
97+ if ( _normal . dot ( edgeData [ reverseHash ] . normal ) <= thresholdDot ) {
7098
71- } else {
99+ vertices . push ( v0 . x , v0 . y , v0 . z ) ;
100+ vertices . push ( v1 . x , v1 . y , v1 . z ) ;
72101
73- edges [ key ] . face2 = i ;
102+ }
74103
75- }
104+ edgeData [ reverseHash ] = null ;
76105
77- }
106+ } else if ( ! ( hash in edgeData ) ) {
78107
79- }
108+ // if we've already got an edge here then skip adding a new one
109+ edgeData [ hash ] = {
80110
81- // generate vertices
111+ index0 : indexArr [ j ] ,
112+ index1 : indexArr [ jNext ] ,
113+ normal : _normal . clone ( ) ,
82114
83- for ( key in edges ) {
115+ } ;
84116
85- const e = edges [ key ] ;
117+ }
86118
87- // an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.
119+ }
88120
89- if ( e . face2 === undefined || faces [ e . face1 ] . normal . dot ( faces [ e . face2 ] . normal ) <= thresholdDot ) {
121+ }
90122
91- let vertex = sourceVertices [ e . index1 ] ;
92- vertices . push ( vertex . x , vertex . y , vertex . z ) ;
123+ // iterate over all remaining, unmatched edges and add them to the vertex array
124+ for ( const key in edgeData ) {
93125
94- vertex = sourceVertices [ e . index2 ] ;
95- vertices . push ( vertex . x , vertex . y , vertex . z ) ;
126+ if ( edgeData [ key ] ) {
127+
128+ const { index0, index1 } = edgeData [ key ] ;
129+ _v0 . fromBufferAttribute ( positionAttr , index0 ) ;
130+ _v1 . fromBufferAttribute ( positionAttr , index1 ) ;
131+
132+ vertices . push ( _v0 . x , _v0 . y , _v0 . z ) ;
133+ vertices . push ( _v1 . x , _v1 . y , _v1 . z ) ;
96134
97135 }
98136
99137 }
100138
101- // build geometry
102-
103139 this . setAttribute ( 'position' , new Float32BufferAttribute ( vertices , 3 ) ) ;
104140
105141 }
106142
107143}
108144
109-
110145export { EdgesGeometry } ;
0 commit comments