@babylonjs/core 7.27.2 → 7.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/Animations/animatable.core.d.ts +198 -0
  2. package/Animations/animatable.core.js +893 -0
  3. package/Animations/animatable.core.js.map +1 -0
  4. package/Animations/animatable.d.ts +4 -213
  5. package/Animations/animatable.js +5 -886
  6. package/Animations/animatable.js.map +1 -1
  7. package/Animations/animationGroup.d.ts +1 -1
  8. package/Animations/animationGroup.js.map +1 -1
  9. package/Animations/runtimeAnimation.d.ts +1 -0
  10. package/Animations/runtimeAnimation.js +25 -1
  11. package/Animations/runtimeAnimation.js.map +1 -1
  12. package/Audio/audioSceneComponent.d.ts +0 -4
  13. package/Audio/audioSceneComponent.js.map +1 -1
  14. package/Behaviors/Cameras/bouncingBehavior.js.map +1 -1
  15. package/Behaviors/Cameras/framingBehavior.js.map +1 -1
  16. package/Bones/skeleton.d.ts +1 -1
  17. package/Bones/skeleton.js.map +1 -1
  18. package/Culling/ray.core.d.ts +328 -0
  19. package/Culling/ray.core.js +931 -0
  20. package/Culling/ray.core.js.map +1 -0
  21. package/Culling/ray.d.ts +1 -220
  22. package/Culling/ray.js +12 -791
  23. package/Culling/ray.js.map +1 -1
  24. package/Engines/WebGPU/webgpuBufferManager.js +3 -2
  25. package/Engines/WebGPU/webgpuBufferManager.js.map +1 -1
  26. package/Engines/WebGPU/webgpuPipelineContext.js +1 -0
  27. package/Engines/WebGPU/webgpuPipelineContext.js.map +1 -1
  28. package/Engines/abstractEngine.js +2 -2
  29. package/Engines/abstractEngine.js.map +1 -1
  30. package/Engines/index.d.ts +1 -0
  31. package/Engines/index.js +1 -0
  32. package/Engines/index.js.map +1 -1
  33. package/FlowGraph/Blocks/Execution/Animation/flowGraphPauseAnimationBlock.d.ts +1 -1
  34. package/FlowGraph/Blocks/Execution/Animation/flowGraphPauseAnimationBlock.js.map +1 -1
  35. package/FlowGraph/Blocks/Execution/Animation/flowGraphPlayAnimationBlock.d.ts +1 -1
  36. package/FlowGraph/Blocks/Execution/Animation/flowGraphPlayAnimationBlock.js.map +1 -1
  37. package/FlowGraph/Blocks/Execution/Animation/flowGraphStopAnimationBlock.d.ts +1 -1
  38. package/FlowGraph/Blocks/Execution/Animation/flowGraphStopAnimationBlock.js.map +1 -1
  39. package/Inputs/scene.inputManager.js +2 -1
  40. package/Inputs/scene.inputManager.js.map +1 -1
  41. package/Layers/effectLayerSceneComponent.d.ts +0 -6
  42. package/Layers/effectLayerSceneComponent.js +0 -1
  43. package/Layers/effectLayerSceneComponent.js.map +1 -1
  44. package/Layers/layerSceneComponent.d.ts +0 -9
  45. package/Layers/layerSceneComponent.js +0 -1
  46. package/Layers/layerSceneComponent.js.map +1 -1
  47. package/LensFlares/lensFlareSystemSceneComponent.d.ts +0 -5
  48. package/LensFlares/lensFlareSystemSceneComponent.js +0 -1
  49. package/LensFlares/lensFlareSystemSceneComponent.js.map +1 -1
  50. package/Lights/light.js.map +1 -1
  51. package/Materials/Textures/Procedurals/proceduralTextureSceneComponent.d.ts +0 -10
  52. package/Materials/Textures/Procedurals/proceduralTextureSceneComponent.js +0 -1
  53. package/Materials/Textures/Procedurals/proceduralTextureSceneComponent.js.map +1 -1
  54. package/Meshes/Node/Blocks/geometryInterceptorBlock.d.ts +36 -0
  55. package/Meshes/Node/Blocks/geometryInterceptorBlock.js +60 -0
  56. package/Meshes/Node/Blocks/geometryInterceptorBlock.js.map +1 -0
  57. package/Meshes/Node/index.d.ts +1 -0
  58. package/Meshes/Node/index.js +1 -0
  59. package/Meshes/Node/index.js.map +1 -1
  60. package/Meshes/WebGPU/webgpuDataBuffer.d.ts +3 -1
  61. package/Meshes/WebGPU/webgpuDataBuffer.js +6 -1
  62. package/Meshes/WebGPU/webgpuDataBuffer.js.map +1 -1
  63. package/Misc/assetsManager.d.ts +1 -1
  64. package/Misc/assetsManager.js.map +1 -1
  65. package/Misc/tools.js +1 -13
  66. package/Misc/tools.js.map +1 -1
  67. package/Sprites/spriteSceneComponent.d.ts +1 -1
  68. package/Sprites/spriteSceneComponent.js +4 -4
  69. package/Sprites/spriteSceneComponent.js.map +1 -1
  70. package/assetContainer.d.ts +1 -1
  71. package/assetContainer.js.map +1 -1
  72. package/import.helper.d.ts +5 -0
  73. package/import.helper.js +6 -0
  74. package/import.helper.js.map +1 -0
  75. package/node.d.ts +1 -1
  76. package/node.js.map +1 -1
  77. package/package.json +1 -1
  78. package/scene.d.ts +41 -4
  79. package/scene.js +25 -6
  80. package/scene.js.map +1 -1
