156 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			156 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
									BoxGeometry,
							 | 
						||
| 
								 | 
							
									Vector3
							 | 
						||
| 
								 | 
							
								} from 'three';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const _tempNormal = new Vector3();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function getUv( faceDirVector, normal, uvAxis, projectionAxis, radius, sideLength ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const totArcLength = 2 * Math.PI * radius / 4;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// length of the planes between the arcs on each axis
							 | 
						||
| 
								 | 
							
									const centerLength = Math.max( sideLength - 2 * radius, 0 );
							 | 
						||
| 
								 | 
							
									const halfArc = Math.PI / 4;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Get the vector projected onto the Y plane
							 | 
						||
| 
								 | 
							
									_tempNormal.copy( normal );
							 | 
						||
| 
								 | 
							
									_tempNormal[ projectionAxis ] = 0;
							 | 
						||
| 
								 | 
							
									_tempNormal.normalize();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// total amount of UV space alloted to a single arc
							 | 
						||
| 
								 | 
							
									const arcUvRatio = 0.5 * totArcLength / ( totArcLength + centerLength );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// the distance along one arc the point is at
							 | 
						||
| 
								 | 
							
									const arcAngleRatio = 1.0 - ( _tempNormal.angleTo( faceDirVector ) / halfArc );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if ( Math.sign( _tempNormal[ uvAxis ] ) === 1 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return arcAngleRatio * arcUvRatio;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// total amount of UV space alloted to the plane between the arcs
							 | 
						||
| 
								 | 
							
										const lenUv = centerLength / ( totArcLength + centerLength );
							 | 
						||
| 
								 | 
							
										return lenUv + arcUvRatio + arcUvRatio * ( 1.0 - arcAngleRatio );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class RoundedBoxGeometry extends BoxGeometry {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									constructor( width = 1, height = 1, depth = 1, segments = 2, radius = 0.1 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// ensure segments is odd so we have a plane connecting the rounded corners
							 | 
						||
| 
								 | 
							
										segments = segments * 2 + 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// ensure radius isn't bigger than shortest side
							 | 
						||
| 
								 | 
							
										radius = Math.min( width / 2, height / 2, depth / 2, radius );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										super( 1, 1, 1, segments, segments, segments );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// if we just have one segment we're the same as a regular box
							 | 
						||
| 
								 | 
							
										if ( segments === 1 ) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const geometry2 = this.toNonIndexed();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.index = null;
							 | 
						||
| 
								 | 
							
										this.attributes.position = geometry2.attributes.position;
							 | 
						||
| 
								 | 
							
										this.attributes.normal = geometry2.attributes.normal;
							 | 
						||
| 
								 | 
							
										this.attributes.uv = geometry2.attributes.uv;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const position = new Vector3();
							 | 
						||
| 
								 | 
							
										const normal = new Vector3();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const box = new Vector3( width, height, depth ).divideScalar( 2 ).subScalar( radius );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const positions = this.attributes.position.array;
							 | 
						||
| 
								 | 
							
										const normals = this.attributes.normal.array;
							 | 
						||
| 
								 | 
							
										const uvs = this.attributes.uv.array;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const faceTris = positions.length / 6;
							 | 
						||
| 
								 | 
							
										const faceDirVector = new Vector3();
							 | 
						||
| 
								 | 
							
										const halfSegmentSize = 0.5 / segments;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let i = 0, j = 0; i < positions.length; i += 3, j += 2 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											position.fromArray( positions, i );
							 | 
						||
| 
								 | 
							
											normal.copy( position );
							 | 
						||
| 
								 | 
							
											normal.x -= Math.sign( normal.x ) * halfSegmentSize;
							 | 
						||
| 
								 | 
							
											normal.y -= Math.sign( normal.y ) * halfSegmentSize;
							 | 
						||
| 
								 | 
							
											normal.z -= Math.sign( normal.z ) * halfSegmentSize;
							 | 
						||
| 
								 | 
							
											normal.normalize();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											positions[ i + 0 ] = box.x * Math.sign( position.x ) + normal.x * radius;
							 | 
						||
| 
								 | 
							
											positions[ i + 1 ] = box.y * Math.sign( position.y ) + normal.y * radius;
							 | 
						||
| 
								 | 
							
											positions[ i + 2 ] = box.z * Math.sign( position.z ) + normal.z * radius;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											normals[ i + 0 ] = normal.x;
							 | 
						||
| 
								 | 
							
											normals[ i + 1 ] = normal.y;
							 | 
						||
| 
								 | 
							
											normals[ i + 2 ] = normal.z;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const side = Math.floor( i / faceTris );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											switch ( side ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												case 0: // right
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// generate UVs along Z then Y
							 | 
						||
| 
								 | 
							
													faceDirVector.set( 1, 0, 0 );
							 | 
						||
| 
								 | 
							
													uvs[ j + 0 ] = getUv( faceDirVector, normal, 'z', 'y', radius, depth );
							 | 
						||
| 
								 | 
							
													uvs[ j + 1 ] = 1.0 - getUv( faceDirVector, normal, 'y', 'z', radius, height );
							 | 
						||
| 
								 | 
							
													break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												case 1: // left
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// generate UVs along Z then Y
							 | 
						||
| 
								 | 
							
													faceDirVector.set( - 1, 0, 0 );
							 | 
						||
| 
								 | 
							
													uvs[ j + 0 ] = 1.0 - getUv( faceDirVector, normal, 'z', 'y', radius, depth );
							 | 
						||
| 
								 | 
							
													uvs[ j + 1 ] = 1.0 - getUv( faceDirVector, normal, 'y', 'z', radius, height );
							 | 
						||
| 
								 | 
							
													break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												case 2: // top
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// generate UVs along X then Z
							 | 
						||
| 
								 | 
							
													faceDirVector.set( 0, 1, 0 );
							 | 
						||
| 
								 | 
							
													uvs[ j + 0 ] = 1.0 - getUv( faceDirVector, normal, 'x', 'z', radius, width );
							 | 
						||
| 
								 | 
							
													uvs[ j + 1 ] = getUv( faceDirVector, normal, 'z', 'x', radius, depth );
							 | 
						||
| 
								 | 
							
													break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												case 3: // bottom
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// generate UVs along X then Z
							 | 
						||
| 
								 | 
							
													faceDirVector.set( 0, - 1, 0 );
							 | 
						||
| 
								 | 
							
													uvs[ j + 0 ] = 1.0 - getUv( faceDirVector, normal, 'x', 'z', radius, width );
							 | 
						||
| 
								 | 
							
													uvs[ j + 1 ] = 1.0 - getUv( faceDirVector, normal, 'z', 'x', radius, depth );
							 | 
						||
| 
								 | 
							
													break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												case 4: // front
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// generate UVs along X then Y
							 | 
						||
| 
								 | 
							
													faceDirVector.set( 0, 0, 1 );
							 | 
						||
| 
								 | 
							
													uvs[ j + 0 ] = 1.0 - getUv( faceDirVector, normal, 'x', 'y', radius, width );
							 | 
						||
| 
								 | 
							
													uvs[ j + 1 ] = 1.0 - getUv( faceDirVector, normal, 'y', 'x', radius, height );
							 | 
						||
| 
								 | 
							
													break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												case 5: // back
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// generate UVs along X then Y
							 | 
						||
| 
								 | 
							
													faceDirVector.set( 0, 0, - 1 );
							 | 
						||
| 
								 | 
							
													uvs[ j + 0 ] = getUv( faceDirVector, normal, 'x', 'y', radius, width );
							 | 
						||
| 
								 | 
							
													uvs[ j + 1 ] = 1.0 - getUv( faceDirVector, normal, 'y', 'x', radius, height );
							 | 
						||
| 
								 | 
							
													break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export { RoundedBoxGeometry };
							 |