|
@@ -303,48 +303,71 @@ function smoothNormals( faces, lineSegments ) {
|
|
|
|
|
|
// share the first normal
|
|
// share the first normal
|
|
const otherNext = ( otherIndex + 1 ) % otherVertCount;
|
|
const otherNext = ( otherIndex + 1 ) % otherVertCount;
|
|
|
|
+ if (
|
|
|
|
+ vertNormals[ index ] && otherNormals[ otherNext ] &&
|
|
|
|
+ vertNormals[ index ] !== otherNormals[ otherNext ]
|
|
|
|
+ ) {
|
|
|
|
+
|
|
|
|
+ otherNormals[ otherNext ].norm.add( vertNormals[ index ].norm );
|
|
|
|
+ vertNormals[ index ].norm = otherNormals[ otherNext ].norm;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
let sharedNormal1 = vertNormals[ index ] || otherNormals[ otherNext ];
|
|
let sharedNormal1 = vertNormals[ index ] || otherNormals[ otherNext ];
|
|
if ( sharedNormal1 === null ) {
|
|
if ( sharedNormal1 === null ) {
|
|
|
|
|
|
- sharedNormal1 = new Vector3();
|
|
|
|
- normals.push( sharedNormal1 );
|
|
|
|
|
|
+ // it's possible to encounter an edge of a triangle that has already been traversed meaning
|
|
|
|
+ // both edges already have different normals defined and shared. To work around this we create
|
|
|
|
+ // a wrapper object so when those edges are merged the normals can be updated everywhere.
|
|
|
|
+ sharedNormal1 = { norm: new Vector3() };
|
|
|
|
+ normals.push( sharedNormal1.norm );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if ( vertNormals[ index ] === null ) {
|
|
if ( vertNormals[ index ] === null ) {
|
|
|
|
|
|
vertNormals[ index ] = sharedNormal1;
|
|
vertNormals[ index ] = sharedNormal1;
|
|
- sharedNormal1.add( faceNormal );
|
|
|
|
|
|
+ sharedNormal1.norm.add( faceNormal );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if ( otherNormals[ otherNext ] === null ) {
|
|
if ( otherNormals[ otherNext ] === null ) {
|
|
|
|
|
|
otherNormals[ otherNext ] = sharedNormal1;
|
|
otherNormals[ otherNext ] = sharedNormal1;
|
|
- sharedNormal1.add( otherFaceNormal );
|
|
|
|
|
|
+ sharedNormal1.norm.add( otherFaceNormal );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// share the second normal
|
|
// share the second normal
|
|
|
|
+ if (
|
|
|
|
+ vertNormals[ next ] && otherNormals[ otherIndex ] &&
|
|
|
|
+ vertNormals[ next ] !== otherNormals[ otherIndex ]
|
|
|
|
+ ) {
|
|
|
|
+
|
|
|
|
+ otherNormals[ otherIndex ].norm.add( vertNormals[ next ].norm );
|
|
|
|
+ vertNormals[ next ].norm = otherNormals[ otherIndex ].norm;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
let sharedNormal2 = vertNormals[ next ] || otherNormals[ otherIndex ];
|
|
let sharedNormal2 = vertNormals[ next ] || otherNormals[ otherIndex ];
|
|
if ( sharedNormal2 === null ) {
|
|
if ( sharedNormal2 === null ) {
|
|
|
|
|
|
- sharedNormal2 = new Vector3();
|
|
|
|
- normals.push( sharedNormal2 );
|
|
|
|
|
|
+ sharedNormal2 = { norm: new Vector3() };
|
|
|
|
+ normals.push( sharedNormal2.norm );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if ( vertNormals[ next ] === null ) {
|
|
if ( vertNormals[ next ] === null ) {
|
|
|
|
|
|
vertNormals[ next ] = sharedNormal2;
|
|
vertNormals[ next ] = sharedNormal2;
|
|
- sharedNormal2.add( faceNormal );
|
|
|
|
|
|
+ sharedNormal2.norm.add( faceNormal );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if ( otherNormals[ otherIndex ] === null ) {
|
|
if ( otherNormals[ otherIndex ] === null ) {
|
|
|
|
|
|
otherNormals[ otherIndex ] = sharedNormal2;
|
|
otherNormals[ otherIndex ] = sharedNormal2;
|
|
- sharedNormal2.add( otherFaceNormal );
|
|
|
|
|
|
+ sharedNormal2.norm.add( otherFaceNormal );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
@@ -540,7 +563,13 @@ function createObject( elements, elementSize, isConditionalSegments = false, tot
|
|
|
|
|
|
for ( let j = 0, l = elemNormals.length; j < l; j ++ ) {
|
|
for ( let j = 0, l = elemNormals.length; j < l; j ++ ) {
|
|
|
|
|
|
- const n = elemNormals[ j ] || elem.faceNormal;
|
|
|
|
|
|
+ let n = elem.faceNormal;
|
|
|
|
+ if ( elemNormals[ j ] ) {
|
|
|
|
+
|
|
|
|
+ n = elemNormals[ j ].norm;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
const index = offset + j * 3;
|
|
const index = offset + j * 3;
|
|
normals[ index + 0 ] = n.x;
|
|
normals[ index + 0 ] = n.x;
|
|
normals[ index + 1 ] = n.y;
|
|
normals[ index + 1 ] = n.y;
|
|
@@ -592,11 +621,11 @@ function createObject( elements, elementSize, isConditionalSegments = false, tot
|
|
|
|
|
|
if ( elementSize === 2 ) {
|
|
if ( elementSize === 2 ) {
|
|
|
|
|
|
- object3d = new LineSegments( bufferGeometry, materials );
|
|
|
|
|
|
+ object3d = new LineSegments( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
|
|
|
|
|
|
} else if ( elementSize === 3 ) {
|
|
} else if ( elementSize === 3 ) {
|
|
|
|
|
|
- object3d = new Mesh( bufferGeometry, materials );
|
|
|
|
|
|
+ object3d = new Mesh( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
@@ -687,6 +716,44 @@ class LDrawLoader extends Loader {
|
|
// If this flag is set to true the vertex normals will be smoothed.
|
|
// If this flag is set to true the vertex normals will be smoothed.
|
|
this.smoothNormals = true;
|
|
this.smoothNormals = true;
|
|
|
|
|
|
|
|
+ // The path to load parts from the LDraw parts library from.
|
|
|
|
+ this.partsLibraryPath = '';
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ setPartsLibraryPath( path ) {
|
|
|
|
+
|
|
|
|
+ this.partsLibraryPath = path;
|
|
|
|
+ return this;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async preloadMaterials( url ) {
|
|
|
|
+
|
|
|
|
+ const fileLoader = new FileLoader( this.manager );
|
|
|
|
+ fileLoader.setPath( this.path );
|
|
|
|
+ fileLoader.setRequestHeader( this.requestHeader );
|
|
|
|
+ fileLoader.setWithCredentials( this.withCredentials );
|
|
|
|
+
|
|
|
|
+ const text = await fileLoader.loadAsync( url );
|
|
|
|
+ const colorLineRegex = /^0 !COLOUR/;
|
|
|
|
+ const lines = text.split( /[\n\r]/g );
|
|
|
|
+ const materials = [];
|
|
|
|
+ for ( let i = 0, l = lines.length; i < l; i ++ ) {
|
|
|
|
+
|
|
|
|
+ const line = lines[ i ];
|
|
|
|
+ if ( colorLineRegex.test( line ) ) {
|
|
|
|
+
|
|
|
|
+ const directive = line.replace( colorLineRegex, '' );
|
|
|
|
+ const material = this.parseColourMetaDirective( new LineParser( directive ) );
|
|
|
|
+ materials.push( material );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.setMaterials( materials );
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
load( url, onLoad, onProgress, onError ) {
|
|
load( url, onLoad, onProgress, onError ) {
|
|
@@ -1988,7 +2055,7 @@ class LDrawLoader extends Loader {
|
|
// Use another file loader here so we can keep track of the subobject information
|
|
// Use another file loader here so we can keep track of the subobject information
|
|
// and use it when processing the next model.
|
|
// and use it when processing the next model.
|
|
const fileLoader = new FileLoader( scope.manager );
|
|
const fileLoader = new FileLoader( scope.manager );
|
|
- fileLoader.setPath( scope.path );
|
|
|
|
|
|
+ fileLoader.setPath( scope.partsLibraryPath );
|
|
fileLoader.setRequestHeader( scope.requestHeader );
|
|
fileLoader.setRequestHeader( scope.requestHeader );
|
|
fileLoader.setWithCredentials( scope.withCredentials );
|
|
fileLoader.setWithCredentials( scope.withCredentials );
|
|
fileLoader.load( subobjectURL, function ( text ) {
|
|
fileLoader.load( subobjectURL, function ( text ) {
|