@babylonjs/core 5.45.0 → 5.45.2

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 (55) hide show
  1. package/Engines/thinEngine.js +2 -2
  2. package/Engines/thinEngine.js.map +1 -1
  3. package/Inputs/scene.inputManager.js +12 -1
  4. package/Inputs/scene.inputManager.js.map +1 -1
  5. package/Materials/Node/Blocks/Fragment/perturbNormalBlock.d.ts +7 -0
  6. package/Materials/Node/Blocks/Fragment/perturbNormalBlock.js +30 -1
  7. package/Materials/Node/Blocks/Fragment/perturbNormalBlock.js.map +1 -1
  8. package/Materials/Textures/texture.d.ts +2 -2
  9. package/Materials/Textures/texture.js +2 -2
  10. package/Materials/Textures/texture.js.map +1 -1
  11. package/Materials/Textures/videoTexture.d.ts +1 -0
  12. package/Materials/Textures/videoTexture.js +19 -8
  13. package/Materials/Textures/videoTexture.js.map +1 -1
  14. package/Materials/clipPlaneMaterialHelper.js +22 -19
  15. package/Materials/clipPlaneMaterialHelper.js.map +1 -1
  16. package/Misc/khronosTextureContainer2.js +3 -5
  17. package/Misc/khronosTextureContainer2.js.map +1 -1
  18. package/Physics/index.d.ts +1 -0
  19. package/Physics/index.js +1 -0
  20. package/Physics/index.js.map +1 -1
  21. package/Physics/physicsHelper.d.ts +452 -1
  22. package/Physics/physicsHelper.js +877 -2
  23. package/Physics/physicsHelper.js.map +1 -1
  24. package/Physics/v1/index.d.ts +0 -1
  25. package/Physics/v1/index.js +0 -1
  26. package/Physics/v1/index.js.map +1 -1
  27. package/Physics/v2/IPhysicsEnginePlugin.d.ts +8 -1
  28. package/Physics/v2/IPhysicsEnginePlugin.js.map +1 -1
  29. package/Physics/v2/index.d.ts +1 -0
  30. package/Physics/v2/index.js +1 -0
  31. package/Physics/v2/index.js.map +1 -1
  32. package/Physics/v2/physicsAggregate.d.ts +39 -19
  33. package/Physics/v2/physicsAggregate.js +61 -5
  34. package/Physics/v2/physicsAggregate.js.map +1 -1
  35. package/Physics/v2/physicsBody.d.ts +37 -1
  36. package/Physics/v2/physicsBody.js +71 -1
  37. package/Physics/v2/physicsBody.js.map +1 -1
  38. package/Physics/v2/physicsEngine.d.ts +7 -2
  39. package/Physics/v2/physicsEngine.js +9 -2
  40. package/Physics/v2/physicsEngine.js.map +1 -1
  41. package/Physics/v2/physicsShape.d.ts +30 -44
  42. package/Physics/v2/physicsShape.js +30 -44
  43. package/Physics/v2/physicsShape.js.map +1 -1
  44. package/Shaders/ShadersInclude/bumpFragment.js +1 -0
  45. package/Shaders/ShadersInclude/bumpFragment.js.map +1 -1
  46. package/Shaders/ShadersInclude/bumpFragmentMainFunctions.js +4 -1
  47. package/Shaders/ShadersInclude/bumpFragmentMainFunctions.js.map +1 -1
  48. package/Shaders/sprites.fragment.js +1 -1
  49. package/Shaders/sprites.fragment.js.map +1 -1
  50. package/assetContainer.js +1 -1
  51. package/assetContainer.js.map +1 -1
  52. package/package.json +1 -1
  53. package/Physics/v1/physicsHelper.d.ts +0 -411
  54. package/Physics/v1/physicsHelper.js +0 -709
  55. package/Physics/v1/physicsHelper.js.map +0 -1
