TubePainter.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import {
  2. BufferAttribute,
  3. BufferGeometry,
  4. Color,
  5. DynamicDrawUsage,
  6. Matrix4,
  7. Mesh,
  8. MeshStandardMaterial,
  9. Vector3
  10. } from 'three';
  11. function TubePainter() {
  12. const BUFFER_SIZE = 1000000 * 3;
  13. const positions = new BufferAttribute( new Float32Array( BUFFER_SIZE ), 3 );
  14. positions.usage = DynamicDrawUsage;
  15. const normals = new BufferAttribute( new Float32Array( BUFFER_SIZE ), 3 );
  16. normals.usage = DynamicDrawUsage;
  17. const colors = new BufferAttribute( new Float32Array( BUFFER_SIZE ), 3 );
  18. colors.usage = DynamicDrawUsage;
  19. const geometry = new BufferGeometry();
  20. geometry.setAttribute( 'position', positions );
  21. geometry.setAttribute( 'normal', normals );
  22. geometry.setAttribute( 'color', colors );
  23. geometry.drawRange.count = 0;
  24. const material = new MeshStandardMaterial( {
  25. vertexColors: true
  26. } );
  27. const mesh = new Mesh( geometry, material );
  28. mesh.frustumCulled = false;
  29. //
  30. function getPoints( size ) {
  31. const PI2 = Math.PI * 2;
  32. const sides = 10;
  33. const array = [];
  34. const radius = 0.01 * size;
  35. for ( let i = 0; i < sides; i ++ ) {
  36. const angle = ( i / sides ) * PI2;
  37. array.push( new Vector3( Math.sin( angle ) * radius, Math.cos( angle ) * radius, 0 ) );
  38. }
  39. return array;
  40. }
  41. //
  42. const vector1 = new Vector3();
  43. const vector2 = new Vector3();
  44. const vector3 = new Vector3();
  45. const vector4 = new Vector3();
  46. const color = new Color( 0xffffff );
  47. let size = 1;
  48. function stroke( position1, position2, matrix1, matrix2 ) {
  49. if ( position1.distanceToSquared( position2 ) === 0 ) return;
  50. let count = geometry.drawRange.count;
  51. const points = getPoints( size );
  52. for ( let i = 0, il = points.length; i < il; i ++ ) {
  53. const vertex1 = points[ i ];
  54. const vertex2 = points[ ( i + 1 ) % il ];
  55. // positions
  56. vector1.copy( vertex1 ).applyMatrix4( matrix2 ).add( position2 );
  57. vector2.copy( vertex2 ).applyMatrix4( matrix2 ).add( position2 );
  58. vector3.copy( vertex2 ).applyMatrix4( matrix1 ).add( position1 );
  59. vector4.copy( vertex1 ).applyMatrix4( matrix1 ).add( position1 );
  60. vector1.toArray( positions.array, ( count + 0 ) * 3 );
  61. vector2.toArray( positions.array, ( count + 1 ) * 3 );
  62. vector4.toArray( positions.array, ( count + 2 ) * 3 );
  63. vector2.toArray( positions.array, ( count + 3 ) * 3 );
  64. vector3.toArray( positions.array, ( count + 4 ) * 3 );
  65. vector4.toArray( positions.array, ( count + 5 ) * 3 );
  66. // normals
  67. vector1.copy( vertex1 ).applyMatrix4( matrix2 ).normalize();
  68. vector2.copy( vertex2 ).applyMatrix4( matrix2 ).normalize();
  69. vector3.copy( vertex2 ).applyMatrix4( matrix1 ).normalize();
  70. vector4.copy( vertex1 ).applyMatrix4( matrix1 ).normalize();
  71. vector1.toArray( normals.array, ( count + 0 ) * 3 );
  72. vector2.toArray( normals.array, ( count + 1 ) * 3 );
  73. vector4.toArray( normals.array, ( count + 2 ) * 3 );
  74. vector2.toArray( normals.array, ( count + 3 ) * 3 );
  75. vector3.toArray( normals.array, ( count + 4 ) * 3 );
  76. vector4.toArray( normals.array, ( count + 5 ) * 3 );
  77. // colors
  78. color.toArray( colors.array, ( count + 0 ) * 3 );
  79. color.toArray( colors.array, ( count + 1 ) * 3 );
  80. color.toArray( colors.array, ( count + 2 ) * 3 );
  81. color.toArray( colors.array, ( count + 3 ) * 3 );
  82. color.toArray( colors.array, ( count + 4 ) * 3 );
  83. color.toArray( colors.array, ( count + 5 ) * 3 );
  84. count += 6;
  85. }
  86. geometry.drawRange.count = count;
  87. }
  88. //
  89. const up = new Vector3( 0, 1, 0 );
  90. const point1 = new Vector3();
  91. const point2 = new Vector3();
  92. const matrix1 = new Matrix4();
  93. const matrix2 = new Matrix4();
  94. function moveTo( position ) {
  95. point1.copy( position );
  96. matrix1.lookAt( point2, point1, up );
  97. point2.copy( position );
  98. matrix2.copy( matrix1 );
  99. }
  100. function lineTo( position ) {
  101. point1.copy( position );
  102. matrix1.lookAt( point2, point1, up );
  103. stroke( point1, point2, matrix1, matrix2 );
  104. point2.copy( point1 );
  105. matrix2.copy( matrix1 );
  106. }
  107. function setSize( value ) {
  108. size = value;
  109. }
  110. //
  111. let count = 0;
  112. function update() {
  113. const start = count;
  114. const end = geometry.drawRange.count;
  115. if ( start === end ) return;
  116. positions.updateRange.offset = start * 3;
  117. positions.updateRange.count = ( end - start ) * 3;
  118. positions.needsUpdate = true;
  119. normals.updateRange.offset = start * 3;
  120. normals.updateRange.count = ( end - start ) * 3;
  121. normals.needsUpdate = true;
  122. colors.updateRange.offset = start * 3;
  123. colors.updateRange.count = ( end - start ) * 3;
  124. colors.needsUpdate = true;
  125. count = geometry.drawRange.count;
  126. }
  127. return {
  128. mesh: mesh,
  129. moveTo: moveTo,
  130. lineTo: lineTo,
  131. setSize: setSize,
  132. update: update
  133. };
  134. }
  135. export { TubePainter };