@@ -0,0 +1,931 @@
1
+ import { Epsilon } from "../Maths/math.constants.js";
2
+ import { Matrix, TmpVectors, Vector3 } from "../Maths/math.vector.js";
3
+ import { BuildArray } from "../Misc/arrayTools.js";
4
+ import { IntersectionInfo } from "../Collisions/intersectionInfo.js";
5
+ import { PickingInfo } from "../Collisions/pickingInfo.js";
6
+ import { EngineStore } from "../Engines/engineStore.js";
7
+ import { _ImportHelper } from "../import.helper.js";
8
+ /**
9
+ * Class representing a ray with position and direction
10
+ */
11
+ export class Ray {
12
+ /**
13
+ * Creates a new ray
14
+ * @param origin origin point
15
+ * @param direction direction
16
+ * @param length length of the ray
17
+ * @param epsilon The epsilon value to use when calculating the ray/triangle intersection (default: 0)
18
+ */
19
+ constructor(
20
+ /** origin point */
21
+ origin,
22
+ /** direction */
23
+ direction,
24
+ /** [Number.MAX_VALUE] length of the ray */
25
+ length = Number.MAX_VALUE,
26
+ /** [Epsilon] The epsilon value to use when calculating the ray/triangle intersection (default: Epsilon from math constants) */
27
+ epsilon = Epsilon) {
28
+ this.origin = origin;
29
+ this.direction = direction;
30
+ this.length = length;
31
+ this.epsilon = epsilon;
32
+ }
33
+ // Methods
34
+ /**
35
+ * Clone the current ray
36
+ * @returns a new ray
37
+ */
38
+ clone() {
39
+ return new Ray(this.origin.clone(), this.direction.clone(), this.length);
40
+ }
41
+ /**
42
+ * Checks if the ray intersects a box
43
+ * This does not account for the ray length by design to improve perfs.
44
+ * @param minimum bound of the box
45
+ * @param maximum bound of the box
46
+ * @param intersectionTreshold extra extend to be added to the box in all direction
47
+ * @returns if the box was hit
48
+ */
49
+ intersectsBoxMinMax(minimum, maximum, intersectionTreshold = 0) {
50
+ const newMinimum = Ray._TmpVector3[0].copyFromFloats(minimum.x - intersectionTreshold, minimum.y - intersectionTreshold, minimum.z - intersectionTreshold);
51
+ const newMaximum = Ray._TmpVector3[1].copyFromFloats(maximum.x + intersectionTreshold, maximum.y + intersectionTreshold, maximum.z + intersectionTreshold);
52
+ let d = 0.0;
53
+ let maxValue = Number.MAX_VALUE;
54
+ let inv;
55
+ let min;
56
+ let max;
57
+ let temp;
58
+ if (Math.abs(this.direction.x) < 0.0000001) {
59
+ if (this.origin.x < newMinimum.x || this.origin.x > newMaximum.x) {
60
+ return false;
61
+ }
62
+ }
63
+ else {
64
+ inv = 1.0 / this.direction.x;
65
+ min = (newMinimum.x - this.origin.x) * inv;
66
+ max = (newMaximum.x - this.origin.x) * inv;
67
+ if (max === -Infinity) {
68
+ max = Infinity;
69
+ }
70
+ if (min > max) {
71
+ temp = min;
72
+ min = max;
73
+ max = temp;
74
+ }
75
+ d = Math.max(min, d);
76
+ maxValue = Math.min(max, maxValue);
77
+ if (d > maxValue) {
78
+ return false;
79
+ }
80
+ }
81
+ if (Math.abs(this.direction.y) < 0.0000001) {
82
+ if (this.origin.y < newMinimum.y || this.origin.y > newMaximum.y) {
83
+ return false;
84
+ }
85
+ }
86
+ else {
87
+ inv = 1.0 / this.direction.y;
88
+ min = (newMinimum.y - this.origin.y) * inv;
89
+ max = (newMaximum.y - this.origin.y) * inv;
90
+ if (max === -Infinity) {
91
+ max = Infinity;
92
+ }
93
+ if (min > max) {
94
+ temp = min;
95
+ min = max;
96
+ max = temp;
97
+ }
98
+ d = Math.max(min, d);
99
+ maxValue = Math.min(max, maxValue);
100
+ if (d > maxValue) {
101
+ return false;
102
+ }
103
+ }
104
+ if (Math.abs(this.direction.z) < 0.0000001) {
105
+ if (this.origin.z < newMinimum.z || this.origin.z > newMaximum.z) {
106
+ return false;
107
+ }
108
+ }
109
+ else {
110
+ inv = 1.0 / this.direction.z;
111
+ min = (newMinimum.z - this.origin.z) * inv;
112
+ max = (newMaximum.z - this.origin.z) * inv;
113
+ if (max === -Infinity) {
114
+ max = Infinity;
115
+ }
116
+ if (min > max) {
117
+ temp = min;
118
+ min = max;
119
+ max = temp;
120
+ }
121
+ d = Math.max(min, d);
122
+ maxValue = Math.min(max, maxValue);
123
+ if (d > maxValue) {
124
+ return false;
125
+ }
126
+ }
127
+ return true;
128
+ }
129
+ /**
130
+ * Checks if the ray intersects a box
131
+ * This does not account for the ray lenght by design to improve perfs.
132
+ * @param box the bounding box to check
133
+ * @param intersectionTreshold extra extend to be added to the BoundingBox in all direction
134
+ * @returns if the box was hit
135
+ */
136
+ intersectsBox(box, intersectionTreshold = 0) {
137
+ return this.intersectsBoxMinMax(box.minimum, box.maximum, intersectionTreshold);
138
+ }
139
+ /**
140
+ * If the ray hits a sphere
141
+ * @param sphere the bounding sphere to check
142
+ * @param intersectionTreshold extra extend to be added to the BoundingSphere in all direction
143
+ * @returns true if it hits the sphere
144
+ */
145
+ intersectsSphere(sphere, intersectionTreshold = 0) {
146
+ const x = sphere.center.x - this.origin.x;
147
+ const y = sphere.center.y - this.origin.y;
148
+ const z = sphere.center.z - this.origin.z;
149
+ const pyth = x * x + y * y + z * z;
150
+ const radius = sphere.radius + intersectionTreshold;
151
+ const rr = radius * radius;
152
+ if (pyth <= rr) {
153
+ return true;
154
+ }
155
+ const dot = x * this.direction.x + y * this.direction.y + z * this.direction.z;
156
+ if (dot < 0.0) {
157
+ return false;
158
+ }
159
+ const temp = pyth - dot * dot;
160
+ return temp <= rr;
161
+ }
162
+ /**
163
+ * If the ray hits a triange
164
+ * @param vertex0 triangle vertex
165
+ * @param vertex1 triangle vertex
166
+ * @param vertex2 triangle vertex
167
+ * @returns intersection information if hit
168
+ */
169
+ intersectsTriangle(vertex0, vertex1, vertex2) {
170
+ const edge1 = Ray._TmpVector3[0];
171
+ const edge2 = Ray._TmpVector3[1];
172
+ const pvec = Ray._TmpVector3[2];
173
+ const tvec = Ray._TmpVector3[3];
174
+ const qvec = Ray._TmpVector3[4];
175
+ vertex1.subtractToRef(vertex0, edge1);
176
+ vertex2.subtractToRef(vertex0, edge2);
177
+ Vector3.CrossToRef(this.direction, edge2, pvec);
178
+ const det = Vector3.Dot(edge1, pvec);
179
+ if (det === 0) {
180
+ return null;
181
+ }
182
+ const invdet = 1 / det;
183
+ this.origin.subtractToRef(vertex0, tvec);
184
+ const bv = Vector3.Dot(tvec, pvec) * invdet;
185
+ if (bv < -this.epsilon || bv > 1.0 + this.epsilon) {
186
+ return null;
187
+ }
188
+ Vector3.CrossToRef(tvec, edge1, qvec);
189
+ const bw = Vector3.Dot(this.direction, qvec) * invdet;
190
+ if (bw < -this.epsilon || bv + bw > 1.0 + this.epsilon) {
191
+ return null;
192
+ }
193
+ //check if the distance is longer than the predefined length.
194
+ const distance = Vector3.Dot(edge2, qvec) * invdet;
195
+ if (distance > this.length) {
196
+ return null;
197
+ }
198
+ return new IntersectionInfo(1 - bv - bw, bv, distance);
199
+ }
200
+ /**
201
+ * Checks if ray intersects a plane
202
+ * @param plane the plane to check
203
+ * @returns the distance away it was hit
204
+ */
205
+ intersectsPlane(plane) {
206
+ let distance;
207
+ const result1 = Vector3.Dot(plane.normal, this.direction);
208
+ if (Math.abs(result1) < 9.99999997475243e-7) {
209
+ return null;
210
+ }
211
+ else {
212
+ const result2 = Vector3.Dot(plane.normal, this.origin);
213
+ distance = (-plane.d - result2) / result1;
214
+ if (distance < 0.0) {
215
+ if (distance < -9.99999997475243e-7) {
216
+ return null;
217
+ }
218
+ else {
219
+ return 0;
220
+ }
221
+ }
222
+ return distance;
223
+ }
224
+ }
225
+ /**
226
+ * Calculate the intercept of a ray on a given axis
227
+ * @param axis to check 'x' | 'y' | 'z'
228
+ * @param offset from axis interception (i.e. an offset of 1y is intercepted above ground)
229
+ * @returns a vector containing the coordinates where 'axis' is equal to zero (else offset), or null if there is no intercept.
230
+ */
231
+ intersectsAxis(axis, offset = 0) {
232
+ switch (axis) {
233
+ case "y": {
234
+ const t = (this.origin.y - offset) / this.direction.y;
235
+ if (t > 0) {
236
+ return null;
237
+ }
238
+ return new Vector3(this.origin.x + this.direction.x * -t, offset, this.origin.z + this.direction.z * -t);
239
+ }
240
+ case "x": {
241
+ const t = (this.origin.x - offset) / this.direction.x;
242
+ if (t > 0) {
243
+ return null;
244
+ }
245
+ return new Vector3(offset, this.origin.y + this.direction.y * -t, this.origin.z + this.direction.z * -t);
246
+ }
247
+ case "z": {
248
+ const t = (this.origin.z - offset) / this.direction.z;
249
+ if (t > 0) {
250
+ return null;
251
+ }
252
+ return new Vector3(this.origin.x + this.direction.x * -t, this.origin.y + this.direction.y * -t, offset);
253
+ }
254
+ default:
255
+ return null;
256
+ }
257
+ }
258
+ /**
259
+ * Checks if ray intersects a mesh. The ray is defined in WORLD space. A mesh triangle can be picked both from its front and back sides,
260
+ * irrespective of orientation.
261
+ * @param mesh the mesh to check
262
+ * @param fastCheck defines if the first intersection will be used (and not the closest)
263
+ * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
264
+ * @param onlyBoundingInfo defines a boolean indicating if picking should only happen using bounding info (false by default)
265
+ * @param worldToUse defines the world matrix to use to get the world coordinate of the intersection point
266
+ * @param skipBoundingInfo a boolean indicating if we should skip the bounding info check
267
+ * @returns picking info of the intersection
268
+ */
269
+ intersectsMesh(mesh, fastCheck, trianglePredicate, onlyBoundingInfo = false, worldToUse, skipBoundingInfo = false) {
270
+ const tm = TmpVectors.Matrix[0];
271
+ mesh.getWorldMatrix().invertToRef(tm);
272
+ if (this._tmpRay) {
273
+ Ray.TransformToRef(this, tm, this._tmpRay);
274
+ }
275
+ else {
276
+ this._tmpRay = Ray.Transform(this, tm);
277
+ }
278
+ return mesh.intersects(this._tmpRay, fastCheck, trianglePredicate, onlyBoundingInfo, worldToUse, skipBoundingInfo);
279
+ }
280
+ /**
281
+ * Checks if ray intersects a mesh
282
+ * @param meshes the meshes to check
283
+ * @param fastCheck defines if the first intersection will be used (and not the closest)
284
+ * @param results array to store result in
285
+ * @returns Array of picking infos
286
+ */
287
+ intersectsMeshes(meshes, fastCheck, results) {
288
+ if (results) {
289
+ results.length = 0;
290
+ }
291
+ else {
292
+ results = [];
293
+ }
294
+ for (let i = 0; i < meshes.length; i++) {
295
+ const pickInfo = this.intersectsMesh(meshes[i], fastCheck);
296
+ if (pickInfo.hit) {
297
+ results.push(pickInfo);
298
+ }
299
+ }
300
+ results.sort(this._comparePickingInfo);
301
+ return results;
302
+ }
303
+ _comparePickingInfo(pickingInfoA, pickingInfoB) {
304
+ if (pickingInfoA.distance < pickingInfoB.distance) {
305
+ return -1;
306
+ }
307
+ else if (pickingInfoA.distance > pickingInfoB.distance) {
308
+ return 1;
309
+ }
310
+ else {
311
+ return 0;
312
+ }
313
+ }
314
+ /**
315
+ * Intersection test between the ray and a given segment within a given tolerance (threshold)
316
+ * @param sega the first point of the segment to test the intersection against
317
+ * @param segb the second point of the segment to test the intersection against
318
+ * @param threshold the tolerance margin, if the ray doesn't intersect the segment but is close to the given threshold, the intersection is successful
319
+ * @returns the distance from the ray origin to the intersection point if there's intersection, or -1 if there's no intersection
320
+ */
321
+ intersectionSegment(sega, segb, threshold) {
322
+ const o = this.origin;
323
+ const u = TmpVectors.Vector3[0];
324
+ const rsegb = TmpVectors.Vector3[1];
325
+ const v = TmpVectors.Vector3[2];
326
+ const w = TmpVectors.Vector3[3];
327
+ segb.subtractToRef(sega, u);
328
+ this.direction.scaleToRef(Ray._Rayl, v);
329
+ o.addToRef(v, rsegb);
330
+ sega.subtractToRef(o, w);
331
+ const a = Vector3.Dot(u, u); // always >= 0
332
+ const b = Vector3.Dot(u, v);
333
+ const c = Vector3.Dot(v, v); // always >= 0
334
+ const d = Vector3.Dot(u, w);
335
+ const e = Vector3.Dot(v, w);
336
+ const D = a * c - b * b; // always >= 0
337
+ let sN, sD = D; // sc = sN / sD, default sD = D >= 0
338
+ let tN, tD = D; // tc = tN / tD, default tD = D >= 0
339
+ // compute the line parameters of the two closest points
340
+ if (D < Ray._Smallnum) {
341
+ // the lines are almost parallel
342
+ sN = 0.0; // force using point P0 on segment S1
343
+ sD = 1.0; // to prevent possible division by 0.0 later
344
+ tN = e;
345
+ tD = c;
346
+ }
347
+ else {
348
+ // get the closest points on the infinite lines
349
+ sN = b * e - c * d;
350
+ tN = a * e - b * d;
351
+ if (sN < 0.0) {
352
+ // sc < 0 => the s=0 edge is visible
353
+ sN = 0.0;
354
+ tN = e;
355
+ tD = c;
356
+ }
357
+ else if (sN > sD) {
358
+ // sc > 1 => the s=1 edge is visible
359
+ sN = sD;
360
+ tN = e + b;
361
+ tD = c;
362
+ }
363
+ }
364
+ if (tN < 0.0) {
365
+ // tc < 0 => the t=0 edge is visible
366
+ tN = 0.0;
367
+ // recompute sc for this edge
368
+ if (-d < 0.0) {
369
+ sN = 0.0;
370
+ }
371
+ else if (-d > a) {
372
+ sN = sD;
373
+ }
374
+ else {
375
+ sN = -d;
376
+ sD = a;
377
+ }
378
+ }
379
+ else if (tN > tD) {
380
+ // tc > 1 => the t=1 edge is visible
381
+ tN = tD;
382
+ // recompute sc for this edge
383
+ if (-d + b < 0.0) {
384
+ sN = 0;
385
+ }
386
+ else if (-d + b > a) {
387
+ sN = sD;
388
+ }
389
+ else {
390
+ sN = -d + b;
391
+ sD = a;
392
+ }
393
+ }
394
+ // finally do the division to get sc and tc
395
+ const sc = Math.abs(sN) < Ray._Smallnum ? 0.0 : sN / sD;
396
+ const tc = Math.abs(tN) < Ray._Smallnum ? 0.0 : tN / tD;
397
+ // get the difference of the two closest points
398
+ const qtc = TmpVectors.Vector3[4];
399
+ v.scaleToRef(tc, qtc);
400
+ const qsc = TmpVectors.Vector3[5];
401
+ u.scaleToRef(sc, qsc);
402
+ qsc.addInPlace(w);
403
+ const dP = TmpVectors.Vector3[6];
404
+ qsc.subtractToRef(qtc, dP); // = S1(sc) - S2(tc)
405
+ const isIntersected = tc > 0 && tc <= this.length && dP.lengthSquared() < threshold * threshold; // return intersection result
406
+ if (isIntersected) {
407
+ return qsc.length();
408
+ }
409
+ return -1;
410
+ }
411
+ /**
412
+ * Update the ray from viewport position
413
+ * @param x position
414
+ * @param y y position
415
+ * @param viewportWidth viewport width
416
+ * @param viewportHeight viewport height
417
+ * @param world world matrix
418
+ * @param view view matrix
419
+ * @param projection projection matrix
420
+ * @param enableDistantPicking defines if picking should handle large values for mesh position/scaling (false by default)
421
+ * @returns this ray updated
422
+ */
423
+ update(x, y, viewportWidth, viewportHeight, world, view, projection, enableDistantPicking = false) {
424
+ if (enableDistantPicking) {
425
+ // With world matrices having great values (like 8000000000 on 1 or more scaling or position axis),
426
+ // multiplying view/projection/world and doing invert will result in loss of float precision in the matrix.
427
+ // One way to fix it is to compute the ray with world at identity then transform the ray in object space.
428
+ // This is slower (2 matrix inverts instead of 1) but precision is preserved.
429
+ // This is hidden behind `EnableDistantPicking` flag (default is false)
430
+ if (!Ray._RayDistant) {
431
+ Ray._RayDistant = Ray.Zero();
432
+ }
433
+ Ray._RayDistant.unprojectRayToRef(x, y, viewportWidth, viewportHeight, Matrix.IdentityReadOnly, view, projection);
434
+ const tm = TmpVectors.Matrix[0];
435
+ world.invertToRef(tm);
436
+ Ray.TransformToRef(Ray._RayDistant, tm, this);
437
+ }
438
+ else {
439
+ this.unprojectRayToRef(x, y, viewportWidth, viewportHeight, world, view, projection);
440
+ }
441
+ return this;
442
+ }
443
+ // Statics
444
+ /**
445
+ * Creates a ray with origin and direction of 0,0,0
446
+ * @returns the new ray
447
+ */
448
+ static Zero() {
449
+ return new Ray(Vector3.Zero(), Vector3.Zero());
450
+ }
451
+ /**
452
+ * Creates a new ray from screen space and viewport
453
+ * @param x position
454
+ * @param y y position
455
+ * @param viewportWidth viewport width
456
+ * @param viewportHeight viewport height
457
+ * @param world world matrix
458
+ * @param view view matrix
459
+ * @param projection projection matrix
460
+ * @returns new ray
461
+ */
462
+ static CreateNew(x, y, viewportWidth, viewportHeight, world, view, projection) {
463
+ const result = Ray.Zero();
464
+ return result.update(x, y, viewportWidth, viewportHeight, world, view, projection);
465
+ }
466
+ /**
467
+ * Function will create a new transformed ray starting from origin and ending at the end point. Ray's length will be set, and ray will be
468
+ * transformed to the given world matrix.
469
+ * @param origin The origin point
470
+ * @param end The end point
471
+ * @param world a matrix to transform the ray to. Default is the identity matrix.
472
+ * @returns the new ray
473
+ */
474
+ static CreateNewFromTo(origin, end, world = Matrix.IdentityReadOnly) {
475
+ const result = new Ray(new Vector3(0, 0, 0), new Vector3(0, 0, 0));
476
+ return Ray.CreateFromToToRef(origin, end, result, world);
477
+ }
478
+ /**
479
+ * Function will update a transformed ray starting from origin and ending at the end point. Ray's length will be set, and ray will be
480
+ * transformed to the given world matrix.
481
+ * @param origin The origin point
482
+ * @param end The end point
483
+ * @param result the object to store the result
484
+ * @param world a matrix to transform the ray to. Default is the identity matrix.
485
+ * @returns the ref ray
486
+ */
487
+ static CreateFromToToRef(origin, end, result, world = Matrix.IdentityReadOnly) {
488
+ result.origin.copyFrom(origin);
489
+ const direction = end.subtractToRef(origin, result.direction);
490
+ const length = Math.sqrt(direction.x * direction.x + direction.y * direction.y + direction.z * direction.z);
491
+ result.length = length;
492
+ result.direction.normalize();
493
+ return Ray.TransformToRef(result, world, result);
494
+ }
495
+ /**
496
+ * Transforms a ray by a matrix
497
+ * @param ray ray to transform
498
+ * @param matrix matrix to apply
499
+ * @returns the resulting new ray
500
+ */
501
+ static Transform(ray, matrix) {
502
+ const result = new Ray(new Vector3(0, 0, 0), new Vector3(0, 0, 0));
503
+ Ray.TransformToRef(ray, matrix, result);
504
+ return result;
505
+ }
506
+ /**
507
+ * Transforms a ray by a matrix
508
+ * @param ray ray to transform
509
+ * @param matrix matrix to apply
510
+ * @param result ray to store result in
511
+ * @returns the updated result ray
512
+ */
513
+ static TransformToRef(ray, matrix, result) {
514
+ Vector3.TransformCoordinatesToRef(ray.origin, matrix, result.origin);
515
+ Vector3.TransformNormalToRef(ray.direction, matrix, result.direction);
516
+ result.length = ray.length;
517
+ result.epsilon = ray.epsilon;
518
+ const dir = result.direction;
519
+ const len = dir.length();
520
+ if (!(len === 0 || len === 1)) {
521
+ const num = 1.0 / len;
522
+ dir.x *= num;
523
+ dir.y *= num;
524
+ dir.z *= num;
525
+ result.length *= len;
526
+ }
527
+ return result;
528
+ }
529
+ /**
530
+ * Unproject a ray from screen space to object space
531
+ * @param sourceX defines the screen space x coordinate to use
532
+ * @param sourceY defines the screen space y coordinate to use
533
+ * @param viewportWidth defines the current width of the viewport
534
+ * @param viewportHeight defines the current height of the viewport
535
+ * @param world defines the world matrix to use (can be set to Identity to go to world space)
536
+ * @param view defines the view matrix to use
537
+ * @param projection defines the projection matrix to use
538
+ */
539
+ unprojectRayToRef(sourceX, sourceY, viewportWidth, viewportHeight, world, view, projection) {
540
+ const matrix = TmpVectors.Matrix[0];
541
+ world.multiplyToRef(view, matrix);
542
+ matrix.multiplyToRef(projection, matrix);
543
+ matrix.invert();
544
+ const engine = EngineStore.LastCreatedEngine;
545
+ const nearScreenSource = TmpVectors.Vector3[0];
546
+ nearScreenSource.x = (sourceX / viewportWidth) * 2 - 1;
547
+ nearScreenSource.y = -((sourceY / viewportHeight) * 2 - 1);
548
+ nearScreenSource.z = engine?.useReverseDepthBuffer ? 1 : engine?.isNDCHalfZRange ? 0 : -1;
549
+ // far Z need to be close but < to 1 or camera projection matrix with maxZ = 0 will NaN
550
+ const farScreenSource = TmpVectors.Vector3[1].copyFromFloats(nearScreenSource.x, nearScreenSource.y, 1.0 - 1e-8);
551
+ const nearVec3 = TmpVectors.Vector3[2];
552
+ const farVec3 = TmpVectors.Vector3[3];
553
+ Vector3._UnprojectFromInvertedMatrixToRef(nearScreenSource, matrix, nearVec3);
554
+ Vector3._UnprojectFromInvertedMatrixToRef(farScreenSource, matrix, farVec3);
555
+ this.origin.copyFrom(nearVec3);
556
+ farVec3.subtractToRef(nearVec3, this.direction);
557
+ this.direction.normalize();
558
+ }
559
+ }
560
+ Ray._TmpVector3 = BuildArray(6, Vector3.Zero);
561
+ Ray._RayDistant = Ray.Zero();
562
+ Ray._Smallnum = 0.00000001;
563
+ Ray._Rayl = 10e8;
564
+ /**
565
+ * Creates a ray that can be used to pick in the scene
566
+ * @param scene defines the scene to use for the picking
567
+ * @param x defines the x coordinate of the origin (on-screen)
568
+ * @param y defines the y coordinate of the origin (on-screen)
569
+ * @param world defines the world matrix to use if you want to pick in object space (instead of world space)
570
+ * @param camera defines the camera to use for the picking
571
+ * @param cameraViewSpace defines if picking will be done in view space (false by default)
572
+ * @returns a Ray
573
+ */
574
+ export function CreatePickingRay(scene, x, y, world, camera, cameraViewSpace = false) {
575
+ const result = Ray.Zero();
576
+ CreatePickingRayToRef(scene, x, y, world, result, camera, cameraViewSpace);
577
+ return result;
578
+ }
579
+ /**
580
+ * Creates a ray that can be used to pick in the scene
581
+ * @param scene defines the scene to use for the picking
582
+ * @param x defines the x coordinate of the origin (on-screen)
583
+ * @param y defines the y coordinate of the origin (on-screen)
584
+ * @param world defines the world matrix to use if you want to pick in object space (instead of world space)
585
+ * @param result defines the ray where to store the picking ray
586
+ * @param camera defines the camera to use for the picking
587
+ * @param cameraViewSpace defines if picking will be done in view space (false by default)
588
+ * @param enableDistantPicking defines if picking should handle large values for mesh position/scaling (false by default)
589
+ * @returns the current scene
590
+ */
591
+ export function CreatePickingRayToRef(scene, x, y, world, result, camera, cameraViewSpace = false, enableDistantPicking = false) {
592
+ const engine = scene.getEngine();
593
+ if (!camera && !(camera = scene.activeCamera)) {
594
+ return scene;
595
+ }
596
+ const cameraViewport = camera.viewport;
597
+ const renderHeight = engine.getRenderHeight();
598
+ const { x: vx, y: vy, width, height } = cameraViewport.toGlobal(engine.getRenderWidth(), renderHeight);
599
+ // Moving coordinates to local viewport world
600
+ const levelInv = 1 / engine.getHardwareScalingLevel();
601
+ x = x * levelInv - vx;
602
+ y = y * levelInv - (renderHeight - vy - height);
603
+ result.update(x, y, width, height, world ? world : Matrix.IdentityReadOnly, cameraViewSpace ? Matrix.IdentityReadOnly : camera.getViewMatrix(), camera.getProjectionMatrix(), enableDistantPicking);
604
+ return scene;
605
+ }
606
+ /**
607
+ * Creates a ray that can be used to pick in the scene
608
+ * @param scene defines the scene to use for the picking
609
+ * @param x defines the x coordinate of the origin (on-screen)
610
+ * @param y defines the y coordinate of the origin (on-screen)
611
+ * @param camera defines the camera to use for the picking
612
+ * @returns a Ray
613
+ */
614
+ export function CreatePickingRayInCameraSpace(scene, x, y, camera) {
615
+ const result = Ray.Zero();
616
+ CreatePickingRayInCameraSpaceToRef(scene, x, y, result, camera);
617
+ return result;
618
+ }
619
+ /**
620
+ * Creates a ray that can be used to pick in the scene
621
+ * @param scene defines the scene to use for the picking
622
+ * @param x defines the x coordinate of the origin (on-screen)
623
+ * @param y defines the y coordinate of the origin (on-screen)
624
+ * @param result defines the ray where to store the picking ray
625
+ * @param camera defines the camera to use for the picking
626
+ * @returns the current scene
627
+ */
628
+ export function CreatePickingRayInCameraSpaceToRef(scene, x, y, result, camera) {
629
+ if (!PickingInfo) {
630
+ return scene;
631
+ }
632
+ const engine = scene.getEngine();
633
+ if (!camera && !(camera = scene.activeCamera)) {
634
+ throw new Error("Active camera not set");
635
+ }
636
+ const cameraViewport = camera.viewport;
637
+ const renderHeight = engine.getRenderHeight();
638
+ const { x: vx, y: vy, width, height } = cameraViewport.toGlobal(engine.getRenderWidth(), renderHeight);
639
+ const identity = Matrix.Identity();
640
+ // Moving coordinates to local viewport world
641
+ const levelInv = 1 / engine.getHardwareScalingLevel();
642
+ x = x * levelInv - vx;
643
+ y = y * levelInv - (renderHeight - vy - height);
644
+ result.update(x, y, width, height, identity, identity, camera.getProjectionMatrix());
645
+ return scene;
646
+ }
647
+ function InternalPickForMesh(pickingInfo, rayFunction, mesh, world, fastCheck, onlyBoundingInfo, trianglePredicate, skipBoundingInfo) {
648
+ const ray = rayFunction(world, mesh.enableDistantPicking);
649
+ const result = mesh.intersects(ray, fastCheck, trianglePredicate, onlyBoundingInfo, world, skipBoundingInfo);
650
+ if (!result || !result.hit) {
651
+ return null;
652
+ }
653
+ if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance) {
654
+ return null;
655
+ }
656
+ return result;
657
+ }
658
+ function InternalPick(scene, rayFunction, predicate, fastCheck, onlyBoundingInfo, trianglePredicate) {
659
+ let pickingInfo = null;
660
+ const computeWorldMatrixForCamera = !!(scene.activeCameras && scene.activeCameras.length > 1 && scene.cameraToUseForPointers !== scene.activeCamera);
661
+ const currentCamera = scene.cameraToUseForPointers || scene.activeCamera;
662
+ for (let meshIndex = 0; meshIndex < scene.meshes.length; meshIndex++) {
663
+ const mesh = scene.meshes[meshIndex];
664
+ if (predicate) {
665
+ if (!predicate(mesh, -1)) {
666
+ continue;
667
+ }
668
+ }
669
+ else if (!mesh.isEnabled() || !mesh.isVisible || !mesh.isPickable) {
670
+ continue;
671
+ }
672
+ const forceCompute = computeWorldMatrixForCamera && mesh.isWorldMatrixCameraDependent();
673
+ const world = mesh.computeWorldMatrix(forceCompute, currentCamera);
674
+ if (mesh.hasThinInstances && mesh.thinInstanceEnablePicking) {
675
+ // first check if the ray intersects the whole bounding box/sphere of the mesh
676
+ const result = InternalPickForMesh(pickingInfo, rayFunction, mesh, world, true, true, trianglePredicate);
677
+ if (result) {
678
+ if (onlyBoundingInfo) {
679
+ // the user only asked for a bounding info check so we can return
680
+ return result;
681
+ }
682
+ const tmpMatrix = TmpVectors.Matrix[1];
683
+ const thinMatrices = mesh.thinInstanceGetWorldMatrices();
684
+ for (let index = 0; index < thinMatrices.length; index++) {
685
+ if (predicate && !predicate(mesh, index)) {
686
+ continue;
687
+ }
688
+ const thinMatrix = thinMatrices[index];
689
+ thinMatrix.multiplyToRef(world, tmpMatrix);
690
+ const result = InternalPickForMesh(pickingInfo, rayFunction, mesh, tmpMatrix, fastCheck, onlyBoundingInfo, trianglePredicate, true);
691
+ if (result) {
692
+ pickingInfo = result;
693
+ pickingInfo.thinInstanceIndex = index;
694
+ if (fastCheck) {
695
+ return pickingInfo;
696
+ }
697
+ }
698
+ }
699
+ }
700
+ }
701
+ else {
702
+ const result = InternalPickForMesh(pickingInfo, rayFunction, mesh, world, fastCheck, onlyBoundingInfo, trianglePredicate);
703
+ if (result) {
704
+ pickingInfo = result;
705
+ if (fastCheck) {
706
+ return pickingInfo;
707
+ }
708
+ }
709
+ }
710
+ }
711
+ return pickingInfo || new PickingInfo();
712
+ }
713
+ function InternalMultiPick(scene, rayFunction, predicate, trianglePredicate) {
714
+ if (!PickingInfo) {
715
+ return null;
716
+ }
717
+ const pickingInfos = [];
718
+ const computeWorldMatrixForCamera = !!(scene.activeCameras && scene.activeCameras.length > 1 && scene.cameraToUseForPointers !== scene.activeCamera);
719
+ const currentCamera = scene.cameraToUseForPointers || scene.activeCamera;
720
+ for (let meshIndex = 0; meshIndex < scene.meshes.length; meshIndex++) {
721
+ const mesh = scene.meshes[meshIndex];
722
+ if (predicate) {
723
+ if (!predicate(mesh, -1)) {
724
+ continue;
725
+ }
726
+ }
727
+ else if (!mesh.isEnabled() || !mesh.isVisible || !mesh.isPickable) {
728
+ continue;
729
+ }
730
+ const forceCompute = computeWorldMatrixForCamera && mesh.isWorldMatrixCameraDependent();
731
+ const world = mesh.computeWorldMatrix(forceCompute, currentCamera);
732
+ if (mesh.hasThinInstances && mesh.thinInstanceEnablePicking) {
733
+ const result = InternalPickForMesh(null, rayFunction, mesh, world, true, true, trianglePredicate);
734
+ if (result) {
735
+ const tmpMatrix = TmpVectors.Matrix[1];
736
+ const thinMatrices = mesh.thinInstanceGetWorldMatrices();
737
+ for (let index = 0; index < thinMatrices.length; index++) {
738
+ if (predicate && !predicate(mesh, index)) {
739
+ continue;
740
+ }
741
+ const thinMatrix = thinMatrices[index];
742
+ thinMatrix.multiplyToRef(world, tmpMatrix);
743
+ const result = InternalPickForMesh(null, rayFunction, mesh, tmpMatrix, false, false, trianglePredicate, true);
744
+ if (result) {
745
+ result.thinInstanceIndex = index;
746
+ pickingInfos.push(result);
747
+ }
748
+ }
749
+ }
750
+ }
751
+ else {
752
+ const result = InternalPickForMesh(null, rayFunction, mesh, world, false, false, trianglePredicate);
753
+ if (result) {
754
+ pickingInfos.push(result);
755
+ }
756
+ }
757
+ }
758
+ return pickingInfos;
759
+ }
760
+ /** Launch a ray to try to pick a mesh in the scene using only bounding information of the main mesh (not using submeshes)
761
+ * @param scene defines the scene to use for the picking
762
+ * @param x position on screen
763
+ * @param y position on screen
764
+ * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true. thinInstanceIndex is -1 when the mesh is non-instanced
765
+ * @param fastCheck defines if the first intersection will be used (and not the closest)
766
+ * @param camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
767
+ * @returns a PickingInfo (Please note that some info will not be set like distance, bv, bu and everything that cannot be capture by only using bounding infos)
768
+ */
769
+ export function PickWithBoundingInfo(scene, x, y, predicate, fastCheck, camera) {
770
+ if (!PickingInfo) {
771
+ return null;
772
+ }
773
+ const result = InternalPick(scene, (world) => {
774
+ if (!scene._tempPickingRay) {
775
+ scene._tempPickingRay = Ray.Zero();
776
+ }
777
+ CreatePickingRayToRef(scene, x, y, world, scene._tempPickingRay, camera || null);
778
+ return scene._tempPickingRay;
779
+ }, predicate, fastCheck, true);
780
+ if (result) {
781
+ result.ray = CreatePickingRay(scene, x, y, Matrix.Identity(), camera || null);
782
+ }
783
+ return result;
784
+ }
785
+ /** Launch a ray to try to pick a mesh in the scene
786
+ * @param scene defines the scene to use for the picking
787
+ * @param x position on screen
788
+ * @param y position on screen
789
+ * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true. thinInstanceIndex is -1 when the mesh is non-instanced
790
+ * @param fastCheck defines if the first intersection will be used (and not the closest)
791
+ * @param camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
792
+ * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
793
+ * @param _enableDistantPicking defines if picking should handle large values for mesh position/scaling (false by default)
794
+ * @returns a PickingInfo
795
+ */
796
+ export function Pick(scene, x, y, predicate, fastCheck, camera, trianglePredicate, _enableDistantPicking = false) {
797
+ const result = InternalPick(scene, (world, enableDistantPicking) => {
798
+ if (!scene._tempPickingRay) {
799
+ scene._tempPickingRay = Ray.Zero();
800
+ }
801
+ CreatePickingRayToRef(scene, x, y, world, scene._tempPickingRay, camera || null, false, enableDistantPicking);
802
+ return scene._tempPickingRay;
803
+ }, predicate, fastCheck, false, trianglePredicate);
804
+ if (result) {
805
+ result.ray = CreatePickingRay(scene, x, y, Matrix.Identity(), camera || null);
806
+ }
807
+ return result;
808
+ }
809
+ /**
810
+ * Use the given ray to pick a mesh in the scene. A mesh triangle can be picked both from its front and back sides,
811
+ * irrespective of orientation.
812
+ * @param scene defines the scene to use for the picking
813
+ * @param ray The ray to use to pick meshes
814
+ * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true. thinInstanceIndex is -1 when the mesh is non-instanced
815
+ * @param fastCheck defines if the first intersection will be used (and not the closest)
816
+ * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
817
+ * @returns a PickingInfo
818
+ */
819
+ export function PickWithRay(scene, ray, predicate, fastCheck, trianglePredicate) {
820
+ const result = InternalPick(scene, (world) => {
821
+ if (!scene._pickWithRayInverseMatrix) {
822
+ scene._pickWithRayInverseMatrix = Matrix.Identity();
823
+ }
824
+ world.invertToRef(scene._pickWithRayInverseMatrix);
825
+ if (!scene._cachedRayForTransform) {
826
+ scene._cachedRayForTransform = Ray.Zero();
827
+ }
828
+ Ray.TransformToRef(ray, scene._pickWithRayInverseMatrix, scene._cachedRayForTransform);
829
+ return scene._cachedRayForTransform;
830
+ }, predicate, fastCheck, false, trianglePredicate);
831
+ if (result) {
832
+ result.ray = ray;
833
+ }
834
+ return result;
835
+ }
836
+ /**
837
+ * Launch a ray to try to pick a mesh in the scene. A mesh triangle can be picked both from its front and back sides,
838
+ * irrespective of orientation.
839
+ * @param scene defines the scene to use for the picking
840
+ * @param x X position on screen
841
+ * @param y Y position on screen
842
+ * @param predicate Predicate function used to determine eligible meshes and instances. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true. thinInstanceIndex is -1 when the mesh is non-instanced
843
+ * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
844
+ * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
845
+ * @returns an array of PickingInfo
846
+ */
847
+ export function MultiPick(scene, x, y, predicate, camera, trianglePredicate) {
848
+ return InternalMultiPick(scene, (world) => CreatePickingRay(scene, x, y, world, camera || null), predicate, trianglePredicate);
849
+ }
850
+ /**
851
+ * Launch a ray to try to pick a mesh in the scene
852
+ * @param scene defines the scene to use for the picking
853
+ * @param ray Ray to use
854
+ * @param predicate Predicate function used to determine eligible meshes and instances. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true. thinInstanceIndex is -1 when the mesh is non-instanced
855
+ * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
856
+ * @returns an array of PickingInfo
857
+ */
858
+ export function MultiPickWithRay(scene, ray, predicate, trianglePredicate) {
859
+ return InternalMultiPick(scene, (world) => {
860
+ if (!scene._pickWithRayInverseMatrix) {
861
+ scene._pickWithRayInverseMatrix = Matrix.Identity();
862
+ }
863
+ world.invertToRef(scene._pickWithRayInverseMatrix);
864
+ if (!scene._cachedRayForTransform) {
865
+ scene._cachedRayForTransform = Ray.Zero();
866
+ }
867
+ Ray.TransformToRef(ray, scene._pickWithRayInverseMatrix, scene._cachedRayForTransform);
868
+ return scene._cachedRayForTransform;
869
+ }, predicate, trianglePredicate);
870
+ }
871
+ /**
872
+ * Gets a ray in the forward direction from the camera.
873
+ * @param camera Defines the camera to use to get the ray from
874
+ * @param length Defines the length of the ray to create
875
+ * @param transform Defines the transform to apply to the ray, by default the world matrix is used to create a workd space ray
876
+ * @param origin Defines the start point of the ray which defaults to the camera position
877
+ * @returns the forward ray
878
+ */
879
+ export function GetForwardRay(camera, length = 100, transform, origin) {
880
+ return GetForwardRayToRef(camera, new Ray(Vector3.Zero(), Vector3.Zero(), length), length, transform, origin);
881
+ }
882
+ /**
883
+ * Gets a ray in the forward direction from the camera.
884
+ * @param camera Defines the camera to use to get the ray from
885
+ * @param refRay the ray to (re)use when setting the values
886
+ * @param length Defines the length of the ray to create
887
+ * @param transform Defines the transform to apply to the ray, by default the world matrx is used to create a workd space ray
888
+ * @param origin Defines the start point of the ray which defaults to the camera position
889
+ * @returns the forward ray
890
+ */
891
+ export function GetForwardRayToRef(camera, refRay, length = 100, transform, origin) {
892
+ if (!transform) {
893
+ transform = camera.getWorldMatrix();
894
+ }
895
+ refRay.length = length;
896
+ if (origin) {
897
+ refRay.origin.copyFrom(origin);
898
+ }
899
+ else {
900
+ refRay.origin.copyFrom(camera.position);
901
+ }
902
+ const forward = TmpVectors.Vector3[2];
903
+ forward.set(0, 0, camera._scene.useRightHandedSystem ? -1 : 1);
904
+ const worldForward = TmpVectors.Vector3[3];
905
+ Vector3.TransformNormalToRef(forward, transform, worldForward);
906
+ Vector3.NormalizeToRef(worldForward, refRay.direction);
907
+ return refRay;
908
+ }
909
+ /**
910
+ * Initialize the minimal interdependecies between the Ray and Scene and Camera
911
+ * @param sceneClass defines the scene prototype to use
912
+ * @param cameraClass defines the camera prototype to use
913
+ */
914
+ export function AddRayExtensions(sceneClass, cameraClass) {
915
+ if (cameraClass) {
916
+ cameraClass.prototype.getForwardRay = function (length = 100, transform, origin) {
917
+ return GetForwardRayToRef(this, new Ray(Vector3.Zero(), Vector3.Zero(), length), length, transform, origin);
918
+ };
919
+ cameraClass.prototype.getForwardRayToRef = function (refRay, length = 100, transform, origin) {
920
+ return GetForwardRayToRef(this, refRay, length, transform, origin);
921
+ };
922
+ }
923
+ if (!sceneClass) {
924
+ return;
925
+ }
926
+ _ImportHelper._IsPickingAvailable = true;
927
+ sceneClass.prototype.createPickingRay = function (x, y, world, camera, cameraViewSpace = false) {
928
+ return CreatePickingRay(this, x, y, world, camera, cameraViewSpace);
929
+ };
930
+ }
931
+ //# sourceMappingURL=ray.core.js.map