Spaces:
Running
Running
File size: 4,625 Bytes
a28eca3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
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 };
|