RoundedBoxBufferGeometry.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import {
  2. BoxBufferGeometry,
  3. Vector3
  4. } from "../../../build/three.module.js";
  5. class RoundedBoxBufferGeometry extends BoxBufferGeometry {
  6. constructor( width = 1, height = 1, depth = 1, segments = 1, radius = 1 ) {
  7. super( 1, 1, 1, segments, segments, segments );
  8. const geometry2 = this.toNonIndexed();
  9. this.index = null;
  10. this.attributes.position = geometry2.attributes.position;
  11. this.attributes.normal = geometry2.attributes.normal;
  12. this.attributes.uv = geometry2.attributes.uv;
  13. //
  14. const position = new Vector3();
  15. const normal = new Vector3();
  16. const box = new Vector3( width, height, depth ).divideScalar( 2 ).subScalar( radius );
  17. const positions = this.attributes.position.array;
  18. const normals = this.attributes.normal.array;
  19. const uvs = this.attributes.uv.array;
  20. const faceTris = positions.length / 6;
  21. const arcLength = 2 * Math.PI * radius / 4;
  22. const widthLength = Math.max( width - 2 * radius, 0 );
  23. const heightLength = Math.max( height - 2 * radius, 0 );
  24. const depthLength = Math.max( depth - 2 * radius, 0 );
  25. for ( let i = 0, j = 0; i < positions.length; i += 3, j += 2 ) {
  26. position.fromArray( positions, i );
  27. normal.copy( position ).normalize();
  28. positions[ i + 0 ] = box.x * Math.sign( position.x ) + normal.x * radius;
  29. positions[ i + 1 ] = box.y * Math.sign( position.y ) + normal.y * radius;
  30. positions[ i + 2 ] = box.z * Math.sign( position.z ) + normal.z * radius;
  31. normals[ i + 0 ] = normal.x;
  32. normals[ i + 1 ] = normal.y;
  33. normals[ i + 2 ] = normal.z;
  34. const side = Math.floor( i / faceTris );
  35. switch ( side ) {
  36. case 0: // right
  37. const tempNormal = new Vector3();
  38. const rightVector = new Vector3( 1, 0, 0 );
  39. const totArcLength = 2 * Math.PI * radius / 4;
  40. // length of the planes between the arcs on each axis
  41. const heightLength = Math.max( height - 2 * radius, 0 );
  42. const depthLength = Math.max( depth - 2 * radius, 0 );
  43. const halfArc = Math.PI / 4;
  44. // Get the vector projected onto the Y plane
  45. tempNormal.copy( normal );
  46. tempNormal.y = 0;
  47. tempNormal.normalize();
  48. // total amount of UV space alloted to a single arc
  49. const arcUvRatioZ = 0.5 * totArcLength / ( totArcLength + depthLength );
  50. // the distance along one arc the point is at
  51. const arcAngleRatioZ = 1.0 - ( tempNormal.angleTo( rightVector ) / halfArc );
  52. if ( Math.sign( tempNormal.z ) === 1 ) {
  53. uvs[ j + 0 ] = arcAngleRatioZ * arcUvRatioZ;
  54. } else {
  55. // total amount of UV space alloted to the plane between the arcs
  56. const lenUv = depthLength / ( totArcLength + depthLength );
  57. uvs[ j + 0 ] = lenUv + arcUvRatioZ + arcUvRatioZ * ( 1.0 - arcAngleRatioZ );
  58. }
  59. tempNormal.copy( normal );
  60. tempNormal.z = 0;
  61. tempNormal.normalize();
  62. const arcUvRatioY = 0.5 * totArcLength / ( totArcLength + heightLength );
  63. const arcAngleRatioY = 1.0 - ( tempNormal.angleTo( rightVector ) / halfArc );
  64. if ( Math.sign( tempNormal.y ) === - 1 ) {
  65. uvs[ j + 1 ] = arcAngleRatioY * arcUvRatioY;
  66. } else {
  67. const lenUv = heightLength / ( totArcLength + heightLength );
  68. uvs[ j + 1 ] = lenUv + arcUvRatioY + arcUvRatioY * ( 1.0 - arcAngleRatioY );
  69. }
  70. break;
  71. // case 1: // left
  72. // uvs[ j + 0 ] = 0.5 + ( positions[ i + 2 ] / ( depth - radius ) );
  73. // uvs[ j + 1 ] = 0.5 + ( positions[ i + 1 ] / ( height - radius ) );
  74. // break;
  75. // case 2: // top
  76. // uvs[ j + 0 ] = 0.5 + ( positions[ i + 0 ] / ( width - radius ) );
  77. // uvs[ j + 1 ] = 0.5 - ( positions[ i + 2 ] / ( depth - radius ) );
  78. // break;
  79. // case 3: // bottom
  80. // uvs[ j + 0 ] = 0.5 + ( positions[ i + 0 ] / ( width - radius ) );
  81. // uvs[ j + 1 ] = 0.5 + ( positions[ i + 2 ] / ( depth - radius ) );
  82. // break;
  83. // case 4: // front
  84. // uvs[ j + 0 ] = 0.5 + ( positions[ i + 0 ] / ( width - radius ) );
  85. // uvs[ j + 1 ] = 0.5 + ( positions[ i + 1 ] / ( height - radius ) );
  86. // break;
  87. // case 5: // back
  88. // uvs[ j + 0 ] = 0.5 - ( positions[ i + 0 ] / ( width - radius ) );
  89. // uvs[ j + 1 ] = 0.5 + ( positions[ i + 1 ] / ( height - radius ) );
  90. // break;
  91. }
  92. }
  93. }
  94. }
  95. export { RoundedBoxBufferGeometry };