PositionalAudioHelper.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import {
  2. BufferGeometry,
  3. BufferAttribute,
  4. LineBasicMaterial,
  5. Line,
  6. MathUtils
  7. } from 'three';
  8. class PositionalAudioHelper extends Line {
  9. constructor( audio, range = 1, divisionsInnerAngle = 16, divisionsOuterAngle = 2 ) {
  10. const geometry = new BufferGeometry();
  11. const divisions = divisionsInnerAngle + divisionsOuterAngle * 2;
  12. const positions = new Float32Array( ( divisions * 3 + 3 ) * 3 );
  13. geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
  14. const materialInnerAngle = new LineBasicMaterial( { color: 0x00ff00 } );
  15. const materialOuterAngle = new LineBasicMaterial( { color: 0xffff00 } );
  16. super( geometry, [ materialOuterAngle, materialInnerAngle ] );
  17. this.audio = audio;
  18. this.range = range;
  19. this.divisionsInnerAngle = divisionsInnerAngle;
  20. this.divisionsOuterAngle = divisionsOuterAngle;
  21. this.type = 'PositionalAudioHelper';
  22. this.update();
  23. }
  24. update() {
  25. const audio = this.audio;
  26. const range = this.range;
  27. const divisionsInnerAngle = this.divisionsInnerAngle;
  28. const divisionsOuterAngle = this.divisionsOuterAngle;
  29. const coneInnerAngle = MathUtils.degToRad( audio.panner.coneInnerAngle );
  30. const coneOuterAngle = MathUtils.degToRad( audio.panner.coneOuterAngle );
  31. const halfConeInnerAngle = coneInnerAngle / 2;
  32. const halfConeOuterAngle = coneOuterAngle / 2;
  33. let start = 0;
  34. let count = 0;
  35. let i;
  36. let stride;
  37. const geometry = this.geometry;
  38. const positionAttribute = geometry.attributes.position;
  39. geometry.clearGroups();
  40. //
  41. function generateSegment( from, to, divisions, materialIndex ) {
  42. const step = ( to - from ) / divisions;
  43. positionAttribute.setXYZ( start, 0, 0, 0 );
  44. count ++;
  45. for ( i = from; i < to; i += step ) {
  46. stride = start + count;
  47. positionAttribute.setXYZ( stride, Math.sin( i ) * range, 0, Math.cos( i ) * range );
  48. positionAttribute.setXYZ( stride + 1, Math.sin( Math.min( i + step, to ) ) * range, 0, Math.cos( Math.min( i + step, to ) ) * range );
  49. positionAttribute.setXYZ( stride + 2, 0, 0, 0 );
  50. count += 3;
  51. }
  52. geometry.addGroup( start, count, materialIndex );
  53. start += count;
  54. count = 0;
  55. }
  56. //
  57. generateSegment( - halfConeOuterAngle, - halfConeInnerAngle, divisionsOuterAngle, 0 );
  58. generateSegment( - halfConeInnerAngle, halfConeInnerAngle, divisionsInnerAngle, 1 );
  59. generateSegment( halfConeInnerAngle, halfConeOuterAngle, divisionsOuterAngle, 0 );
  60. //
  61. positionAttribute.needsUpdate = true;
  62. if ( coneInnerAngle === coneOuterAngle ) this.material[ 0 ].visible = false;
  63. }
  64. dispose() {
  65. this.geometry.dispose();
  66. this.material[ 0 ].dispose();
  67. this.material[ 1 ].dispose();
  68. }
  69. }
  70. export { PositionalAudioHelper };