|
@@ -6,158 +6,163 @@ import { Vector2 } from '../math/Vector2.js';
|
|
|
|
|
|
// PolyhedronGeometry
|
|
|
|
|
|
-function PolyhedronGeometry( vertices, indices, radius, detail ) {
|
|
|
+class PolyhedronGeometry extends Geometry {
|
|
|
|
|
|
- Geometry.call( this );
|
|
|
+ constructor( vertices, indices, radius, detail ) {
|
|
|
|
|
|
- this.type = 'PolyhedronGeometry';
|
|
|
+ super();
|
|
|
|
|
|
- this.parameters = {
|
|
|
- vertices: vertices,
|
|
|
- indices: indices,
|
|
|
- radius: radius,
|
|
|
- detail: detail
|
|
|
- };
|
|
|
+ this.type = 'PolyhedronGeometry';
|
|
|
|
|
|
- this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
|
|
|
- this.mergeVertices();
|
|
|
+ this.parameters = {
|
|
|
+ vertices: vertices,
|
|
|
+ indices: indices,
|
|
|
+ radius: radius,
|
|
|
+ detail: detail
|
|
|
+ };
|
|
|
|
|
|
-}
|
|
|
+ this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
|
|
|
+ this.mergeVertices();
|
|
|
|
|
|
-PolyhedronGeometry.prototype = Object.create( Geometry.prototype );
|
|
|
-PolyhedronGeometry.prototype.constructor = PolyhedronGeometry;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
|
|
|
// PolyhedronBufferGeometry
|
|
|
|
|
|
-function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
|
|
|
+class PolyhedronBufferGeometry extends BufferGeometry {
|
|
|
|
|
|
- BufferGeometry.call( this );
|
|
|
+ constructor( vertices, indices, radius, detail ) {
|
|
|
|
|
|
- this.type = 'PolyhedronBufferGeometry';
|
|
|
+ super();
|
|
|
|
|
|
- this.parameters = {
|
|
|
- vertices: vertices,
|
|
|
- indices: indices,
|
|
|
- radius: radius,
|
|
|
- detail: detail
|
|
|
- };
|
|
|
+ this.type = 'PolyhedronBufferGeometry';
|
|
|
|
|
|
- radius = radius || 1;
|
|
|
- detail = detail || 0;
|
|
|
+ this.parameters = {
|
|
|
+ vertices: vertices,
|
|
|
+ indices: indices,
|
|
|
+ radius: radius,
|
|
|
+ detail: detail
|
|
|
+ };
|
|
|
|
|
|
- // default buffer data
|
|
|
+ radius = radius || 1;
|
|
|
+ detail = detail || 0;
|
|
|
|
|
|
- const vertexBuffer = [];
|
|
|
- const uvBuffer = [];
|
|
|
+ // default buffer data
|
|
|
|
|
|
- // the subdivision creates the vertex buffer data
|
|
|
+ const vertexBuffer = [];
|
|
|
+ const uvBuffer = [];
|
|
|
|
|
|
- subdivide( detail );
|
|
|
+ // the subdivision creates the vertex buffer data
|
|
|
|
|
|
- // all vertices should lie on a conceptual sphere with a given radius
|
|
|
+ subdivide( detail );
|
|
|
|
|
|
- applyRadius( radius );
|
|
|
+ // all vertices should lie on a conceptual sphere with a given radius
|
|
|
|
|
|
- // finally, create the uv data
|
|
|
+ applyRadius( radius );
|
|
|
|
|
|
- generateUVs();
|
|
|
+ // finally, create the uv data
|
|
|
|
|
|
- // build non-indexed geometry
|
|
|
+ generateUVs();
|
|
|
|
|
|
- this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
|
|
|
- this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
|
|
|
- this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
|
|
|
+ // build non-indexed geometry
|
|
|
|
|
|
- if ( detail === 0 ) {
|
|
|
+ this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
|
|
|
+ this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
|
|
|
+ this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
|
|
|
|
|
|
- this.computeVertexNormals(); // flat normals
|
|
|
+ if ( detail === 0 ) {
|
|
|
|
|
|
- } else {
|
|
|
+ this.computeVertexNormals(); // flat normals
|
|
|
|
|
|
- this.normalizeNormals(); // smooth normals
|
|
|
+ } else {
|
|
|
|
|
|
- }
|
|
|
+ this.normalizeNormals(); // smooth normals
|
|
|
|
|
|
- // helper functions
|
|
|
+ }
|
|
|
+
|
|
|
+ // helper functions
|
|
|
|
|
|
- function subdivide( detail ) {
|
|
|
+ function subdivide( detail ) {
|
|
|
|
|
|
- const a = new Vector3();
|
|
|
- const b = new Vector3();
|
|
|
- const c = new Vector3();
|
|
|
+ const a = new Vector3();
|
|
|
+ const b = new Vector3();
|
|
|
+ const c = new Vector3();
|
|
|
|
|
|
- // iterate over all faces and apply a subdivison with the given detail value
|
|
|
+ // iterate over all faces and apply a subdivison with the given detail value
|
|
|
|
|
|
- for ( let i = 0; i < indices.length; i += 3 ) {
|
|
|
+ for ( let i = 0; i < indices.length; i += 3 ) {
|
|
|
|
|
|
- // get the vertices of the face
|
|
|
+ // get the vertices of the face
|
|
|
|
|
|
- getVertexByIndex( indices[ i + 0 ], a );
|
|
|
- getVertexByIndex( indices[ i + 1 ], b );
|
|
|
- getVertexByIndex( indices[ i + 2 ], c );
|
|
|
+ getVertexByIndex( indices[ i + 0 ], a );
|
|
|
+ getVertexByIndex( indices[ i + 1 ], b );
|
|
|
+ getVertexByIndex( indices[ i + 2 ], c );
|
|
|
|
|
|
- // perform subdivision
|
|
|
+ // perform subdivision
|
|
|
|
|
|
- subdivideFace( a, b, c, detail );
|
|
|
+ subdivideFace( a, b, c, detail );
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ function subdivideFace( a, b, c, detail ) {
|
|
|
|
|
|
- function subdivideFace( a, b, c, detail ) {
|
|
|
+ const cols = Math.pow( 2, detail );
|
|
|
|
|
|
- const cols = Math.pow( 2, detail );
|
|
|
+ // we use this multidimensional array as a data structure for creating the subdivision
|
|
|
|
|
|
- // we use this multidimensional array as a data structure for creating the subdivision
|
|
|
+ const v = [];
|
|
|
|
|
|
- const v = [];
|
|
|
+ // construct all of the vertices for this subdivision
|
|
|
|
|
|
- // construct all of the vertices for this subdivision
|
|
|
+ for ( let i = 0; i <= cols; i ++ ) {
|
|
|
|
|
|
- for ( let i = 0; i <= cols; i ++ ) {
|
|
|
+ v[ i ] = [];
|
|
|
|
|
|
- v[ i ] = [];
|
|
|
+ const aj = a.clone().lerp( c, i / cols );
|
|
|
+ const bj = b.clone().lerp( c, i / cols );
|
|
|
|
|
|
- const aj = a.clone().lerp( c, i / cols );
|
|
|
- const bj = b.clone().lerp( c, i / cols );
|
|
|
+ const rows = cols - i;
|
|
|
|
|
|
- const rows = cols - i;
|
|
|
+ for ( let j = 0; j <= rows; j ++ ) {
|
|
|
|
|
|
- for ( let j = 0; j <= rows; j ++ ) {
|
|
|
+ if ( j === 0 && i === cols ) {
|
|
|
|
|
|
- if ( j === 0 && i === cols ) {
|
|
|
+ v[ i ][ j ] = aj;
|
|
|
|
|
|
- v[ i ][ j ] = aj;
|
|
|
+ } else {
|
|
|
|
|
|
- } else {
|
|
|
+ v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
|
|
|
|
|
|
- v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ // construct all of the faces
|
|
|
|
|
|
- // construct all of the faces
|
|
|
+ for ( let i = 0; i < cols; i ++ ) {
|
|
|
|
|
|
- for ( let i = 0; i < cols; i ++ ) {
|
|
|
+ for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
|
|
|
|
|
|
- for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
|
|
|
+ const k = Math.floor( j / 2 );
|
|
|
|
|
|
- const k = Math.floor( j / 2 );
|
|
|
+ if ( j % 2 === 0 ) {
|
|
|
|
|
|
- if ( j % 2 === 0 ) {
|
|
|
+ pushVertex( v[ i ][ k + 1 ] );
|
|
|
+ pushVertex( v[ i + 1 ][ k ] );
|
|
|
+ pushVertex( v[ i ][ k ] );
|
|
|
|
|
|
- pushVertex( v[ i ][ k + 1 ] );
|
|
|
- pushVertex( v[ i + 1 ][ k ] );
|
|
|
- pushVertex( v[ i ][ k ] );
|
|
|
+ } else {
|
|
|
|
|
|
- } else {
|
|
|
+ pushVertex( v[ i ][ k + 1 ] );
|
|
|
+ pushVertex( v[ i + 1 ][ k + 1 ] );
|
|
|
+ pushVertex( v[ i + 1 ][ k ] );
|
|
|
|
|
|
- pushVertex( v[ i ][ k + 1 ] );
|
|
|
- pushVertex( v[ i + 1 ][ k + 1 ] );
|
|
|
- pushVertex( v[ i + 1 ][ k ] );
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
@@ -165,168 +170,165 @@ function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ function applyRadius( radius ) {
|
|
|
|
|
|
- function applyRadius( radius ) {
|
|
|
+ const vertex = new Vector3();
|
|
|
|
|
|
- const vertex = new Vector3();
|
|
|
+ // iterate over the entire buffer and apply the radius to each vertex
|
|
|
|
|
|
- // iterate over the entire buffer and apply the radius to each vertex
|
|
|
+ for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
|
|
|
|
|
|
- for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
|
|
|
+ vertex.x = vertexBuffer[ i + 0 ];
|
|
|
+ vertex.y = vertexBuffer[ i + 1 ];
|
|
|
+ vertex.z = vertexBuffer[ i + 2 ];
|
|
|
|
|
|
- vertex.x = vertexBuffer[ i + 0 ];
|
|
|
- vertex.y = vertexBuffer[ i + 1 ];
|
|
|
- vertex.z = vertexBuffer[ i + 2 ];
|
|
|
+ vertex.normalize().multiplyScalar( radius );
|
|
|
|
|
|
- vertex.normalize().multiplyScalar( radius );
|
|
|
+ vertexBuffer[ i + 0 ] = vertex.x;
|
|
|
+ vertexBuffer[ i + 1 ] = vertex.y;
|
|
|
+ vertexBuffer[ i + 2 ] = vertex.z;
|
|
|
|
|
|
- vertexBuffer[ i + 0 ] = vertex.x;
|
|
|
- vertexBuffer[ i + 1 ] = vertex.y;
|
|
|
- vertexBuffer[ i + 2 ] = vertex.z;
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ function generateUVs() {
|
|
|
|
|
|
- function generateUVs() {
|
|
|
+ const vertex = new Vector3();
|
|
|
|
|
|
- const vertex = new Vector3();
|
|
|
+ for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
|
|
|
|
|
|
- for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
|
|
|
+ vertex.x = vertexBuffer[ i + 0 ];
|
|
|
+ vertex.y = vertexBuffer[ i + 1 ];
|
|
|
+ vertex.z = vertexBuffer[ i + 2 ];
|
|
|
|
|
|
- vertex.x = vertexBuffer[ i + 0 ];
|
|
|
- vertex.y = vertexBuffer[ i + 1 ];
|
|
|
- vertex.z = vertexBuffer[ i + 2 ];
|
|
|
+ const u = azimuth( vertex ) / 2 / Math.PI + 0.5;
|
|
|
+ const v = inclination( vertex ) / Math.PI + 0.5;
|
|
|
+ uvBuffer.push( u, 1 - v );
|
|
|
|
|
|
- const u = azimuth( vertex ) / 2 / Math.PI + 0.5;
|
|
|
- const v = inclination( vertex ) / Math.PI + 0.5;
|
|
|
- uvBuffer.push( u, 1 - v );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ correctUVs();
|
|
|
|
|
|
- correctUVs();
|
|
|
+ correctSeam();
|
|
|
|
|
|
- correctSeam();
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ function correctSeam() {
|
|
|
|
|
|
- function correctSeam() {
|
|
|
+ // handle case when face straddles the seam, see #3269
|
|
|
|
|
|
- // handle case when face straddles the seam, see #3269
|
|
|
+ for ( let i = 0; i < uvBuffer.length; i += 6 ) {
|
|
|
|
|
|
- for ( let i = 0; i < uvBuffer.length; i += 6 ) {
|
|
|
+ // uv data of a single face
|
|
|
|
|
|
- // uv data of a single face
|
|
|
+ const x0 = uvBuffer[ i + 0 ];
|
|
|
+ const x1 = uvBuffer[ i + 2 ];
|
|
|
+ const x2 = uvBuffer[ i + 4 ];
|
|
|
|
|
|
- const x0 = uvBuffer[ i + 0 ];
|
|
|
- const x1 = uvBuffer[ i + 2 ];
|
|
|
- const x2 = uvBuffer[ i + 4 ];
|
|
|
+ const max = Math.max( x0, x1, x2 );
|
|
|
+ const min = Math.min( x0, x1, x2 );
|
|
|
|
|
|
- const max = Math.max( x0, x1, x2 );
|
|
|
- const min = Math.min( x0, x1, x2 );
|
|
|
+ // 0.9 is somewhat arbitrary
|
|
|
|
|
|
- // 0.9 is somewhat arbitrary
|
|
|
+ if ( max > 0.9 && min < 0.1 ) {
|
|
|
|
|
|
- if ( max > 0.9 && min < 0.1 ) {
|
|
|
+ if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
|
|
|
+ if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
|
|
|
+ if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
|
|
|
|
|
|
- if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
|
|
|
- if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
|
|
|
- if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ function pushVertex( vertex ) {
|
|
|
|
|
|
- function pushVertex( vertex ) {
|
|
|
+ vertexBuffer.push( vertex.x, vertex.y, vertex.z );
|
|
|
|
|
|
- vertexBuffer.push( vertex.x, vertex.y, vertex.z );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ function getVertexByIndex( index, vertex ) {
|
|
|
|
|
|
- function getVertexByIndex( index, vertex ) {
|
|
|
+ const stride = index * 3;
|
|
|
|
|
|
- const stride = index * 3;
|
|
|
+ vertex.x = vertices[ stride + 0 ];
|
|
|
+ vertex.y = vertices[ stride + 1 ];
|
|
|
+ vertex.z = vertices[ stride + 2 ];
|
|
|
|
|
|
- vertex.x = vertices[ stride + 0 ];
|
|
|
- vertex.y = vertices[ stride + 1 ];
|
|
|
- vertex.z = vertices[ stride + 2 ];
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ function correctUVs() {
|
|
|
|
|
|
- function correctUVs() {
|
|
|
+ const a = new Vector3();
|
|
|
+ const b = new Vector3();
|
|
|
+ const c = new Vector3();
|
|
|
|
|
|
- const a = new Vector3();
|
|
|
- const b = new Vector3();
|
|
|
- const c = new Vector3();
|
|
|
+ const centroid = new Vector3();
|
|
|
|
|
|
- const centroid = new Vector3();
|
|
|
+ const uvA = new Vector2();
|
|
|
+ const uvB = new Vector2();
|
|
|
+ const uvC = new Vector2();
|
|
|
|
|
|
- const uvA = new Vector2();
|
|
|
- const uvB = new Vector2();
|
|
|
- const uvC = new Vector2();
|
|
|
+ for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
|
|
|
|
|
|
- for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
|
|
|
+ a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
|
|
|
+ b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
|
|
|
+ c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
|
|
|
|
|
|
- a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
|
|
|
- b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
|
|
|
- c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
|
|
|
+ uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
|
|
|
+ uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
|
|
|
+ uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
|
|
|
|
|
|
- uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
|
|
|
- uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
|
|
|
- uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
|
|
|
+ centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
|
|
|
|
|
|
- centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
|
|
|
+ const azi = azimuth( centroid );
|
|
|
|
|
|
- const azi = azimuth( centroid );
|
|
|
+ correctUV( uvA, j + 0, a, azi );
|
|
|
+ correctUV( uvB, j + 2, b, azi );
|
|
|
+ correctUV( uvC, j + 4, c, azi );
|
|
|
|
|
|
- correctUV( uvA, j + 0, a, azi );
|
|
|
- correctUV( uvB, j + 2, b, azi );
|
|
|
- correctUV( uvC, j + 4, c, azi );
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ function correctUV( uv, stride, vector, azimuth ) {
|
|
|
|
|
|
- function correctUV( uv, stride, vector, azimuth ) {
|
|
|
+ if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
|
|
|
|
|
|
- if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
|
|
|
+ uvBuffer[ stride ] = uv.x - 1;
|
|
|
|
|
|
- uvBuffer[ stride ] = uv.x - 1;
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
|
|
|
|
|
|
- if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
|
|
|
+ uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
|
|
|
|
|
|
- uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ // Angle around the Y axis, counter-clockwise when looking from above.
|
|
|
|
|
|
- // Angle around the Y axis, counter-clockwise when looking from above.
|
|
|
+ function azimuth( vector ) {
|
|
|
|
|
|
- function azimuth( vector ) {
|
|
|
+ return Math.atan2( vector.z, - vector.x );
|
|
|
|
|
|
- return Math.atan2( vector.z, - vector.x );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ // Angle above the XZ plane.
|
|
|
|
|
|
- // Angle above the XZ plane.
|
|
|
+ function inclination( vector ) {
|
|
|
|
|
|
- function inclination( vector ) {
|
|
|
+ return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
|
|
|
|
|
|
- return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
-PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
|
|
|
-PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;
|
|
|
-
|
|
|
|
|
|
export { PolyhedronGeometry, PolyhedronBufferGeometry };
|