InstancedMesh.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. */
  4. import { BufferAttribute } from '../core/BufferAttribute.js';
  5. import { Mesh } from './Mesh.js';
  6. import { Vector3 } from '../math/Vector3.js';
  7. import { Vector2 } from '../math/Vector2.js';
  8. import { Sphere } from '../math/Sphere.js';
  9. import { Ray } from '../math/Ray.js';
  10. import { Matrix4 } from '../math/Matrix4.js';
  11. import { Triangle } from '../math/Triangle.js';
  12. import { Face3 } from '../core/Face3.js';
  13. import { DoubleSide, BackSide } from '../constants.js';
  14. var _inverseMatrix = new Matrix4();
  15. var _ray = new Ray();
  16. var _sphere = new Sphere();
  17. var _vA = new Vector3();
  18. var _vB = new Vector3();
  19. var _vC = new Vector3();
  20. var _uvA = new Vector2();
  21. var _uvB = new Vector2();
  22. var _uvC = new Vector2();
  23. var _intersectionPoint = new Vector3();
  24. var _intersectionPointWorld = new Vector3();
  25. function InstancedMesh( geometry, material, count ) {
  26. Mesh.call( this, geometry, material );
  27. this.instanceMatrix = new BufferAttribute( new Float32Array( count * 16 ), 16 );
  28. this.count = count;
  29. }
  30. InstancedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
  31. constructor: InstancedMesh,
  32. isInstancedMesh: true,
  33. raycast: function ( raycaster, intersects ) {
  34. var geometry = this.geometry;
  35. var material = this.material;
  36. var matrixWorld = this.matrixWorld;
  37. if ( material === undefined ) return;
  38. for ( var instanceID = 0; instanceID < this.count; instanceID ++ ) {
  39. //Calculate the world matrix for each instance
  40. var instanceMatrixWorld = new Matrix4();
  41. var instanceMatrix = this.getMatrixAt( instanceID );
  42. instanceMatrixWorld.multiplyMatrices( matrixWorld, instanceMatrix );
  43. // Checking boundingSphere distance to ray
  44. if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
  45. _sphere.copy( geometry.boundingSphere );
  46. _sphere.applyMatrix4( instanceMatrixWorld );
  47. if ( raycaster.ray.intersectsSphere( _sphere ) === false ) continue;
  48. //Transform the ray into the local space of the model
  49. _inverseMatrix.getInverse( instanceMatrixWorld );
  50. _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
  51. // Check boundingBox before continuing
  52. if ( geometry.boundingBox !== null ) {
  53. if ( _ray.intersectsBox( geometry.boundingBox ) === false ) continue;
  54. }
  55. var intersection;
  56. if ( geometry.isBufferGeometry ) {
  57. var a, b, c;
  58. var index = geometry.index;
  59. var position = geometry.attributes.position;
  60. var uv = geometry.attributes.uv;
  61. var uv2 = geometry.attributes.uv2;
  62. var groups = geometry.groups;
  63. var drawRange = geometry.drawRange;
  64. var i, j, il, jl;
  65. var group, groupMaterial;
  66. var start, end;
  67. if ( index !== null ) {
  68. // indexed buffer geometry
  69. if ( Array.isArray( material ) ) {
  70. for ( i = 0, il = groups.length; i < il; i ++ ) {
  71. group = groups[ i ];
  72. groupMaterial = material[ group.materialIndex ];
  73. start = Math.max( group.start, drawRange.start );
  74. end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
  75. for ( j = start, jl = end; j < jl; j += 3 ) {
  76. a = index.getX( j );
  77. b = index.getX( j + 1 );
  78. c = index.getX( j + 2 );
  79. intersection = checkBufferGeometryIntersection( this, instanceMatrixWorld, groupMaterial, raycaster, _ray, position, uv, uv2, a, b, c );
  80. if ( intersection ) {
  81. intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics
  82. intersection.face.materialIndex = group.materialIndex;
  83. intersection.instanceID = instanceID;
  84. intersects.push( intersection );
  85. }
  86. }
  87. }
  88. } else {
  89. start = Math.max( 0, drawRange.start );
  90. end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
  91. for ( i = start, il = end; i < il; i += 3 ) {
  92. a = index.getX( i );
  93. b = index.getX( i + 1 );
  94. c = index.getX( i + 2 );
  95. intersection = checkBufferGeometryIntersection( this, instanceMatrixWorld, material, raycaster, _ray, position, uv, uv2, a, b, c );
  96. if ( intersection ) {
  97. intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
  98. intersection.instanceID = instanceID;
  99. intersects.push( intersection );
  100. }
  101. }
  102. }
  103. } else if ( position !== undefined ) {
  104. // non-indexed buffer geometry
  105. if ( Array.isArray( material ) ) {
  106. for ( i = 0, il = groups.length; i < il; i ++ ) {
  107. group = groups[ i ];
  108. groupMaterial = material[ group.materialIndex ];
  109. start = Math.max( group.start, drawRange.start );
  110. end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
  111. for ( j = start, jl = end; j < jl; j += 3 ) {
  112. a = j;
  113. b = j + 1;
  114. c = j + 2;
  115. intersection = checkBufferGeometryIntersection( this, instanceMatrixWorld, groupMaterial, raycaster, _ray, position, uv, uv2, a, b, c );
  116. if ( intersection ) {
  117. intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics
  118. intersection.face.materialIndex = group.materialIndex;
  119. intersection.instanceID = instanceID;
  120. intersects.push( intersection );
  121. }
  122. }
  123. }
  124. } else {
  125. start = Math.max( 0, drawRange.start );
  126. end = Math.min( position.count, ( drawRange.start + drawRange.count ) );
  127. for ( i = start, il = end; i < il; i += 3 ) {
  128. a = i;
  129. b = i + 1;
  130. c = i + 2;
  131. intersection = checkBufferGeometryIntersection( this, instanceMatrixWorld, material, raycaster, _ray, position, uv, uv2, a, b, c );
  132. if ( intersection ) {
  133. intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
  134. intersection.instanceID = instanceID;
  135. intersects.push( intersection );
  136. }
  137. }
  138. }
  139. }
  140. }
  141. }
  142. },
  143. getMatrixAt: function ( index ) {
  144. var matrix = new Matrix4();
  145. matrix.fromArray( this.instanceMatrix.array, index * 16 );
  146. return matrix;
  147. },
  148. setMatrixAt: function ( index, matrix ) {
  149. matrix.toArray( this.instanceMatrix.array, index * 16 );
  150. },
  151. updateMorphTargets: function () {
  152. }
  153. } );
  154. function checkIntersection( object, matrixWorld, material, raycaster, ray, pA, pB, pC, point ) {
  155. var intersect;
  156. if ( material.side === BackSide ) {
  157. intersect = ray.intersectTriangle( pC, pB, pA, true, point );
  158. } else {
  159. intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
  160. }
  161. if ( intersect === null ) return null;
  162. _intersectionPointWorld.copy( point );
  163. _intersectionPointWorld.applyMatrix4( matrixWorld );
  164. var distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );
  165. if ( distance < raycaster.near || distance > raycaster.far ) return null;
  166. return {
  167. distance: distance,
  168. point: _intersectionPointWorld.clone(),
  169. object: object
  170. };
  171. }
  172. function checkBufferGeometryIntersection( object, matrixWorld, material, raycaster, ray, position, uv, uv2, a, b, c ) {
  173. _vA.fromBufferAttribute( position, a );
  174. _vB.fromBufferAttribute( position, b );
  175. _vC.fromBufferAttribute( position, c );
  176. var intersection = checkIntersection( object, matrixWorld, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint );
  177. if ( intersection ) {
  178. if ( uv ) {
  179. _uvA.fromBufferAttribute( uv, a );
  180. _uvB.fromBufferAttribute( uv, b );
  181. _uvC.fromBufferAttribute( uv, c );
  182. intersection.uv = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() );
  183. }
  184. if ( uv2 ) {
  185. _uvA.fromBufferAttribute( uv2, a );
  186. _uvB.fromBufferAttribute( uv2, b );
  187. _uvC.fromBufferAttribute( uv2, c );
  188. intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() );
  189. }
  190. var face = new Face3( a, b, c );
  191. Triangle.getNormal( _vA, _vB, _vC, face.normal );
  192. intersection.face = face;
  193. }
  194. return intersection;
  195. }
  196. export { InstancedMesh };