@@ -1,3 +1,878 @@
1
- // ES 6 Compatibility
2
- export * from "./v1/physicsHelper.js";
1
+ import { Logger } from "../Misc/logger.js";
2
+ import { Vector3 } from "../Maths/math.vector.js";
3
+ import { CreateSphere } from "../Meshes/Builders/sphereBuilder.js";
4
+ import { CreateCylinder } from "../Meshes/Builders/cylinderBuilder.js";
5
+ import { Ray } from "../Culling/ray.js";
6
+ /**
7
+ * A helper for physics simulations
8
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/physics/usingPhysicsEngine#further-functionality-of-the-impostor-class
9
+ */
10
+ export class PhysicsHelper {
11
+ /**
12
+ * Initializes the Physics helper
13
+ * @param scene Babylon.js scene
14
+ */
15
+ constructor(scene) {
16
+ this._hitData = { force: new Vector3(), contactPoint: new Vector3(), distanceFromOrigin: 0 };
17
+ this._scene = scene;
18
+ this._physicsEngine = this._scene.getPhysicsEngine();
19
+ if (!this._physicsEngine) {
20
+ Logger.Warn("Physics engine not enabled. Please enable the physics before you can use the methods.");
21
+ return;
22
+ }
23
+ }
24
+ /**
25
+ * Applies a radial explosion impulse
26
+ * @param origin the origin of the explosion
27
+ * @param radiusOrEventOptions the radius or the options of radial explosion
28
+ * @param strength the explosion strength
29
+ * @param falloff possible options: Constant & Linear. Defaults to Constant
30
+ * @returns A physics radial explosion event, or null
31
+ */
32
+ applyRadialExplosionImpulse(origin, radiusOrEventOptions, strength, falloff) {
33
+ if (!this._physicsEngine) {
34
+ Logger.Warn("Physics engine not enabled. Please enable the physics before you call this method.");
35
+ return null;
36
+ }
37
+ if (this._physicsEngine.getPluginVersion() === 1 && this._physicsEngine.getImpostors().length === 0) {
38
+ return null;
39
+ }
40
+ if (this._physicsEngine.getPluginVersion() === 2 && this._physicsEngine.getBodies().length === 0) {
41
+ return null;
42
+ }
43
+ let useCallback = false;
44
+ if (typeof radiusOrEventOptions === "number") {
45
+ const r = radiusOrEventOptions;
46
+ radiusOrEventOptions = new PhysicsRadialExplosionEventOptions();
47
+ radiusOrEventOptions.radius = r;
48
+ radiusOrEventOptions.strength = strength !== null && strength !== void 0 ? strength : radiusOrEventOptions.strength;
49
+ radiusOrEventOptions.falloff = falloff !== null && falloff !== void 0 ? falloff : radiusOrEventOptions.falloff;
50
+ }
51
+ else {
52
+ useCallback = !!(radiusOrEventOptions.affectedImpostorsCallback || radiusOrEventOptions.affectedBodiesCallback);
53
+ }
54
+ const event = new PhysicsRadialExplosionEvent(this._scene, radiusOrEventOptions);
55
+ const hitData = this._hitData;
56
+ if (this._physicsEngine.getPluginVersion() === 1) {
57
+ const affectedImpostorsWithData = Array();
58
+ const impostors = this._physicsEngine.getImpostors();
59
+ impostors.forEach((impostor) => {
60
+ if (!event.getImpostorHitData(impostor, origin, hitData)) {
61
+ return;
62
+ }
63
+ impostor.applyImpulse(hitData.force, hitData.contactPoint);
64
+ if (useCallback) {
65
+ affectedImpostorsWithData.push({
66
+ impostor: impostor,
67
+ hitData: this._copyPhysicsHitData(hitData),
68
+ });
69
+ }
70
+ });
71
+ event.triggerAffectedImpostorsCallback(affectedImpostorsWithData);
72
+ }
73
+ else {
74
+ const affectedBodiesWithData = Array();
75
+ const bodies = this._physicsEngine.getBodies();
76
+ bodies.forEach((body) => {
77
+ if (!event.getBodyHitData(body, origin, hitData)) {
78
+ return;
79
+ }
80
+ body.applyImpulse(hitData.force, hitData.contactPoint);
81
+ if (useCallback) {
82
+ affectedBodiesWithData.push({
83
+ body: body,
84
+ hitData: this._copyPhysicsHitData(hitData),
85
+ });
86
+ }
87
+ });
88
+ event.triggerAffectedBodiesCallback(affectedBodiesWithData);
89
+ }
90
+ event.dispose(false);
91
+ return event;
92
+ }
93
+ /**
94
+ * Applies a radial explosion force
95
+ * @param origin the origin of the explosion
96
+ * @param radiusOrEventOptions the radius or the options of radial explosion
97
+ * @param strength the explosion strength
98
+ * @param falloff possible options: Constant & Linear. Defaults to Constant
99
+ * @returns A physics radial explosion event, or null
100
+ */
101
+ applyRadialExplosionForce(origin, radiusOrEventOptions, strength, falloff) {
102
+ if (!this._physicsEngine) {
103
+ Logger.Warn("Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.");
104
+ return null;
105
+ }
106
+ if (this._physicsEngine.getPluginVersion() === 1 && this._physicsEngine.getImpostors().length === 0) {
107
+ return null;
108
+ }
109
+ if (this._physicsEngine.getPluginVersion() === 2 && this._physicsEngine.getBodies().length === 0) {
110
+ return null;
111
+ }
112
+ let useCallback = false;
113
+ if (typeof radiusOrEventOptions === "number") {
114
+ const r = radiusOrEventOptions;
115
+ radiusOrEventOptions = new PhysicsRadialExplosionEventOptions();
116
+ radiusOrEventOptions.radius = r;
117
+ radiusOrEventOptions.strength = strength !== null && strength !== void 0 ? strength : radiusOrEventOptions.strength;
118
+ radiusOrEventOptions.falloff = falloff !== null && falloff !== void 0 ? falloff : radiusOrEventOptions.falloff;
119
+ }
120
+ else {
121
+ useCallback = !!(radiusOrEventOptions.affectedImpostorsCallback || radiusOrEventOptions.affectedBodiesCallback);
122
+ }
123
+ const event = new PhysicsRadialExplosionEvent(this._scene, radiusOrEventOptions);
124
+ const hitData = this._hitData;
125
+ if (this._physicsEngine.getPluginVersion() === 1) {
126
+ const affectedImpostorsWithData = Array();
127
+ const impostors = this._physicsEngine.getImpostors();
128
+ impostors.forEach((impostor) => {
129
+ if (!event.getImpostorHitData(impostor, origin, hitData)) {
130
+ return;
131
+ }
132
+ impostor.applyForce(hitData.force, hitData.contactPoint);
133
+ if (useCallback) {
134
+ affectedImpostorsWithData.push({
135
+ impostor: impostor,
136
+ hitData: this._copyPhysicsHitData(hitData),
137
+ });
138
+ }
139
+ });
140
+ event.triggerAffectedImpostorsCallback(affectedImpostorsWithData);
141
+ }
142
+ else {
143
+ const affectedBodiesWithData = Array();
144
+ const bodies = this._physicsEngine.getBodies();
145
+ bodies.forEach((body) => {
146
+ if (!event.getBodyHitData(body, origin, hitData)) {
147
+ return;
148
+ }
149
+ body.applyForce(hitData.force, hitData.contactPoint);
150
+ if (useCallback) {
151
+ affectedBodiesWithData.push({
152
+ body: body,
153
+ hitData: this._copyPhysicsHitData(hitData),
154
+ });
155
+ }
156
+ });
157
+ event.triggerAffectedBodiesCallback(affectedBodiesWithData);
158
+ }
159
+ event.dispose(false);
160
+ return event;
161
+ }
162
+ /**
163
+ * Creates a gravitational field
164
+ * @param origin the origin of the gravitational field
165
+ * @param radiusOrEventOptions the radius or the options of radial gravitational field
166
+ * @param strength the gravitational field strength
167
+ * @param falloff possible options: Constant & Linear. Defaults to Constant
168
+ * @returns A physics gravitational field event, or null
169
+ */
170
+ gravitationalField(origin, radiusOrEventOptions, strength, falloff) {
171
+ if (!this._physicsEngine) {
172
+ Logger.Warn("Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.");
173
+ return null;
174
+ }
175
+ if (this._physicsEngine.getPluginVersion() === 1 && this._physicsEngine.getImpostors().length === 0) {
176
+ return null;
177
+ }
178
+ if (this._physicsEngine.getPluginVersion() === 2 && this._physicsEngine.getBodies().length === 0) {
179
+ return null;
180
+ }
181
+ if (typeof radiusOrEventOptions === "number") {
182
+ const r = radiusOrEventOptions;
183
+ radiusOrEventOptions = new PhysicsRadialExplosionEventOptions();
184
+ radiusOrEventOptions.radius = r;
185
+ radiusOrEventOptions.strength = strength !== null && strength !== void 0 ? strength : radiusOrEventOptions.strength;
186
+ radiusOrEventOptions.falloff = falloff !== null && falloff !== void 0 ? falloff : radiusOrEventOptions.falloff;
187
+ }
188
+ const event = new PhysicsGravitationalFieldEvent(this, this._scene, origin, radiusOrEventOptions);
189
+ event.dispose(false);
190
+ return event;
191
+ }
192
+ /**
193
+ * Creates a physics updraft event
194
+ * @param origin the origin of the updraft
195
+ * @param radiusOrEventOptions the radius or the options of the updraft
196
+ * @param strength the strength of the updraft
197
+ * @param height the height of the updraft
198
+ * @param updraftMode possible options: Center & Perpendicular. Defaults to Center
199
+ * @returns A physics updraft event, or null
200
+ */
201
+ updraft(origin, radiusOrEventOptions, strength, height, updraftMode) {
202
+ if (!this._physicsEngine) {
203
+ Logger.Warn("Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.");
204
+ return null;
205
+ }
206
+ if (this._physicsEngine.getPluginVersion() === 1 && this._physicsEngine.getImpostors().length === 0) {
207
+ return null;
208
+ }
209
+ if (this._physicsEngine.getPluginVersion() === 2 && this._physicsEngine.getBodies().length === 0) {
210
+ return null;
211
+ }
212
+ if (typeof radiusOrEventOptions === "number") {
213
+ const r = radiusOrEventOptions;
214
+ radiusOrEventOptions = new PhysicsUpdraftEventOptions();
215
+ radiusOrEventOptions.radius = r;
216
+ radiusOrEventOptions.strength = strength !== null && strength !== void 0 ? strength : radiusOrEventOptions.strength;
217
+ radiusOrEventOptions.height = height !== null && height !== void 0 ? height : radiusOrEventOptions.height;
218
+ radiusOrEventOptions.updraftMode = updraftMode !== null && updraftMode !== void 0 ? updraftMode : radiusOrEventOptions.updraftMode;
219
+ }
220
+ const event = new PhysicsUpdraftEvent(this._scene, origin, radiusOrEventOptions);
221
+ event.dispose(false);
222
+ return event;
223
+ }
224
+ /**
225
+ * Creates a physics vortex event
226
+ * @param origin the of the vortex
227
+ * @param radiusOrEventOptions the radius or the options of the vortex
228
+ * @param strength the strength of the vortex
229
+ * @param height the height of the vortex
230
+ * @returns a Physics vortex event, or null
231
+ * A physics vortex event or null
232
+ */
233
+ vortex(origin, radiusOrEventOptions, strength, height) {
234
+ if (!this._physicsEngine) {
235
+ Logger.Warn("Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.");
236
+ return null;
237
+ }
238
+ if (this._physicsEngine.getPluginVersion() === 1 && this._physicsEngine.getImpostors().length === 0) {
239
+ return null;
240
+ }
241
+ if (this._physicsEngine.getPluginVersion() === 2 && this._physicsEngine.getBodies().length === 0) {
242
+ return null;
243
+ }
244
+ if (typeof radiusOrEventOptions === "number") {
245
+ const r = radiusOrEventOptions;
246
+ radiusOrEventOptions = new PhysicsVortexEventOptions();
247
+ radiusOrEventOptions.radius = r;
248
+ radiusOrEventOptions.strength = strength !== null && strength !== void 0 ? strength : radiusOrEventOptions.strength;
249
+ radiusOrEventOptions.height = height !== null && height !== void 0 ? height : radiusOrEventOptions.height;
250
+ }
251
+ const event = new PhysicsVortexEvent(this._scene, origin, radiusOrEventOptions);
252
+ event.dispose(false);
253
+ return event;
254
+ }
255
+ _copyPhysicsHitData(data) {
256
+ return { force: data.force.clone(), contactPoint: data.contactPoint.clone(), distanceFromOrigin: data.distanceFromOrigin };
257
+ }
258
+ }
259
+ /**
260
+ * Represents a physics radial explosion event
261
+ */
262
+ class PhysicsRadialExplosionEvent {
263
+ /**
264
+ * Initializes a radial explosion event
265
+ * @param _scene BabylonJS scene
266
+ * @param _options The options for the vortex event
267
+ */
268
+ constructor(_scene, _options) {
269
+ this._scene = _scene;
270
+ this._options = _options;
271
+ this._dataFetched = false; // check if the data has been fetched. If not, do cleanup
272
+ this._options = { ...new PhysicsRadialExplosionEventOptions(), ...this._options };
273
+ }
274
+ /**
275
+ * Returns the data related to the radial explosion event (sphere).
276
+ * @returns The radial explosion event data
277
+ */
278
+ getData() {
279
+ this._dataFetched = true;
280
+ return {
281
+ sphere: this._sphere,
282
+ };
283
+ }
284
+ _getHitData(mesh, center, origin, data) {
285
+ const direction = center.subtract(origin);
286
+ const ray = new Ray(origin, direction, this._options.radius);
287
+ const hit = ray.intersectsMesh(mesh);
288
+ const contactPoint = hit.pickedPoint;
289
+ if (!contactPoint) {
290
+ return false;
291
+ }
292
+ const distanceFromOrigin = Vector3.Distance(origin, contactPoint);
293
+ if (distanceFromOrigin > this._options.radius) {
294
+ return false;
295
+ }
296
+ const multiplier = this._options.falloff === PhysicsRadialImpulseFalloff.Constant ? this._options.strength : this._options.strength * (1 - distanceFromOrigin / this._options.radius);
297
+ const force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
298
+ data.force = force;
299
+ data.contactPoint = contactPoint;
300
+ data.distanceFromOrigin = distanceFromOrigin;
301
+ return true;
302
+ }
303
+ /**
304
+ * Returns the force and contact point of the body or false, if the body is not affected by the force/impulse.
305
+ * @param body A physics body
306
+ * @param origin the origin of the explosion
307
+ * @returns A physics force and contact point, or null
308
+ */
309
+ getBodyHitData(body, origin, data) {
310
+ if (body.transformNode.getClassName() !== "Mesh" && body.transformNode.getClassName() !== "InstancedMesh") {
311
+ return false;
312
+ }
313
+ const mesh = body.transformNode;
314
+ if (!this._intersectsWithSphere(mesh, origin, this._options.radius)) {
315
+ return false;
316
+ }
317
+ const bodyObjectCenter = body.getObjectCenter();
318
+ this._getHitData(mesh, bodyObjectCenter, origin, data);
319
+ return true;
320
+ }
321
+ /**
322
+ * Returns the force and contact point of the impostor or false, if the impostor is not affected by the force/impulse.
323
+ * @param impostor A physics imposter
324
+ * @param origin the origin of the explosion
325
+ * @returns A physics force and contact point, or null
326
+ */
327
+ getImpostorHitData(impostor, origin, data) {
328
+ if (impostor.mass === 0) {
329
+ return false;
330
+ }
331
+ if (impostor.object.getClassName() !== "Mesh" && impostor.object.getClassName() !== "InstancedMesh") {
332
+ return false;
333
+ }
334
+ const mesh = impostor.object;
335
+ if (!this._intersectsWithSphere(mesh, origin, this._options.radius)) {
336
+ return false;
337
+ }
338
+ const impostorObjectCenter = impostor.getObjectCenter();
339
+ this._getHitData(mesh, impostorObjectCenter, origin, data);
340
+ return true;
341
+ }
342
+ /**
343
+ * Triggers affected impostors callbacks
344
+ * @param affectedImpostorsWithData defines the list of affected impostors (including associated data)
345
+ */
346
+ triggerAffectedImpostorsCallback(affectedImpostorsWithData) {
347
+ if (this._options.affectedImpostorsCallback) {
348
+ this._options.affectedImpostorsCallback(affectedImpostorsWithData);
349
+ }
350
+ }
351
+ /**
352
+ * Triggers affected bodies callbacks
353
+ * @param affectedBodiesWithData defines the list of affected bodies (including associated data)
354
+ */
355
+ triggerAffectedBodiesCallback(affectedBodiesWithData) {
356
+ if (this._options.affectedBodiesCallback) {
357
+ this._options.affectedBodiesCallback(affectedBodiesWithData);
358
+ }
359
+ }
360
+ /**
361
+ * Disposes the sphere.
362
+ * @param force Specifies if the sphere should be disposed by force
363
+ */
364
+ dispose(force = true) {
365
+ if (force) {
366
+ this._sphere.dispose();
367
+ }
368
+ else {
369
+ setTimeout(() => {
370
+ if (!this._dataFetched) {
371
+ this._sphere.dispose();
372
+ }
373
+ }, 0);
374
+ }
375
+ }
376
+ /*** Helpers ***/
377
+ _prepareSphere() {
378
+ if (!this._sphere) {
379
+ this._sphere = CreateSphere("radialExplosionEventSphere", this._options.sphere, this._scene);
380
+ this._sphere.isVisible = false;
381
+ }
382
+ }
383
+ _intersectsWithSphere(mesh, origin, radius) {
384
+ this._prepareSphere();
385
+ this._sphere.position = origin;
386
+ this._sphere.scaling.setAll(radius * 2);
387
+ this._sphere._updateBoundingInfo();
388
+ this._sphere.computeWorldMatrix(true);
389
+ return this._sphere.intersectsMesh(mesh, true);
390
+ }
391
+ }
392
+ /**
393
+ * Represents a gravitational field event
394
+ */
395
+ class PhysicsGravitationalFieldEvent {
396
+ /**
397
+ * Initializes the physics gravitational field event
398
+ * @param _physicsHelper A physics helper
399
+ * @param _scene BabylonJS scene
400
+ * @param _origin The origin position of the gravitational field event
401
+ * @param _options The options for the vortex event
402
+ */
403
+ constructor(_physicsHelper, _scene, _origin, _options) {
404
+ this._physicsHelper = _physicsHelper;
405
+ this._scene = _scene;
406
+ this._origin = _origin;
407
+ this._options = _options;
408
+ this._dataFetched = false; // check if the has been fetched the data. If not, do cleanup
409
+ this._options = { ...new PhysicsRadialExplosionEventOptions(), ...this._options };
410
+ this._tickCallback = this._tick.bind(this);
411
+ this._options.strength = this._options.strength * -1;
412
+ }
413
+ /**
414
+ * Returns the data related to the gravitational field event (sphere).
415
+ * @returns A gravitational field event
416
+ */
417
+ getData() {
418
+ this._dataFetched = true;
419
+ return {
420
+ sphere: this._sphere,
421
+ };
422
+ }
423
+ /**
424
+ * Enables the gravitational field.
425
+ */
426
+ enable() {
427
+ this._tickCallback.call(this);
428
+ this._scene.registerBeforeRender(this._tickCallback);
429
+ }
430
+ /**
431
+ * Disables the gravitational field.
432
+ */
433
+ disable() {
434
+ this._scene.unregisterBeforeRender(this._tickCallback);
435
+ }
436
+ /**
437
+ * Disposes the sphere.
438
+ * @param force The force to dispose from the gravitational field event
439
+ */
440
+ dispose(force = true) {
441
+ if (force) {
442
+ this._sphere.dispose();
443
+ }
444
+ else {
445
+ setTimeout(() => {
446
+ if (!this._dataFetched) {
447
+ this._sphere.dispose();
448
+ }
449
+ }, 0);
450
+ }
451
+ }
452
+ _tick() {
453
+ // Since the params won't change, we fetch the event only once
454
+ if (this._sphere) {
455
+ this._physicsHelper.applyRadialExplosionForce(this._origin, this._options);
456
+ }
457
+ else {
458
+ const radialExplosionEvent = this._physicsHelper.applyRadialExplosionForce(this._origin, this._options);
459
+ if (radialExplosionEvent) {
460
+ this._sphere = radialExplosionEvent.getData().sphere.clone("radialExplosionEventSphereClone");
461
+ }
462
+ }
463
+ }
464
+ }
465
+ /**
466
+ * Represents a physics updraft event
467
+ */
468
+ class PhysicsUpdraftEvent {
469
+ /**
470
+ * Initializes the physics updraft event
471
+ * @param _scene BabylonJS scene
472
+ * @param _origin The origin position of the updraft
473
+ * @param _options The options for the updraft event
474
+ */
475
+ constructor(_scene, _origin, _options) {
476
+ this._scene = _scene;
477
+ this._origin = _origin;
478
+ this._options = _options;
479
+ this._originTop = Vector3.Zero(); // the most upper part of the cylinder
480
+ this._originDirection = Vector3.Zero(); // used if the updraftMode is perpendicular
481
+ this._cylinderPosition = Vector3.Zero(); // to keep the cylinders position, because normally the origin is in the center and not on the bottom
482
+ this._dataFetched = false; // check if the has been fetched the data. If not, do cleanup
483
+ this._physicsEngine = this._scene.getPhysicsEngine();
484
+ this._options = { ...new PhysicsUpdraftEventOptions(), ...this._options };
485
+ this._origin.addToRef(new Vector3(0, this._options.height / 2, 0), this._cylinderPosition);
486
+ this._origin.addToRef(new Vector3(0, this._options.height, 0), this._originTop);
487
+ if (this._options.updraftMode === PhysicsUpdraftMode.Perpendicular) {
488
+ this._originDirection = this._origin.subtract(this._originTop).normalize();
489
+ }
490
+ this._tickCallback = this._tick.bind(this);
491
+ this._prepareCylinder();
492
+ }
493
+ /**
494
+ * Returns the data related to the updraft event (cylinder).
495
+ * @returns A physics updraft event
496
+ */
497
+ getData() {
498
+ this._dataFetched = true;
499
+ return {
500
+ cylinder: this._cylinder,
501
+ };
502
+ }
503
+ /**
504
+ * Enables the updraft.
505
+ */
506
+ enable() {
507
+ this._tickCallback.call(this);
508
+ this._scene.registerBeforeRender(this._tickCallback);
509
+ }
510
+ /**
511
+ * Disables the updraft.
512
+ */
513
+ disable() {
514
+ this._scene.unregisterBeforeRender(this._tickCallback);
515
+ }
516
+ /**
517
+ * Disposes the cylinder.
518
+ * @param force Specifies if the updraft should be disposed by force
519
+ */
520
+ dispose(force = true) {
521
+ if (!this._cylinder) {
522
+ return;
523
+ }
524
+ if (force) {
525
+ this._cylinder.dispose();
526
+ }
527
+ else {
528
+ setTimeout(() => {
529
+ if (!this._dataFetched) {
530
+ this._cylinder.dispose();
531
+ }
532
+ }, 0);
533
+ }
534
+ }
535
+ _getHitData(center, data) {
536
+ let direction;
537
+ if (this._options.updraftMode === PhysicsUpdraftMode.Perpendicular) {
538
+ direction = this._originDirection;
539
+ }
540
+ else {
541
+ direction = center.subtract(this._originTop);
542
+ }
543
+ const distanceFromOrigin = Vector3.Distance(this._origin, center);
544
+ const multiplier = this._options.strength * -1;
545
+ const force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
546
+ data.force = force;
547
+ data.contactPoint = center;
548
+ data.distanceFromOrigin = distanceFromOrigin;
549
+ }
550
+ _getBodyHitData(body, data) {
551
+ if (body.transformNode.getClassName() !== "Mesh" && body.transformNode.getClassName() !== "InstancedMesh") {
552
+ return false;
553
+ }
554
+ const bodyObject = body.transformNode;
555
+ if (!this._intersectsWithCylinder(bodyObject)) {
556
+ return false;
557
+ }
558
+ const center = body.getObjectCenter();
559
+ this._getHitData(center, data);
560
+ return true;
561
+ }
562
+ _getImpostorHitData(impostor, data) {
563
+ if (impostor.mass === 0) {
564
+ return false;
565
+ }
566
+ const impostorObject = impostor.object;
567
+ if (!this._intersectsWithCylinder(impostorObject)) {
568
+ return false;
569
+ }
570
+ const center = impostor.getObjectCenter();
571
+ this._getHitData(center, data);
572
+ return true;
573
+ }
574
+ _tick() {
575
+ const hitData = PhysicsUpdraftEvent.hitData;
576
+ if (this._physicsEngine.getPluginVersion() === 1) {
577
+ this._physicsEngine.getImpostors().forEach((impostor) => {
578
+ if (!this._getImpostorHitData(impostor, hitData)) {
579
+ return;
580
+ }
581
+ impostor.applyForce(hitData.force, hitData.contactPoint);
582
+ });
583
+ }
584
+ else {
585
+ // V2
586
+ this._physicsEngine.getBodies().forEach((body) => {
587
+ if (!this._getBodyHitData(body, hitData)) {
588
+ return;
589
+ }
590
+ body.applyForce(hitData.force, hitData.contactPoint);
591
+ });
592
+ }
593
+ }
594
+ /*** Helpers ***/
595
+ _prepareCylinder() {
596
+ if (!this._cylinder) {
597
+ this._cylinder = CreateCylinder("updraftEventCylinder", {
598
+ height: this._options.height,
599
+ diameter: this._options.radius * 2,
600
+ }, this._scene);
601
+ this._cylinder.isVisible = false;
602
+ }
603
+ }
604
+ _intersectsWithCylinder(mesh) {
605
+ this._cylinder.position = this._cylinderPosition;
606
+ return this._cylinder.intersectsMesh(mesh, true);
607
+ }
608
+ }
609
+ PhysicsUpdraftEvent.hitData = { force: new Vector3(), contactPoint: new Vector3(), distanceFromOrigin: 0 };
610
+ /**
611
+ * Represents a physics vortex event
612
+ */
613
+ class PhysicsVortexEvent {
614
+ /**
615
+ * Initializes the physics vortex event
616
+ * @param _scene The BabylonJS scene
617
+ * @param _origin The origin position of the vortex
618
+ * @param _options The options for the vortex event
619
+ */
620
+ constructor(_scene, _origin, _options) {
621
+ this._scene = _scene;
622
+ this._origin = _origin;
623
+ this._options = _options;
624
+ this._originTop = Vector3.Zero(); // the most upper part of the cylinder
625
+ this._cylinderPosition = Vector3.Zero(); // to keep the cylinders position, because normally the origin is in the center and not on the bottom
626
+ this._dataFetched = false; // check if the has been fetched the data. If not, do cleanup
627
+ this._physicsEngine = this._scene.getPhysicsEngine();
628
+ this._options = { ...new PhysicsVortexEventOptions(), ...this._options };
629
+ this._origin.addToRef(new Vector3(0, this._options.height / 2, 0), this._cylinderPosition);
630
+ this._origin.addToRef(new Vector3(0, this._options.height, 0), this._originTop);
631
+ this._tickCallback = this._tick.bind(this);
632
+ this._prepareCylinder();
633
+ }
634
+ /**
635
+ * Returns the data related to the vortex event (cylinder).
636
+ * @returns The physics vortex event data
637
+ */
638
+ getData() {
639
+ this._dataFetched = true;
640
+ return {
641
+ cylinder: this._cylinder,
642
+ };
643
+ }
644
+ /**
645
+ * Enables the vortex.
646
+ */
647
+ enable() {
648
+ this._tickCallback.call(this);
649
+ this._scene.registerBeforeRender(this._tickCallback);
650
+ }
651
+ /**
652
+ * Disables the cortex.
653
+ */
654
+ disable() {
655
+ this._scene.unregisterBeforeRender(this._tickCallback);
656
+ }
657
+ /**
658
+ * Disposes the sphere.
659
+ * @param force
660
+ */
661
+ dispose(force = true) {
662
+ if (force) {
663
+ this._cylinder.dispose();
664
+ }
665
+ else {
666
+ setTimeout(() => {
667
+ if (!this._dataFetched) {
668
+ this._cylinder.dispose();
669
+ }
670
+ }, 0);
671
+ }
672
+ }
673
+ _getHitData(mesh, center, data) {
674
+ const originOnPlane = PhysicsVortexEvent.originOnPlane;
675
+ originOnPlane.set(this._origin.x, center.y, this._origin.z); // the distance to the origin as if both objects were on a plane (Y-axis)
676
+ const originToImpostorDirection = center.subtract(originOnPlane);
677
+ const ray = new Ray(originOnPlane, originToImpostorDirection, this._options.radius);
678
+ const hit = ray.intersectsMesh(mesh);
679
+ const contactPoint = hit.pickedPoint;
680
+ if (!contactPoint) {
681
+ return false;
682
+ }
683
+ const absoluteDistanceFromOrigin = hit.distance / this._options.radius;
684
+ let directionToOrigin = contactPoint.normalize();
685
+ if (absoluteDistanceFromOrigin > this._options.centripetalForceThreshold) {
686
+ directionToOrigin = directionToOrigin.negate();
687
+ }
688
+ let forceX;
689
+ let forceY;
690
+ let forceZ;
691
+ if (absoluteDistanceFromOrigin > this._options.centripetalForceThreshold) {
692
+ forceX = directionToOrigin.x * this._options.centripetalForceMultiplier;
693
+ forceY = directionToOrigin.y * this._options.updraftForceMultiplier;
694
+ forceZ = directionToOrigin.z * this._options.centripetalForceMultiplier;
695
+ }
696
+ else {
697
+ const perpendicularDirection = Vector3.Cross(originOnPlane, center).normalize();
698
+ forceX = (perpendicularDirection.x + directionToOrigin.x) * this._options.centrifugalForceMultiplier;
699
+ forceY = this._originTop.y * this._options.updraftForceMultiplier;
700
+ forceZ = (perpendicularDirection.z + directionToOrigin.z) * this._options.centrifugalForceMultiplier;
701
+ }
702
+ let force = new Vector3(forceX, forceY, forceZ);
703
+ force = force.multiplyByFloats(this._options.strength, this._options.strength, this._options.strength);
704
+ data.force = force;
705
+ data.contactPoint = center;
706
+ data.distanceFromOrigin = absoluteDistanceFromOrigin;
707
+ return true;
708
+ }
709
+ _getBodyHitData(body, data) {
710
+ if (body.transformNode.getClassName() !== "Mesh" && body.transformNode.getClassName() !== "InstancedMesh") {
711
+ return false;
712
+ }
713
+ const bodyObject = body.transformNode;
714
+ if (!this._intersectsWithCylinder(bodyObject)) {
715
+ return false;
716
+ }
717
+ const bodyCenter = body.getObjectCenter();
718
+ this._getHitData(bodyObject, bodyCenter, data);
719
+ return true;
720
+ }
721
+ _getImpostorHitData(impostor, data) {
722
+ if (impostor.mass === 0) {
723
+ return false;
724
+ }
725
+ if (impostor.object.getClassName() !== "Mesh" && impostor.object.getClassName() !== "InstancedMesh") {
726
+ return false;
727
+ }
728
+ const impostorObject = impostor.object;
729
+ if (!this._intersectsWithCylinder(impostorObject)) {
730
+ return false;
731
+ }
732
+ const impostorObjectCenter = impostor.getObjectCenter();
733
+ this._getHitData(impostorObject, impostorObjectCenter, data);
734
+ return true;
735
+ }
736
+ _tick() {
737
+ const hitData = PhysicsVortexEvent.hitData;
738
+ if (this._physicsEngine.getPluginVersion() === 1) {
739
+ this._physicsEngine.getImpostors().forEach((impostor) => {
740
+ if (!this._getImpostorHitData(impostor, hitData)) {
741
+ return;
742
+ }
743
+ impostor.applyForce(hitData.force, hitData.contactPoint);
744
+ });
745
+ }
746
+ else {
747
+ this._physicsEngine.getBodies().forEach((body) => {
748
+ if (!this._getBodyHitData(body, hitData)) {
749
+ return;
750
+ }
751
+ body.applyForce(hitData.force, hitData.contactPoint);
752
+ });
753
+ }
754
+ }
755
+ /*** Helpers ***/
756
+ _prepareCylinder() {
757
+ if (!this._cylinder) {
758
+ this._cylinder = CreateCylinder("vortexEventCylinder", {
759
+ height: this._options.height,
760
+ diameter: this._options.radius * 2,
761
+ }, this._scene);
762
+ this._cylinder.isVisible = false;
763
+ }
764
+ }
765
+ _intersectsWithCylinder(mesh) {
766
+ this._cylinder.position = this._cylinderPosition;
767
+ return this._cylinder.intersectsMesh(mesh, true);
768
+ }
769
+ }
770
+ PhysicsVortexEvent.originOnPlane = Vector3.Zero();
771
+ PhysicsVortexEvent.hitData = { force: new Vector3(), contactPoint: new Vector3(), distanceFromOrigin: 0 };
772
+ /**
773
+ * Options fot the radial explosion event
774
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/physics/usingPhysicsEngine#further-functionality-of-the-impostor-class
775
+ */
776
+ export class PhysicsRadialExplosionEventOptions {
777
+ constructor() {
778
+ /**
779
+ * The radius of the sphere for the radial explosion.
780
+ */
781
+ this.radius = 5;
782
+ /**
783
+ * The strength of the explosion.
784
+ */
785
+ this.strength = 10;
786
+ /**
787
+ * The strength of the force in correspondence to the distance of the affected object
788
+ */
789
+ this.falloff = PhysicsRadialImpulseFalloff.Constant;
790
+ /**
791
+ * Sphere options for the radial explosion.
792
+ */
793
+ this.sphere = { segments: 32, diameter: 1 };
794
+ }
795
+ }
796
+ /**
797
+ * Options fot the updraft event
798
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/physics/usingPhysicsEngine#further-functionality-of-the-impostor-class
799
+ */
800
+ export class PhysicsUpdraftEventOptions {
801
+ constructor() {
802
+ /**
803
+ * The radius of the cylinder for the vortex
804
+ */
805
+ this.radius = 5;
806
+ /**
807
+ * The strength of the updraft.
808
+ */
809
+ this.strength = 10;
810
+ /**
811
+ * The height of the cylinder for the updraft.
812
+ */
813
+ this.height = 10;
814
+ /**
815
+ * The mode for the the updraft.
816
+ */
817
+ this.updraftMode = PhysicsUpdraftMode.Center;
818
+ }
819
+ }
820
+ /**
821
+ * Options fot the vortex event
822
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/physics/usingPhysicsEngine#further-functionality-of-the-impostor-class
823
+ */
824
+ export class PhysicsVortexEventOptions {
825
+ constructor() {
826
+ /**
827
+ * The radius of the cylinder for the vortex
828
+ */
829
+ this.radius = 5;
830
+ /**
831
+ * The strength of the vortex.
832
+ */
833
+ this.strength = 10;
834
+ /**
835
+ * The height of the cylinder for the vortex.
836
+ */
837
+ this.height = 10;
838
+ /**
839
+ * At which distance, relative to the radius the centripetal forces should kick in? Range: 0-1
840
+ */
841
+ this.centripetalForceThreshold = 0.7;
842
+ /**
843
+ * This multiplier determines with how much force the objects will be pushed sideways/around the vortex, when below the threshold.
844
+ */
845
+ this.centripetalForceMultiplier = 5;
846
+ /**
847
+ * This multiplier determines with how much force the objects will be pushed sideways/around the vortex, when above the threshold.
848
+ */
849
+ this.centrifugalForceMultiplier = 0.5;
850
+ /**
851
+ * This multiplier determines with how much force the objects will be pushed upwards, when in the vortex.
852
+ */
853
+ this.updraftForceMultiplier = 0.02;
854
+ }
855
+ }
856
+ /**
857
+ * The strength of the force in correspondence to the distance of the affected object
858
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/physics/usingPhysicsEngine#further-functionality-of-the-impostor-class
859
+ */
860
+ export var PhysicsRadialImpulseFalloff;
861
+ (function (PhysicsRadialImpulseFalloff) {
862
+ /** Defines that impulse is constant in strength across it's whole radius */
863
+ PhysicsRadialImpulseFalloff[PhysicsRadialImpulseFalloff["Constant"] = 0] = "Constant";
864
+ /** Defines that impulse gets weaker if it's further from the origin */
865
+ PhysicsRadialImpulseFalloff[PhysicsRadialImpulseFalloff["Linear"] = 1] = "Linear";
866
+ })(PhysicsRadialImpulseFalloff || (PhysicsRadialImpulseFalloff = {}));
867
+ /**
868
+ * The strength of the force in correspondence to the distance of the affected object
869
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/physics/usingPhysicsEngine#further-functionality-of-the-impostor-class
870
+ */
871
+ export var PhysicsUpdraftMode;
872
+ (function (PhysicsUpdraftMode) {
873
+ /** Defines that the upstream forces will pull towards the top center of the cylinder */
874
+ PhysicsUpdraftMode[PhysicsUpdraftMode["Center"] = 0] = "Center";
875
+ /** Defines that once a impostor is inside the cylinder, it will shoot out perpendicular from the ground of the cylinder */
876
+ PhysicsUpdraftMode[PhysicsUpdraftMode["Perpendicular"] = 1] = "Perpendicular";
877
+ })(PhysicsUpdraftMode || (PhysicsUpdraftMode = {}));
3
878
  //# sourceMappingURL=physicsHelper.js.map