Sprite.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /**
  2. * @author mikael emtinger / http://gomo.se/
  3. * @author alteredq / http://alteredqualia.com/
  4. */
  5. import { Vector2 } from '../math/Vector2.js';
  6. import { Vector3 } from '../math/Vector3.js';
  7. import { Matrix4 } from '../math/Matrix4.js';
  8. import { Triangle } from '../math/Triangle.js';
  9. import { Object3D } from '../core/Object3D.js';
  10. import { BufferGeometry } from '../core/BufferGeometry.js';
  11. import { InterleavedBuffer } from '../core/InterleavedBuffer.js';
  12. import { InterleavedBufferAttribute } from '../core/InterleavedBufferAttribute.js';
  13. import { SpriteMaterial } from '../materials/SpriteMaterial.js';
  14. let _geometry;
  15. const _intersectPoint = new Vector3();
  16. const _worldScale = new Vector3();
  17. const _mvPosition = new Vector3();
  18. const _alignedPosition = new Vector2();
  19. const _rotatedPosition = new Vector2();
  20. const _viewWorldMatrix = new Matrix4();
  21. const _vA = new Vector3();
  22. const _vB = new Vector3();
  23. const _vC = new Vector3();
  24. const _uvA = new Vector2();
  25. const _uvB = new Vector2();
  26. const _uvC = new Vector2();
  27. function Sprite( material ) {
  28. Object3D.call( this );
  29. this.type = 'Sprite';
  30. if ( _geometry === undefined ) {
  31. _geometry = new BufferGeometry();
  32. const float32Array = new Float32Array( [
  33. - 0.5, - 0.5, 0, 0, 0,
  34. 0.5, - 0.5, 0, 1, 0,
  35. 0.5, 0.5, 0, 1, 1,
  36. - 0.5, 0.5, 0, 0, 1
  37. ] );
  38. const interleavedBuffer = new InterleavedBuffer( float32Array, 5 );
  39. _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] );
  40. _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
  41. _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
  42. }
  43. this.geometry = _geometry;
  44. this.material = ( material !== undefined ) ? material : new SpriteMaterial();
  45. this.center = new Vector2( 0.5, 0.5 );
  46. }
  47. Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {
  48. constructor: Sprite,
  49. isSprite: true,
  50. raycast: function ( raycaster, intersects ) {
  51. if ( raycaster.camera === null ) {
  52. console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' );
  53. }
  54. _worldScale.setFromMatrixScale( this.matrixWorld );
  55. _viewWorldMatrix.copy( raycaster.camera.matrixWorld );
  56. this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );
  57. _mvPosition.setFromMatrixPosition( this.modelViewMatrix );
  58. if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {
  59. _worldScale.multiplyScalar( - _mvPosition.z );
  60. }
  61. const rotation = this.material.rotation;
  62. let sin, cos;
  63. if ( rotation !== 0 ) {
  64. cos = Math.cos( rotation );
  65. sin = Math.sin( rotation );
  66. }
  67. const center = this.center;
  68. transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
  69. transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
  70. transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
  71. _uvA.set( 0, 0 );
  72. _uvB.set( 1, 0 );
  73. _uvC.set( 1, 1 );
  74. // check first triangle
  75. let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint );
  76. if ( intersect === null ) {
  77. // check second triangle
  78. transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
  79. _uvB.set( 0, 1 );
  80. intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint );
  81. if ( intersect === null ) {
  82. return;
  83. }
  84. }
  85. const distance = raycaster.ray.origin.distanceTo( _intersectPoint );
  86. if ( distance < raycaster.near || distance > raycaster.far ) return;
  87. intersects.push( {
  88. distance: distance,
  89. point: _intersectPoint.clone(),
  90. uv: Triangle.getUV( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ),
  91. face: null,
  92. object: this
  93. } );
  94. },
  95. clone: function () {
  96. return new this.constructor( this.material ).copy( this );
  97. },
  98. copy: function ( source ) {
  99. Object3D.prototype.copy.call( this, source );
  100. if ( source.center !== undefined ) this.center.copy( source.center );
  101. return this;
  102. }
  103. } );
  104. function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {
  105. // compute position in camera space
  106. _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );
  107. // to check if rotation is not zero
  108. if ( sin !== undefined ) {
  109. _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y );
  110. _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y );
  111. } else {
  112. _rotatedPosition.copy( _alignedPosition );
  113. }
  114. vertexPosition.copy( mvPosition );
  115. vertexPosition.x += _rotatedPosition.x;
  116. vertexPosition.y += _rotatedPosition.y;
  117. // transform to world space
  118. vertexPosition.applyMatrix4( _viewWorldMatrix );
  119. }
  120. export { Sprite };