@@ -13,7 +13,8 @@ import {
1313 ShaderMaterial ,
1414 UniformsLib ,
1515 UniformsUtils ,
16- Vector3
16+ Vector3 ,
17+ Ray
1718} from '../../../build/three.module.js' ;
1819
1920// Special surface finish tag types.
@@ -187,7 +188,8 @@ function generateFaceNormals( faces ) {
187188
188189}
189190
190- function smoothNormals ( faces , lineSegments ) {
191+ const _ray = new Ray ( ) ;
192+ function smoothNormals ( faces , lineSegments , checkSubSegments = false ) {
191193
192194 function hashVertex ( v ) {
193195
@@ -207,7 +209,27 @@ function smoothNormals( faces, lineSegments ) {
207209
208210 }
209211
212+ // converts the two vertices to a ray with a normalized direction and origin of 0, 0, 0 projected
213+ // onto the original line.
214+ function toNormalizedRay ( v0 , v1 , targetRay ) {
215+
216+ targetRay . direction . subVectors ( v1 , v0 ) . normalize ( ) ;
217+
218+ const scalar = v0 . dot ( targetRay . direction ) ;
219+ targetRay . origin . copy ( v0 ) . addScaledVector ( targetRay . direction , - scalar ) ;
220+
221+ return targetRay ;
222+
223+ }
224+
225+ function hashRay ( ray ) {
226+
227+ return hashEdge ( ray . origin , ray . direction ) ;
228+
229+ }
230+
210231 const hardEdges = new Set ( ) ;
232+ const hardEdgeRays = new Map ( ) ;
211233 const halfEdgeList = { } ;
212234 const normals = [ ] ;
213235
@@ -221,6 +243,43 @@ function smoothNormals( faces, lineSegments ) {
221243 hardEdges . add ( hashEdge ( v0 , v1 ) ) ;
222244 hardEdges . add ( hashEdge ( v1 , v0 ) ) ;
223245
246+ // only generate the hard edge ray map if we're checking subsegments because it's more expensive to check
247+ // and requires more memory.
248+ if ( checkSubSegments ) {
249+
250+ // add both ray directions to the map
251+ const ray = toNormalizedRay ( v0 , v1 , new Ray ( ) ) ;
252+ const rh1 = hashRay ( ray ) ;
253+ if ( ! hardEdgeRays . has ( rh1 ) ) {
254+
255+ toNormalizedRay ( v1 , v0 , ray ) ;
256+ const rh2 = hashRay ( ray ) ;
257+
258+ const info = {
259+ ray,
260+ distances : [ ] ,
261+ } ;
262+
263+ hardEdgeRays . set ( rh1 , info ) ;
264+ hardEdgeRays . set ( rh2 , info ) ;
265+
266+ }
267+
268+ // store both segments ends in min, max order in the distances array to check if a face edge is a
269+ // subsegment later.
270+ const info = hardEdgeRays . get ( rh1 ) ;
271+ let d0 = info . ray . direction . dot ( v0 ) ;
272+ let d1 = info . ray . direction . dot ( v1 ) ;
273+ if ( d0 > d1 ) {
274+
275+ [ d0 , d1 ] = [ d1 , d0 ] ;
276+
277+ }
278+
279+ info . distances . push ( d0 , d1 ) ;
280+
281+ }
282+
224283 }
225284
226285 // track the half edges associated with each triangle
@@ -238,7 +297,53 @@ function smoothNormals( faces, lineSegments ) {
238297 const hash = hashEdge ( v0 , v1 ) ;
239298
240299 // don't add the triangle if the edge is supposed to be hard
241- if ( hardEdges . has ( hash ) ) continue ;
300+ if ( hardEdges . has ( hash ) ) {
301+
302+ continue ;
303+
304+ }
305+
306+ // if checking subsegments then check to see if this edge lies on a hard edge ray and whether its within any ray bounds
307+ if ( checkSubSegments ) {
308+
309+ toNormalizedRay ( v0 , v1 , _ray ) ;
310+
311+ const rayHash = hashRay ( _ray ) ;
312+ if ( hardEdgeRays . has ( rayHash ) ) {
313+
314+ const info = hardEdgeRays . get ( rayHash ) ;
315+ const { ray, distances } = info ;
316+ let d0 = ray . direction . dot ( v0 ) ;
317+ let d1 = ray . direction . dot ( v1 ) ;
318+
319+ if ( d0 > d1 ) {
320+
321+ [ d0 , d1 ] = [ d1 , d0 ] ;
322+
323+ }
324+
325+ // return early if the face edge is found to be a subsegment of a line edge meaning the edge will have "hard" normals
326+ let found = false ;
327+ for ( let i = 0 , l = distances . length ; i < l ; i += 2 ) {
328+
329+ if ( d0 >= distances [ i ] && d1 <= distances [ i + 1 ] ) {
330+
331+ found = true ;
332+ break ;
333+
334+ }
335+
336+ }
337+
338+ if ( found ) {
339+
340+ continue ;
341+
342+ }
343+
344+ }
345+
346+ }
242347
243348 const info = {
244349 index : index ,
@@ -1005,6 +1110,7 @@ class LDrawLoader extends Loader {
10051110 lineSegments : [ ] ,
10061111 conditionalSegments : [ ] ,
10071112 totalFaces : 0 ,
1113+ faceMaterials : new Set ( ) ,
10081114
10091115 // If true, this object is the start of a construction step
10101116 startingConstructionStep : false
@@ -1751,6 +1857,8 @@ class LDrawLoader extends Loader {
17511857
17521858 }
17531859
1860+ currentParseScope . faceMaterials . add ( material ) ;
1861+
17541862 break ;
17551863
17561864 // Line type 4: Quadrilateral
@@ -1883,7 +1991,11 @@ class LDrawLoader extends Loader {
18831991 if ( this . smoothNormals && doSmooth ) {
18841992
18851993 generateFaceNormals ( subobjectParseScope . faces ) ;
1886- smoothNormals ( subobjectParseScope . faces , subobjectParseScope . lineSegments ) ;
1994+
1995+ // only check subsetgments if we have multiple materials in a single part because this seems to be the case where it's needed most --
1996+ // there may be cases where a single edge line crosses over polygon edges that are broken up by multiple materials.
1997+ const checkSubSegments = subobjectParseScope . faceMaterials . size > 1 ;
1998+ smoothNormals ( subobjectParseScope . faces , subobjectParseScope . lineSegments , checkSubSegments ) ;
18871999
18882000 }
18892001
@@ -1927,10 +2039,12 @@ class LDrawLoader extends Loader {
19272039 const parentLineSegments = parentParseScope . lineSegments ;
19282040 const parentConditionalSegments = parentParseScope . conditionalSegments ;
19292041 const parentFaces = parentParseScope . faces ;
2042+ const parentFaceMaterials = parentParseScope . faceMaterials ;
19302043
19312044 const lineSegments = subobjectParseScope . lineSegments ;
19322045 const conditionalSegments = subobjectParseScope . conditionalSegments ;
19332046 const faces = subobjectParseScope . faces ;
2047+ const faceMaterials = subobjectParseScope . faceMaterials ;
19342048
19352049 for ( let i = 0 , l = lineSegments . length ; i < l ; i ++ ) {
19362050
@@ -1987,6 +2101,7 @@ class LDrawLoader extends Loader {
19872101 }
19882102
19892103 parentParseScope . totalFaces += subobjectParseScope . totalFaces ;
2104+ faceMaterials . forEach ( material => parentFaceMaterials . add ( material ) ) ;
19902105
19912106 }
19922107
0 commit comments