pickingInfo.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import { Vector3, Vector2, TmpVectors } from "../Maths/math.vector.js";
  2. import { VertexBuffer } from "../Buffers/buffer.js";
  3. /**
  4. * Information about the result of picking within a scene
  5. * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/interactions/picking_collisions
  6. */
  7. export class PickingInfo {
  8. constructor() {
  9. /**
  10. * If the pick collided with an object
  11. */
  12. this.hit = false;
  13. /**
  14. * Distance away where the pick collided
  15. */
  16. this.distance = 0;
  17. /**
  18. * The location of pick collision
  19. */
  20. this.pickedPoint = null;
  21. /**
  22. * The mesh corresponding the pick collision
  23. */
  24. this.pickedMesh = null;
  25. /** (See getTextureCoordinates) The barycentric U coordinate that is used when calculating the texture coordinates of the collision.*/
  26. this.bu = 0;
  27. /** (See getTextureCoordinates) The barycentric V coordinate that is used when calculating the texture coordinates of the collision.*/
  28. this.bv = 0;
  29. /** The index of the face on the mesh that was picked, or the index of the Line if the picked Mesh is a LinesMesh */
  30. this.faceId = -1;
  31. /** The index of the face on the subMesh that was picked, or the index of the Line if the picked Mesh is a LinesMesh */
  32. this.subMeshFaceId = -1;
  33. /** Id of the submesh that was picked */
  34. this.subMeshId = 0;
  35. /** If a sprite was picked, this will be the sprite the pick collided with */
  36. this.pickedSprite = null;
  37. /** If we are picking a mesh with thin instance, this will give you the picked thin instance */
  38. this.thinInstanceIndex = -1;
  39. /**
  40. * The ray that was used to perform the picking.
  41. */
  42. this.ray = null;
  43. /**
  44. * If a mesh was used to do the picking (eg. 6dof controller) as a "near interaction", this will be populated.
  45. */
  46. this.originMesh = null;
  47. /**
  48. * The aim-space transform of the input used for picking, if it is an XR input source.
  49. */
  50. this.aimTransform = null;
  51. /**
  52. * The grip-space transform of the input used for picking, if it is an XR input source.
  53. * Some XR sources, such as input coming from head mounted displays, do not have this.
  54. */
  55. this.gripTransform = null;
  56. }
  57. /**
  58. * Gets the normal corresponding to the face the pick collided with
  59. * @param useWorldCoordinates If the resulting normal should be relative to the world (default: false)
  60. * @param useVerticesNormals If the vertices normals should be used to calculate the normal instead of the normal map (default: true)
  61. * @returns The normal corresponding to the face the pick collided with
  62. * @remarks Note that the returned normal will always point towards the picking ray.
  63. */
  64. getNormal(useWorldCoordinates = false, useVerticesNormals = true) {
  65. if (!this.pickedMesh || (useVerticesNormals && !this.pickedMesh.isVerticesDataPresent(VertexBuffer.NormalKind))) {
  66. return null;
  67. }
  68. let indices = this.pickedMesh.getIndices();
  69. if (indices?.length === 0) {
  70. indices = null;
  71. }
  72. let result;
  73. const tmp0 = TmpVectors.Vector3[0];
  74. const tmp1 = TmpVectors.Vector3[1];
  75. const tmp2 = TmpVectors.Vector3[2];
  76. if (useVerticesNormals) {
  77. const normals = this.pickedMesh.getVerticesData(VertexBuffer.NormalKind);
  78. let normal0 = indices
  79. ? Vector3.FromArrayToRef(normals, indices[this.faceId * 3] * 3, tmp0)
  80. : tmp0.copyFromFloats(normals[this.faceId * 3 * 3], normals[this.faceId * 3 * 3 + 1], normals[this.faceId * 3 * 3 + 2]);
  81. let normal1 = indices
  82. ? Vector3.FromArrayToRef(normals, indices[this.faceId * 3 + 1] * 3, tmp1)
  83. : tmp1.copyFromFloats(normals[(this.faceId * 3 + 1) * 3], normals[(this.faceId * 3 + 1) * 3 + 1], normals[(this.faceId * 3 + 1) * 3 + 2]);
  84. let normal2 = indices
  85. ? Vector3.FromArrayToRef(normals, indices[this.faceId * 3 + 2] * 3, tmp2)
  86. : tmp2.copyFromFloats(normals[(this.faceId * 3 + 2) * 3], normals[(this.faceId * 3 + 2) * 3 + 1], normals[(this.faceId * 3 + 2) * 3 + 2]);
  87. normal0 = normal0.scale(this.bu);
  88. normal1 = normal1.scale(this.bv);
  89. normal2 = normal2.scale(1.0 - this.bu - this.bv);
  90. result = new Vector3(normal0.x + normal1.x + normal2.x, normal0.y + normal1.y + normal2.y, normal0.z + normal1.z + normal2.z);
  91. }
  92. else {
  93. const positions = this.pickedMesh.getVerticesData(VertexBuffer.PositionKind);
  94. const vertex1 = indices
  95. ? Vector3.FromArrayToRef(positions, indices[this.faceId * 3] * 3, tmp0)
  96. : tmp0.copyFromFloats(positions[this.faceId * 3 * 3], positions[this.faceId * 3 * 3 + 1], positions[this.faceId * 3 * 3 + 2]);
  97. const vertex2 = indices
  98. ? Vector3.FromArrayToRef(positions, indices[this.faceId * 3 + 1] * 3, tmp1)
  99. : tmp1.copyFromFloats(positions[(this.faceId * 3 + 1) * 3], positions[(this.faceId * 3 + 1) * 3 + 1], positions[(this.faceId * 3 + 1) * 3 + 2]);
  100. const vertex3 = indices
  101. ? Vector3.FromArrayToRef(positions, indices[this.faceId * 3 + 2] * 3, tmp2)
  102. : tmp2.copyFromFloats(positions[(this.faceId * 3 + 2) * 3], positions[(this.faceId * 3 + 2) * 3 + 1], positions[(this.faceId * 3 + 2) * 3 + 2]);
  103. const p1p2 = vertex1.subtract(vertex2);
  104. const p3p2 = vertex3.subtract(vertex2);
  105. result = Vector3.Cross(p1p2, p3p2);
  106. }
  107. const transformNormalToWorld = (pickedMesh, n) => {
  108. let wm = pickedMesh.getWorldMatrix();
  109. if (pickedMesh.nonUniformScaling) {
  110. TmpVectors.Matrix[0].copyFrom(wm);
  111. wm = TmpVectors.Matrix[0];
  112. wm.setTranslationFromFloats(0, 0, 0);
  113. wm.invert();
  114. wm.transposeToRef(TmpVectors.Matrix[1]);
  115. wm = TmpVectors.Matrix[1];
  116. }
  117. Vector3.TransformNormalToRef(n, wm, n);
  118. };
  119. if (useWorldCoordinates) {
  120. transformNormalToWorld(this.pickedMesh, result);
  121. }
  122. if (this.ray) {
  123. const normalForDirectionChecking = TmpVectors.Vector3[0].copyFrom(result);
  124. if (!useWorldCoordinates) {
  125. // the normal has not been transformed to world space as part as the normal processing, so we must do it now
  126. transformNormalToWorld(this.pickedMesh, normalForDirectionChecking);
  127. }
  128. // Flip the normal if the picking ray is in the same direction.
  129. if (Vector3.Dot(normalForDirectionChecking, this.ray.direction) > 0) {
  130. result.negateInPlace();
  131. }
  132. }
  133. result.normalize();
  134. return result;
  135. }
  136. /**
  137. * Gets the texture coordinates of where the pick occurred
  138. * @param uvSet The UV set to use to calculate the texture coordinates (default: VertexBuffer.UVKind)
  139. * @returns The vector containing the coordinates of the texture
  140. */
  141. getTextureCoordinates(uvSet = VertexBuffer.UVKind) {
  142. if (!this.pickedMesh || !this.pickedMesh.isVerticesDataPresent(uvSet)) {
  143. return null;
  144. }
  145. const indices = this.pickedMesh.getIndices();
  146. if (!indices) {
  147. return null;
  148. }
  149. const uvs = this.pickedMesh.getVerticesData(uvSet);
  150. if (!uvs) {
  151. return null;
  152. }
  153. let uv0 = Vector2.FromArray(uvs, indices[this.faceId * 3] * 2);
  154. let uv1 = Vector2.FromArray(uvs, indices[this.faceId * 3 + 1] * 2);
  155. let uv2 = Vector2.FromArray(uvs, indices[this.faceId * 3 + 2] * 2);
  156. uv0 = uv0.scale(this.bu);
  157. uv1 = uv1.scale(this.bv);
  158. uv2 = uv2.scale(1.0 - this.bu - this.bv);
  159. return new Vector2(uv0.x + uv1.x + uv2.x, uv0.y + uv1.y + uv2.y);
  160. }
  161. }
  162. //# sourceMappingURL=pickingInfo.js.map