|
@@ -3,7 +3,6 @@ import {
|
|
|
BufferGeometry,
|
|
|
Color,
|
|
|
FileLoader,
|
|
|
- Float32BufferAttribute,
|
|
|
Group,
|
|
|
LineBasicMaterial,
|
|
|
LineSegments,
|
|
@@ -198,8 +197,9 @@ function smoothNormals( triangles, lineSegments ) {
|
|
|
for ( let i = 0, l = lineSegments.length; i < l; i ++ ) {
|
|
|
|
|
|
const ls = lineSegments[ i ];
|
|
|
- const v0 = ls.v0;
|
|
|
- const v1 = ls.v1;
|
|
|
+ const vertices = ls.vertices;
|
|
|
+ const v0 = vertices[ 0 ];
|
|
|
+ const v1 = vertices[ 1 ];
|
|
|
hardEdges.add( hashEdge( v0, v1 ) );
|
|
|
hardEdges.add( hashEdge( v1, v0 ) );
|
|
|
|
|
@@ -213,14 +213,20 @@ function smoothNormals( triangles, lineSegments ) {
|
|
|
|
|
|
const index = i2;
|
|
|
const next = ( i2 + 1 ) % 3;
|
|
|
- const v0 = tri[ `v${ index }` ];
|
|
|
- const v1 = tri[ `v${ next }` ];
|
|
|
+ const vertices = tri.vertices;
|
|
|
+ const v0 = vertices[ index ];
|
|
|
+ const v1 = vertices[ next ];
|
|
|
const hash = hashEdge( v0, v1 );
|
|
|
|
|
|
// don't add the triangle if the edge is supposed to be hard
|
|
|
if ( hardEdges.has( hash ) ) continue;
|
|
|
- halfEdgeList[ hash ] = tri;
|
|
|
- fullHalfEdgeList[ hash ] = tri;
|
|
|
+
|
|
|
+ const info = {
|
|
|
+ index: index,
|
|
|
+ tri: tri
|
|
|
+ };
|
|
|
+ halfEdgeList[ hash ] = info;
|
|
|
+ fullHalfEdgeList[ hash ] = info;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -230,37 +236,50 @@ function smoothNormals( triangles, lineSegments ) {
|
|
|
while ( true ) {
|
|
|
|
|
|
// Stop if there are no more triangles left
|
|
|
- const halfEdges = Object.keys( halfEdgeList );
|
|
|
- if ( halfEdges.length === 0 ) break;
|
|
|
+ let halfEdge = null;
|
|
|
+ for ( const key in halfEdgeList ) {
|
|
|
+
|
|
|
+ halfEdge = halfEdgeList[ key ];
|
|
|
+ break;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( halfEdge === null ) {
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
// Exhaustively find all connected triangles
|
|
|
let i = 0;
|
|
|
- const queue = [ fullHalfEdgeList[ halfEdges[ 0 ] ] ];
|
|
|
+ const queue = [ halfEdge ];
|
|
|
while ( i < queue.length ) {
|
|
|
|
|
|
// initialize all vertex normals in this triangle
|
|
|
- const tri = queue[ i ];
|
|
|
+ const tri = queue[ i ].tri;
|
|
|
+ const vertices = tri.vertices;
|
|
|
+ const triNormals = tri.normals;
|
|
|
i ++;
|
|
|
|
|
|
const faceNormal = tri.faceNormal;
|
|
|
- if ( tri.n0 === null ) {
|
|
|
+ if ( triNormals[ 0 ] === null ) {
|
|
|
|
|
|
- tri.n0 = faceNormal.clone().multiplyScalar( tri.fromQuad ? 0.5 : 1.0 );
|
|
|
- normals.push( tri.n0 );
|
|
|
+ triNormals[ 0 ] = faceNormal.clone().multiplyScalar( tri.fromQuad ? 0.5 : 1.0 );
|
|
|
+ normals.push( triNormals[ 0 ] );
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( tri.n1 === null ) {
|
|
|
+ if ( triNormals[ 1 ] === null ) {
|
|
|
|
|
|
- tri.n1 = faceNormal.clone().multiplyScalar( tri.fromQuad ? 0.5 : 1.0 );
|
|
|
- normals.push( tri.n1 );
|
|
|
+ triNormals[ 1 ] = faceNormal.clone().multiplyScalar( tri.fromQuad ? 0.5 : 1.0 );
|
|
|
+ normals.push( triNormals[ 1 ] );
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( tri.n2 === null ) {
|
|
|
+ if ( triNormals[ 2 ] === null ) {
|
|
|
|
|
|
- tri.n2 = faceNormal.clone();
|
|
|
- normals.push( tri.n2 );
|
|
|
+ triNormals[ 2 ] = faceNormal.clone();
|
|
|
+ normals.push( triNormals[ 2 ] );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -269,16 +288,20 @@ function smoothNormals( triangles, lineSegments ) {
|
|
|
|
|
|
const index = i2;
|
|
|
const next = ( i2 + 1 ) % 3;
|
|
|
- const v0 = tri[ `v${ index }` ];
|
|
|
- const v1 = tri[ `v${ next }` ];
|
|
|
+ const v0 = vertices[ index ];
|
|
|
+ const v1 = vertices[ next ];
|
|
|
|
|
|
// delete this triangle from the list so it won't be found again
|
|
|
const hash = hashEdge( v0, v1 );
|
|
|
delete halfEdgeList[ hash ];
|
|
|
|
|
|
const reverseHash = hashEdge( v1, v0 );
|
|
|
- const otherTri = fullHalfEdgeList[ reverseHash ];
|
|
|
- if ( otherTri ) {
|
|
|
+ const otherInfo = fullHalfEdgeList[ reverseHash ];
|
|
|
+ if ( otherInfo ) {
|
|
|
+
|
|
|
+ const otherTri = otherInfo.tri;
|
|
|
+ const otherIndex = otherInfo.index;
|
|
|
+ const otherNormals = otherTri.normals;
|
|
|
|
|
|
// NOTE: If the angle between triangles is > 67.5 degrees then assume it's
|
|
|
// hard edge. There are some cases where the line segments do not line up exactly
|
|
@@ -294,45 +317,29 @@ function smoothNormals( triangles, lineSegments ) {
|
|
|
// it so it won't be found again.
|
|
|
if ( reverseHash in halfEdgeList ) {
|
|
|
|
|
|
- queue.push( otherTri );
|
|
|
+ queue.push( otherInfo );
|
|
|
delete halfEdgeList[ reverseHash ];
|
|
|
|
|
|
}
|
|
|
|
|
|
- // Find the matching edge in this triangle and copy the normal vector over
|
|
|
- for ( let i3 = 0, l3 = 3; i3 < l3; i3 ++ ) {
|
|
|
+ const otherNext = ( otherIndex + 1 ) % 3;
|
|
|
+ if ( otherNormals[ otherIndex ] === null ) {
|
|
|
|
|
|
- const otherIndex = i3;
|
|
|
- const otherNext = ( i3 + 1 ) % 3;
|
|
|
- const otherV0 = otherTri[ `v${ otherIndex }` ];
|
|
|
- const otherV1 = otherTri[ `v${ otherNext }` ];
|
|
|
+ const norm = triNormals[ next ];
|
|
|
+ otherNormals[ otherIndex ] = norm;
|
|
|
|
|
|
- const otherHash = hashEdge( otherV0, otherV1 );
|
|
|
- if ( otherHash === reverseHash ) {
|
|
|
+ const isDoubledVert = otherTri.fromQuad && otherIndex !== 2;
|
|
|
+ norm.addScaledVector( otherTri.faceNormal, isDoubledVert ? 0.5 : 1.0 );
|
|
|
|
|
|
- if ( otherTri[ `n${ otherIndex }` ] === null ) {
|
|
|
-
|
|
|
- const norm = tri[ `n${ next }` ];
|
|
|
- otherTri[ `n${ otherIndex }` ] = norm;
|
|
|
-
|
|
|
- const isDoubledVert = otherTri.fromQuad && otherIndex !== 2;
|
|
|
- norm.addScaledVector( otherTri.faceNormal, isDoubledVert ? 0.5 : 1.0 );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( otherTri[ `n${ otherNext }` ] === null ) {
|
|
|
-
|
|
|
- const norm = tri[ `n${ index }` ];
|
|
|
- otherTri[ `n${ otherNext }` ] = norm;
|
|
|
-
|
|
|
- const isDoubledVert = otherTri.fromQuad && otherNext !== 2;
|
|
|
- norm.addScaledVector( otherTri.faceNormal, isDoubledVert ? 0.5 : 1.0 );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ if ( otherNormals[ otherNext ] === null ) {
|
|
|
|
|
|
- break;
|
|
|
+ const norm = triNormals[ index ];
|
|
|
+ otherNormals[ otherNext ] = norm;
|
|
|
|
|
|
- }
|
|
|
+ const isDoubledVert = otherTri.fromQuad && otherNext !== 2;
|
|
|
+ norm.addScaledVector( otherTri.faceNormal, isDoubledVert ? 0.5 : 1.0 );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -468,8 +475,8 @@ function createObject( elements, elementSize, isConditionalSegments ) {
|
|
|
// Sort the triangles or line segments by colour code to make later the mesh groups
|
|
|
elements.sort( sortByMaterial );
|
|
|
|
|
|
- const positions = [];
|
|
|
- const normals = [];
|
|
|
+ const positions = new Float32Array( elementSize * elements.length * 3 );
|
|
|
+ const normals = new Float32Array( elementSize * elements.length * 3 );
|
|
|
const materials = [];
|
|
|
|
|
|
const bufferGeometry = new BufferGeometry();
|
|
@@ -480,20 +487,39 @@ function createObject( elements, elementSize, isConditionalSegments ) {
|
|
|
for ( let iElem = 0, nElem = elements.length; iElem < nElem; iElem ++ ) {
|
|
|
|
|
|
const elem = elements[ iElem ];
|
|
|
- const v0 = elem.v0;
|
|
|
- const v1 = elem.v1;
|
|
|
+ const vertices = elem.vertices;
|
|
|
+ const elemNormals = elem.normals;
|
|
|
+ const v0 = vertices[ 0 ];
|
|
|
+ const v1 = vertices[ 1 ];
|
|
|
+
|
|
|
// Note that LDraw coordinate system is rotated 180 deg. in the X axis w.r.t. Three.js's one
|
|
|
- positions.push( v0.x, v0.y, v0.z, v1.x, v1.y, v1.z );
|
|
|
- if ( elementSize === 3 ) {
|
|
|
+ const index = iElem * elementSize * 3;
|
|
|
+ positions[ index + 0 ] = v0.x;
|
|
|
+ positions[ index + 1 ] = v0.y;
|
|
|
+ positions[ index + 2 ] = v0.z;
|
|
|
+ positions[ index + 3 ] = v1.x;
|
|
|
+ positions[ index + 4 ] = v1.y;
|
|
|
+ positions[ index + 5 ] = v1.z;
|
|
|
|
|
|
- positions.push( elem.v2.x, elem.v2.y, elem.v2.z );
|
|
|
+ if ( elementSize === 3 ) {
|
|
|
|
|
|
- const n0 = elem.n0 || elem.faceNormal;
|
|
|
- const n1 = elem.n1 || elem.faceNormal;
|
|
|
- const n2 = elem.n2 || elem.faceNormal;
|
|
|
- normals.push( n0.x, n0.y, n0.z );
|
|
|
- normals.push( n1.x, n1.y, n1.z );
|
|
|
- normals.push( n2.x, n2.y, n2.z );
|
|
|
+ const v2 = vertices[ 2 ];
|
|
|
+ positions[ index + 6 ] = v2.x;
|
|
|
+ positions[ index + 7 ] = v2.y;
|
|
|
+ positions[ index + 8 ] = v2.z;
|
|
|
+
|
|
|
+ const n0 = elemNormals[ 0 ] || elem.faceNormal;
|
|
|
+ const n1 = elemNormals[ 1 ] || elem.faceNormal;
|
|
|
+ const n2 = elemNormals[ 2 ] || elem.faceNormal;
|
|
|
+ normals[ index + 0 ] = n0.x;
|
|
|
+ normals[ index + 1 ] = n0.y;
|
|
|
+ normals[ index + 2 ] = n0.z;
|
|
|
+ normals[ index + 3 ] = n1.x;
|
|
|
+ normals[ index + 4 ] = n1.y;
|
|
|
+ normals[ index + 5 ] = n1.z;
|
|
|
+ normals[ index + 6 ] = n2.x;
|
|
|
+ normals[ index + 7 ] = n2.y;
|
|
|
+ normals[ index + 8 ] = n2.z;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -525,11 +551,11 @@ function createObject( elements, elementSize, isConditionalSegments ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
- bufferGeometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
|
|
|
+ bufferGeometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
|
|
|
|
|
|
if ( elementSize === 3 ) {
|
|
|
|
|
|
- bufferGeometry.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
|
|
|
+ bufferGeometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -555,10 +581,12 @@ function createObject( elements, elementSize, isConditionalSegments ) {
|
|
|
for ( let i = 0, l = elements.length; i < l; i ++ ) {
|
|
|
|
|
|
const os = elements[ i ];
|
|
|
- const c0 = os.c0;
|
|
|
- const c1 = os.c1;
|
|
|
- const v0 = os.v0;
|
|
|
- const v1 = os.v1;
|
|
|
+ const vertices = os.vertices;
|
|
|
+ const controlPoints = os.controlPoints;
|
|
|
+ const c0 = controlPoints[ 0 ];
|
|
|
+ const c1 = controlPoints[ 1 ];
|
|
|
+ const v0 = vertices[ 0 ];
|
|
|
+ const v1 = vertices[ 1 ];
|
|
|
const index = i * 3 * 2;
|
|
|
controlArray0[ index + 0 ] = c0.x;
|
|
|
controlArray0[ index + 1 ] = c0.y;
|
|
@@ -1210,7 +1238,7 @@ class LDrawLoader extends Loader {
|
|
|
let inverted;
|
|
|
let ccw;
|
|
|
let doubleSided;
|
|
|
- let v0, v1, v2, v3, faceNormal;
|
|
|
+ let v0, v1, v2, v3, c0, c1, faceNormal;
|
|
|
|
|
|
switch ( lineType ) {
|
|
|
|
|
@@ -1449,12 +1477,16 @@ class LDrawLoader extends Loader {
|
|
|
case '2':
|
|
|
|
|
|
material = parseColourCode( lp, true );
|
|
|
+ v0 = parseVector( lp );
|
|
|
+ v1 = parseVector( lp );
|
|
|
|
|
|
segment = {
|
|
|
material: material.userData.edgeMaterial,
|
|
|
colourCode: material.userData.code,
|
|
|
- v0: parseVector( lp ),
|
|
|
- v1: parseVector( lp )
|
|
|
+ v0: v0,
|
|
|
+ v1: v1,
|
|
|
+
|
|
|
+ vertices: [ v0, v1 ],
|
|
|
};
|
|
|
|
|
|
lineSegments.push( segment );
|
|
@@ -1465,14 +1497,16 @@ class LDrawLoader extends Loader {
|
|
|
case '5':
|
|
|
|
|
|
material = parseColourCode( lp, true );
|
|
|
+ v0 = parseVector( lp );
|
|
|
+ v1 = parseVector( lp );
|
|
|
+ c0 = parseVector( lp );
|
|
|
+ c1 = parseVector( lp );
|
|
|
|
|
|
segment = {
|
|
|
material: material.userData.edgeMaterial.userData.conditionalEdgeMaterial,
|
|
|
colourCode: material.userData.code,
|
|
|
- v0: parseVector( lp ),
|
|
|
- v1: parseVector( lp ),
|
|
|
- c0: parseVector( lp ),
|
|
|
- c1: parseVector( lp )
|
|
|
+ vertices: [ v0, v1 ],
|
|
|
+ controlPoints: [ c0, c1 ],
|
|
|
};
|
|
|
|
|
|
conditionalSegments.push( segment );
|
|
@@ -1511,14 +1545,11 @@ class LDrawLoader extends Loader {
|
|
|
triangles.push( {
|
|
|
material: material,
|
|
|
colourCode: material.userData.code,
|
|
|
- v0: v0,
|
|
|
- v1: v1,
|
|
|
- v2: v2,
|
|
|
faceNormal: faceNormal,
|
|
|
- n0: null,
|
|
|
- n1: null,
|
|
|
- n2: null,
|
|
|
fromQuad: false,
|
|
|
+
|
|
|
+ vertices: [ v0, v1, v2 ],
|
|
|
+ normals: [ null, null, null ],
|
|
|
} );
|
|
|
|
|
|
if ( doubleSided === true ) {
|
|
@@ -1526,14 +1557,11 @@ class LDrawLoader extends Loader {
|
|
|
triangles.push( {
|
|
|
material: material,
|
|
|
colourCode: material.userData.code,
|
|
|
- v0: v0,
|
|
|
- v1: v2,
|
|
|
- v2: v1,
|
|
|
faceNormal: faceNormal,
|
|
|
- n0: null,
|
|
|
- n1: null,
|
|
|
- n2: null,
|
|
|
fromQuad: false,
|
|
|
+
|
|
|
+ vertices: [ v0, v2, v1 ],
|
|
|
+ normals: [ null, null, null ],
|
|
|
} );
|
|
|
|
|
|
}
|
|
@@ -1576,27 +1604,21 @@ class LDrawLoader extends Loader {
|
|
|
triangles.push( {
|
|
|
material: material,
|
|
|
colourCode: material.userData.code,
|
|
|
- v0: v2,
|
|
|
- v1: v0,
|
|
|
- v2: v1,
|
|
|
faceNormal: faceNormal,
|
|
|
- n0: null,
|
|
|
- n1: null,
|
|
|
- n2: null,
|
|
|
fromQuad: true,
|
|
|
+
|
|
|
+ vertices: [ v2, v0, v1 ],
|
|
|
+ normals: [ null, null, null ],
|
|
|
} );
|
|
|
|
|
|
triangles.push( {
|
|
|
material: material,
|
|
|
colourCode: material.userData.code,
|
|
|
- v0: v0,
|
|
|
- v1: v2,
|
|
|
- v2: v3,
|
|
|
faceNormal: faceNormal,
|
|
|
- n0: null,
|
|
|
- n1: null,
|
|
|
- n2: null,
|
|
|
fromQuad: true,
|
|
|
+
|
|
|
+ vertices: [ v0, v2, v3 ],
|
|
|
+ normals: [ null, null, null ],
|
|
|
} );
|
|
|
|
|
|
if ( doubleSided === true ) {
|
|
@@ -1604,27 +1626,21 @@ class LDrawLoader extends Loader {
|
|
|
triangles.push( {
|
|
|
material: material,
|
|
|
colourCode: material.userData.code,
|
|
|
- v0: v0,
|
|
|
- v1: v2,
|
|
|
- v2: v1,
|
|
|
faceNormal: faceNormal,
|
|
|
- n0: null,
|
|
|
- n1: null,
|
|
|
- n2: null,
|
|
|
fromQuad: true,
|
|
|
+
|
|
|
+ vertices: [ v0, v2, v1 ],
|
|
|
+ normals: [ null, null, null ],
|
|
|
} );
|
|
|
|
|
|
triangles.push( {
|
|
|
material: material,
|
|
|
colourCode: material.userData.code,
|
|
|
- v0: v2,
|
|
|
- v1: v0,
|
|
|
- v2: v3,
|
|
|
faceNormal: faceNormal,
|
|
|
- n0: null,
|
|
|
- n1: null,
|
|
|
- n2: null,
|
|
|
fromQuad: true,
|
|
|
+
|
|
|
+ vertices: [ v2, v0, v3 ],
|
|
|
+ normals: [ null, null, null ],
|
|
|
} );
|
|
|
|
|
|
}
|
|
@@ -1805,8 +1821,9 @@ class LDrawLoader extends Loader {
|
|
|
|
|
|
if ( separateObjects ) {
|
|
|
|
|
|
- ls.v0.applyMatrix4( parseScope.matrix );
|
|
|
- ls.v1.applyMatrix4( parseScope.matrix );
|
|
|
+ const vertices = ls.vertices;
|
|
|
+ vertices[ 0 ].applyMatrix4( parseScope.matrix );
|
|
|
+ vertices[ 1 ].applyMatrix4( parseScope.matrix );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -1820,10 +1837,12 @@ class LDrawLoader extends Loader {
|
|
|
|
|
|
if ( separateObjects ) {
|
|
|
|
|
|
- os.v0.applyMatrix4( parseScope.matrix );
|
|
|
- os.v1.applyMatrix4( parseScope.matrix );
|
|
|
- os.c0.applyMatrix4( parseScope.matrix );
|
|
|
- os.c1.applyMatrix4( parseScope.matrix );
|
|
|
+ const vertices = os.vertices;
|
|
|
+ const controlPoints = os.controlPoints;
|
|
|
+ vertices[ 0 ].applyMatrix4( parseScope.matrix );
|
|
|
+ vertices[ 1 ].applyMatrix4( parseScope.matrix );
|
|
|
+ controlPoints[ 0 ].applyMatrix4( parseScope.matrix );
|
|
|
+ controlPoints[ 1 ].applyMatrix4( parseScope.matrix );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -1837,12 +1856,13 @@ class LDrawLoader extends Loader {
|
|
|
|
|
|
if ( separateObjects ) {
|
|
|
|
|
|
- tri.v0 = tri.v0.clone().applyMatrix4( parseScope.matrix );
|
|
|
- tri.v1 = tri.v1.clone().applyMatrix4( parseScope.matrix );
|
|
|
- tri.v2 = tri.v2.clone().applyMatrix4( parseScope.matrix );
|
|
|
+ const vertices = tri.vertices;
|
|
|
+ vertices[ 0 ] = vertices[ 0 ].clone().applyMatrix4( parseScope.matrix );
|
|
|
+ vertices[ 1 ] = vertices[ 1 ].clone().applyMatrix4( parseScope.matrix );
|
|
|
+ vertices[ 2 ] = vertices[ 2 ].clone().applyMatrix4( parseScope.matrix );
|
|
|
|
|
|
- _tempVec0.subVectors( tri.v1, tri.v0 );
|
|
|
- _tempVec1.subVectors( tri.v2, tri.v1 );
|
|
|
+ _tempVec0.subVectors( vertices[ 1 ], vertices[ 0 ] );
|
|
|
+ _tempVec1.subVectors( vertices[ 2 ], vertices[ 1 ] );
|
|
|
tri.faceNormal.crossVectors( _tempVec0, _tempVec1 ).normalize();
|
|
|
|
|
|
}
|