| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 | import {	BoxGeometry,	Vector3} from '../../../build/three.module.js';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 };
 |