Browse Source

Merge pull request #5935 from bobalazek/master

Physics helper refactoring & physics raycasting
David Catuhe 6 years ago
parent
commit
54d986e770

+ 1 - 0
dist/preview release/what's new.md

@@ -269,3 +269,4 @@
 (https://github.com/Sebavan))
 (https://github.com/Sebavan))
 - No more `Primitive Geometries` as they were not in use since 2.0 ([Sebavan](https://github.com/Sebavan))
 - No more `Primitive Geometries` as they were not in use since 2.0 ([Sebavan](https://github.com/Sebavan))
 - Change `shouldExportTransformNode` callback in glTF serializer options to `shouldExportNode`([kcoley](https://github.com/kcoley))
 - Change `shouldExportTransformNode` callback in glTF serializer options to `shouldExportNode`([kcoley](https://github.com/kcoley))
+- Changed `PhysicsHelper` method parameters for event calls ([bobalazek](https://github.com/bobalazek))

+ 10 - 0
src/Physics/IPhysicsEngine.ts

@@ -3,6 +3,8 @@ import { Vector3, Quaternion } from "../Maths/math";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { PhysicsImpostor, IPhysicsEnabledObject } from "./physicsImpostor";
 import { PhysicsImpostor, IPhysicsEnabledObject } from "./physicsImpostor";
 import { PhysicsJoint, IMotorEnabledJoint } from "./physicsJoint";
 import { PhysicsJoint, IMotorEnabledJoint } from "./physicsJoint";
+import { PhysicsRaycastResult } from "./physicsRaycastResult";
+
 /**
 /**
  * Interface used to describe a physics joint
  * Interface used to describe a physics joint
  */
  */
@@ -44,6 +46,7 @@ export interface IPhysicsEnginePlugin {
     setBodyRestitution(impostor: PhysicsImpostor, restitution: number): void;
     setBodyRestitution(impostor: PhysicsImpostor, restitution: number): void;
     sleepBody(impostor: PhysicsImpostor): void;
     sleepBody(impostor: PhysicsImpostor): void;
     wakeUpBody(impostor: PhysicsImpostor): void;
     wakeUpBody(impostor: PhysicsImpostor): void;
+    raycast(from: Vector3, to: Vector3): PhysicsRaycastResult;
     //Joint Update
     //Joint Update
     updateDistanceJoint(joint: PhysicsJoint, maxDistance: number, minDistance?: number): void;
     updateDistanceJoint(joint: PhysicsJoint, maxDistance: number, minDistance?: number): void;
     setMotor(joint: IMotorEnabledJoint, speed: number, maxForce?: number, motorIndex?: number): void;
     setMotor(joint: IMotorEnabledJoint, speed: number, maxForce?: number, motorIndex?: number): void;
@@ -153,6 +156,13 @@ export interface IPhysicsEngine {
     getImpostorWithPhysicsBody(body: any): Nullable<PhysicsImpostor>;
     getImpostorWithPhysicsBody(body: any): Nullable<PhysicsImpostor>;
 
 
     /**
     /**
+     * Does a raycast in the physics world
+     * @param from defines physics body used by the impostor
+     * @returns PhysicsRaycastResult
+     */
+    raycast(from: Vector3, to: Vector3): PhysicsRaycastResult;
+
+    /**
      * Called by the scene. No need to call it.
      * Called by the scene. No need to call it.
      * @param delta defines the timespam between frames
      * @param delta defines the timespam between frames
      */
      */

+ 43 - 0
src/Physics/Plugins/ammoJSPlugin.ts

@@ -6,6 +6,7 @@ import { PhysicsJoint, IMotorEnabledJoint, DistanceJointData } from "../../Physi
 import { VertexBuffer } from "../../Meshes/buffer";
 import { VertexBuffer } from "../../Meshes/buffer";
 import { Nullable } from "../../types";
 import { Nullable } from "../../types";
 import { AbstractMesh } from "../../Meshes/abstractMesh";
 import { AbstractMesh } from "../../Meshes/abstractMesh";
+import { PhysicsRaycastResult } from "../physicsRaycastResult";
 
 
 declare var Ammo: any;
 declare var Ammo: any;
 
 
@@ -43,6 +44,9 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
     private _tmpAmmoVectorB: any;
     private _tmpAmmoVectorB: any;
     private _tmpAmmoVectorC: any;
     private _tmpAmmoVectorC: any;
     private _tmpContactCallbackResult = false;
     private _tmpContactCallbackResult = false;
+    private _tmpAmmoVectorRCA: any;
+    private _tmpAmmoVectorRCB: any;
+    private _raycastResult: PhysicsRaycastResult;
 
 
     private static readonly DISABLE_COLLISION_FLAG = 4;
     private static readonly DISABLE_COLLISION_FLAG = 4;
     private static readonly KINEMATIC_FLAG = 2;
     private static readonly KINEMATIC_FLAG = 2;
@@ -787,4 +791,43 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
 
 
         this.world = null;
         this.world = null;
     }
     }
+
+    /**
+     * @param from when should the ray start?
+     * @param to when should the ray end?
+     * @returns the raycast result
+     */
+    public raycast(from: Vector3, to: Vector3): PhysicsRaycastResult {
+        this._tmpAmmoVectorRCA = new this.bjsAMMO.btVector3(from.x, from.y, from.z);
+        this._tmpAmmoVectorRCB = new this.bjsAMMO.btVector3(to.x, to.y, to.z);
+
+        var rayCallback = new this.bjsAMMO.ClosestRayResultCallback(this._tmpAmmoVectorRCA, this._tmpAmmoVectorRCB);
+        this.world.rayTest(this._tmpAmmoVectorRCA, this._tmpAmmoVectorRCB, rayCallback);
+
+        this._raycastResult.reset(from, to);
+        if (rayCallback.hasHit()) {
+            // TODO: do we want/need the body? If so, set all the data
+            /*
+            var rigidBody = this.bjsAMMO.btRigidBody.prototype.upcast(
+                rayCallback.get_m_collisionObject()
+            );
+            var body = {};
+            */
+            this._raycastResult.setHitData(
+                {
+                    x: rayCallback.get_m_hitNormalWorld().x(),
+                    y: rayCallback.get_m_hitNormalWorld().y(),
+                    z: rayCallback.get_m_hitNormalWorld().z(),
+                },
+                {
+                    x: rayCallback.get_m_hitPointWorld().x(),
+                    y: rayCallback.get_m_hitPointWorld().y(),
+                    z: rayCallback.get_m_hitPointWorld().z(),
+                }
+            );
+            this._raycastResult.calculateHitDistance();
+        }
+
+        return this._raycastResult;
+    }
 }
 }

+ 35 - 0
src/Physics/Plugins/cannonJSPlugin.ts

@@ -7,6 +7,7 @@ import { IPhysicsEnginePlugin, PhysicsImpostorJoint } from "../../Physics/IPhysi
 import { PhysicsImpostor, IPhysicsEnabledObject } from "../../Physics/physicsImpostor";
 import { PhysicsImpostor, IPhysicsEnabledObject } from "../../Physics/physicsImpostor";
 import { PhysicsJoint, IMotorEnabledJoint, DistanceJointData, SpringJointData } from "../../Physics/physicsJoint";
 import { PhysicsJoint, IMotorEnabledJoint, DistanceJointData, SpringJointData } from "../../Physics/physicsJoint";
 import { PhysicsEngine } from "../../Physics/physicsEngine";
 import { PhysicsEngine } from "../../Physics/physicsEngine";
+import { PhysicsRaycastResult } from "../physicsRaycastResult";
 
 
 //declare var require: any;
 //declare var require: any;
 declare var CANNON: any;
 declare var CANNON: any;
@@ -18,6 +19,8 @@ export class CannonJSPlugin implements IPhysicsEnginePlugin {
     public name: string = "CannonJSPlugin";
     public name: string = "CannonJSPlugin";
     private _physicsMaterials = new Array();
     private _physicsMaterials = new Array();
     private _fixedTimeStep: number = 1 / 60;
     private _fixedTimeStep: number = 1 / 60;
+    private _cannonRaycastResult: any;
+    private _raycastResult: PhysicsRaycastResult;
     //See https://github.com/schteppe/CANNON.js/blob/gh-pages/demos/collisionFilter.html
     //See https://github.com/schteppe/CANNON.js/blob/gh-pages/demos/collisionFilter.html
     public BJSCANNON: any;
     public BJSCANNON: any;
 
 
@@ -33,6 +36,8 @@ export class CannonJSPlugin implements IPhysicsEnginePlugin {
         this.world = new this.BJSCANNON.World();
         this.world = new this.BJSCANNON.World();
         this.world.broadphase = new this.BJSCANNON.NaiveBroadphase();
         this.world.broadphase = new this.BJSCANNON.NaiveBroadphase();
         this.world.solver.iterations = iterations;
         this.world.solver.iterations = iterations;
+        this._cannonRaycastResult = new this.BJSCANNON.RaycastResult();
+        this._raycastResult = new PhysicsRaycastResult();
     }
     }
 
 
     public setGravity(gravity: Vector3): void {
     public setGravity(gravity: Vector3): void {
@@ -674,6 +679,36 @@ export class CannonJSPlugin implements IPhysicsEnginePlugin {
             }
             }
         };
         };
     }
     }
+
+    /**
+     * @param from when should the ray start?
+     * @param to when should the ray end?
+     * @returns the raycast result
+     */
+    public raycast(from: Vector3, to: Vector3): PhysicsRaycastResult {
+        this._cannonRaycastResult.reset();
+        this.world.raycastClosest(from, to, {}, this._cannonRaycastResult);
+
+        this._raycastResult.reset(from, to);
+        if (this._cannonRaycastResult.hasHit) {
+            // TODO: do we also want to get the body it hit?
+            this._raycastResult.setHitData(
+                {
+                    x: this._cannonRaycastResult.hitNormalWorld.x,
+                    y: this._cannonRaycastResult.hitNormalWorld.y,
+                    z: this._cannonRaycastResult.hitNormalWorld.z,
+                },
+                {
+                    x: this._cannonRaycastResult.hitPointWorld.x,
+                    y: this._cannonRaycastResult.hitPointWorld.y,
+                    z: this._cannonRaycastResult.hitPointWorld.z,
+                }
+            );
+            this._raycastResult.setHitDistance(this._cannonRaycastResult.distance);
+        }
+
+        return this._raycastResult;
+    }
 }
 }
 
 
 PhysicsEngine.DefaultPluginFactory = () => { return new CannonJSPlugin(); };
 PhysicsEngine.DefaultPluginFactory = () => { return new CannonJSPlugin(); };

+ 16 - 0
src/Physics/Plugins/oimoJSPlugin.ts

@@ -6,6 +6,7 @@ import { AbstractMesh } from "../../Meshes/abstractMesh";
 import { Vector3, Quaternion } from "../../Maths/math";
 import { Vector3, Quaternion } from "../../Maths/math";
 import { Nullable } from "../../types";
 import { Nullable } from "../../types";
 import { Logger } from "../../Misc/logger";
 import { Logger } from "../../Misc/logger";
+import { PhysicsRaycastResult } from "../physicsRaycastResult";
 
 
 declare var OIMO: any;
 declare var OIMO: any;
 
 
@@ -15,6 +16,7 @@ export class OimoJSPlugin implements IPhysicsEnginePlugin {
     public world: any;
     public world: any;
     public name: string = "OimoJSPlugin";
     public name: string = "OimoJSPlugin";
     public BJSOIMO: any;
     public BJSOIMO: any;
+    private _raycastResult: PhysicsRaycastResult;
 
 
     constructor(iterations?: number, oimoInjection = OIMO) {
     constructor(iterations?: number, oimoInjection = OIMO) {
         this.BJSOIMO = oimoInjection;
         this.BJSOIMO = oimoInjection;
@@ -22,6 +24,7 @@ export class OimoJSPlugin implements IPhysicsEnginePlugin {
             iterations: iterations
             iterations: iterations
         });
         });
         this.world.clear();
         this.world.clear();
+        this._raycastResult = new PhysicsRaycastResult();
     }
     }
 
 
     public setGravity(gravity: Vector3) {
     public setGravity(gravity: Vector3) {
@@ -474,4 +477,17 @@ export class OimoJSPlugin implements IPhysicsEnginePlugin {
     public dispose() {
     public dispose() {
         this.world.clear();
         this.world.clear();
     }
     }
+
+    /**
+     * @param from when should the ray start?
+     * @param to when should the ray end?
+     * @returns the raycast result
+     */
+    public raycast(from: Vector3, to: Vector3): PhysicsRaycastResult {
+        Logger.Warn("raycast is not currently supported by the Oimo physics plugin");
+
+        this._raycastResult.reset(from, to);
+
+        return this._raycastResult;
+    }
 }
 }

+ 9 - 0
src/Physics/physicsEngine.ts

@@ -3,6 +3,7 @@ import { Vector3 } from "../Maths/math";
 import { IPhysicsEngine, PhysicsImpostorJoint, IPhysicsEnginePlugin } from "./IPhysicsEngine";
 import { IPhysicsEngine, PhysicsImpostorJoint, IPhysicsEnginePlugin } from "./IPhysicsEngine";
 import { PhysicsImpostor, IPhysicsEnabledObject } from "./physicsImpostor";
 import { PhysicsImpostor, IPhysicsEnabledObject } from "./physicsImpostor";
 import { PhysicsJoint } from "./physicsJoint";
 import { PhysicsJoint } from "./physicsJoint";
+import { PhysicsRaycastResult } from "./physicsRaycastResult";
 import { _DevTools } from '../Misc/devTools';
 import { _DevTools } from '../Misc/devTools';
 
 
 /**
 /**
@@ -225,4 +226,12 @@ export class PhysicsEngine implements IPhysicsEngine {
 
 
         return null;
         return null;
     }
     }
+
+    /**
+     * @param from when should the ray start?
+     * @param to when should the ray end?
+     */
+    public raycast(from: Vector3, to: Vector3): PhysicsRaycastResult {
+        return this._physicsPlugin.raycast(from, to);
+    }
 }
 }

+ 221 - 117
src/Physics/physicsHelper.ts

@@ -13,7 +13,7 @@ import { PhysicsImpostor } from "./physicsImpostor";
 
 
 /**
 /**
  * A helper for physics simulations
  * A helper for physics simulations
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
  */
  */
 export class PhysicsHelper {
 export class PhysicsHelper {
 
 
@@ -30,18 +30,19 @@ export class PhysicsHelper {
 
 
         if (!this._physicsEngine) {
         if (!this._physicsEngine) {
             Logger.Warn('Physics engine not enabled. Please enable the physics before you can use the methods.');
             Logger.Warn('Physics engine not enabled. Please enable the physics before you can use the methods.');
+            return;
         }
         }
     }
     }
 
 
     /**
     /**
      * Applies a radial explosion impulse
      * Applies a radial explosion impulse
      * @param origin the origin of the explosion
      * @param origin the origin of the explosion
-     * @param radius the explosion radius
+     * @param radiusOrEventOptions the radius or the options of radial explosion
      * @param strength the explosion strength
      * @param strength the explosion strength
      * @param falloff possible options: Constant & Linear. Defaults to Constant
      * @param falloff possible options: Constant & Linear. Defaults to Constant
      * @returns A physics radial explosion event, or null
      * @returns A physics radial explosion event, or null
      */
      */
-    public applyRadialExplosionImpulse(origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFalloff = PhysicsRadialImpulseFalloff.Constant): Nullable<PhysicsRadialExplosionEvent> {
+    public applyRadialExplosionImpulse(origin: Vector3, radiusOrEventOptions: number | PhysicsRadialExplosionEventOptions, strength?: number, falloff?: PhysicsRadialImpulseFalloff): Nullable<PhysicsRadialExplosionEvent> {
         if (!this._physicsEngine) {
         if (!this._physicsEngine) {
             Logger.Warn('Physics engine not enabled. Please enable the physics before you call this method.');
             Logger.Warn('Physics engine not enabled. Please enable the physics before you call this method.');
             return null;
             return null;
@@ -52,10 +53,17 @@ export class PhysicsHelper {
             return null;
             return null;
         }
         }
 
 
-        var event = new PhysicsRadialExplosionEvent(this._scene);
+        if (typeof radiusOrEventOptions === 'number') {
+            radiusOrEventOptions = new PhysicsRadialExplosionEventOptions();
+            radiusOrEventOptions.radius = <number><any>radiusOrEventOptions;
+            radiusOrEventOptions.strength = strength || radiusOrEventOptions.strength;
+            radiusOrEventOptions.falloff = falloff || radiusOrEventOptions.falloff;
+        }
+
+        var event = new PhysicsRadialExplosionEvent(this, this._scene, radiusOrEventOptions);
 
 
         impostors.forEach((impostor) => {
         impostors.forEach((impostor) => {
-            var impostorForceAndContactPoint = event.getImpostorForceAndContactPoint(impostor, origin, radius, strength, falloff);
+            var impostorForceAndContactPoint = event.getImpostorForceAndContactPoint(impostor, origin);
             if (!impostorForceAndContactPoint) {
             if (!impostorForceAndContactPoint) {
                 return;
                 return;
             }
             }
@@ -71,12 +79,12 @@ export class PhysicsHelper {
     /**
     /**
      * Applies a radial explosion force
      * Applies a radial explosion force
      * @param origin the origin of the explosion
      * @param origin the origin of the explosion
-     * @param radius the explosion radius
+     * @param radiusOrEventOptions the radius or the options of radial explosion
      * @param strength the explosion strength
      * @param strength the explosion strength
      * @param falloff possible options: Constant & Linear. Defaults to Constant
      * @param falloff possible options: Constant & Linear. Defaults to Constant
      * @returns A physics radial explosion event, or null
      * @returns A physics radial explosion event, or null
      */
      */
-    public applyRadialExplosionForce(origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFalloff = PhysicsRadialImpulseFalloff.Constant): Nullable<PhysicsRadialExplosionEvent> {
+    public applyRadialExplosionForce(origin: Vector3, radiusOrEventOptions: number | PhysicsRadialExplosionEventOptions, strength?: number, falloff?: PhysicsRadialImpulseFalloff): Nullable<PhysicsRadialExplosionEvent> {
         if (!this._physicsEngine) {
         if (!this._physicsEngine) {
             Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
             Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
             return null;
             return null;
@@ -87,10 +95,17 @@ export class PhysicsHelper {
             return null;
             return null;
         }
         }
 
 
-        var event = new PhysicsRadialExplosionEvent(this._scene);
+        if (typeof radiusOrEventOptions === 'number') {
+            radiusOrEventOptions = new PhysicsRadialExplosionEventOptions();
+            radiusOrEventOptions.radius = <number><any>radiusOrEventOptions;
+            radiusOrEventOptions.strength = strength || radiusOrEventOptions.strength;
+            radiusOrEventOptions.falloff = falloff || radiusOrEventOptions.falloff;
+        }
+
+        var event = new PhysicsRadialExplosionEvent(this, this._scene, radiusOrEventOptions);
 
 
         impostors.forEach((impostor) => {
         impostors.forEach((impostor) => {
-            var impostorForceAndContactPoint = event.getImpostorForceAndContactPoint(impostor, origin, radius, strength, falloff);
+            var impostorForceAndContactPoint = event.getImpostorForceAndContactPoint(impostor, origin);
             if (!impostorForceAndContactPoint) {
             if (!impostorForceAndContactPoint) {
                 return;
                 return;
             }
             }
@@ -106,12 +121,12 @@ export class PhysicsHelper {
     /**
     /**
      * Creates a gravitational field
      * Creates a gravitational field
      * @param origin the origin of the explosion
      * @param origin the origin of the explosion
-     * @param radius the explosion radius
+     * @param radiusOrEventOptions the radius or the options of radial explosion
      * @param strength the explosion strength
      * @param strength the explosion strength
      * @param falloff possible options: Constant & Linear. Defaults to Constant
      * @param falloff possible options: Constant & Linear. Defaults to Constant
      * @returns A physics gravitational field event, or null
      * @returns A physics gravitational field event, or null
      */
      */
-    public gravitationalField(origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFalloff = PhysicsRadialImpulseFalloff.Constant): Nullable<PhysicsGravitationalFieldEvent> {
+    public gravitationalField(origin: Vector3, radiusOrEventOptions: number | PhysicsRadialExplosionEventOptions, strength?: number, falloff?: PhysicsRadialImpulseFalloff): Nullable<PhysicsGravitationalFieldEvent> {
         if (!this._physicsEngine) {
         if (!this._physicsEngine) {
             Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
             Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
             return null;
             return null;
@@ -122,7 +137,14 @@ export class PhysicsHelper {
             return null;
             return null;
         }
         }
 
 
-        var event = new PhysicsGravitationalFieldEvent(this, this._scene, origin, radius, strength, falloff);
+        if (typeof radiusOrEventOptions === 'number') {
+            radiusOrEventOptions = new PhysicsRadialExplosionEventOptions();
+            radiusOrEventOptions.radius = <number><any>radiusOrEventOptions;
+            radiusOrEventOptions.strength = strength || radiusOrEventOptions.strength;
+            radiusOrEventOptions.falloff = falloff || radiusOrEventOptions.falloff;
+        }
+
+        var event = new PhysicsGravitationalFieldEvent(this, this._scene, origin, radiusOrEventOptions);
 
 
         event.dispose(false);
         event.dispose(false);
 
 
@@ -132,13 +154,13 @@ export class PhysicsHelper {
     /**
     /**
      * Creates a physics updraft event
      * Creates a physics updraft event
      * @param origin the origin of the updraft
      * @param origin the origin of the updraft
-     * @param radius the radius of the updraft
+     * @param radiusOrEventOptions the radius or the options of the updraft
      * @param strength the strength of the updraft
      * @param strength the strength of the updraft
      * @param height the height of the updraft
      * @param height the height of the updraft
      * @param updraftMode possible options: Center & Perpendicular. Defaults to Center
      * @param updraftMode possible options: Center & Perpendicular. Defaults to Center
      * @returns A physics updraft event, or null
      * @returns A physics updraft event, or null
      */
      */
-    public updraft(origin: Vector3, radius: number, strength: number, height: number, updraftMode: PhysicsUpdraftMode = PhysicsUpdraftMode.Center): Nullable<PhysicsUpdraftEvent> {
+    public updraft(origin: Vector3, radiusOrEventOptions: number | PhysicsUpdraftEventOptions, strength?: number, height?: number, updraftMode?: PhysicsUpdraftMode): Nullable<PhysicsUpdraftEvent> {
         if (!this._physicsEngine) {
         if (!this._physicsEngine) {
             Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
             Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
             return null;
             return null;
@@ -148,7 +170,15 @@ export class PhysicsHelper {
             return null;
             return null;
         }
         }
 
 
-        var event = new PhysicsUpdraftEvent(this._scene, origin, radius, strength, height, updraftMode);
+        if (typeof radiusOrEventOptions === 'number') {
+            radiusOrEventOptions = new PhysicsUpdraftEventOptions();
+            radiusOrEventOptions.radius = <number><any>radiusOrEventOptions;
+            radiusOrEventOptions.strength = strength || radiusOrEventOptions.strength;
+            radiusOrEventOptions.height = height || radiusOrEventOptions.height;
+            radiusOrEventOptions.updraftMode = updraftMode || radiusOrEventOptions.updraftMode;
+        }
+
+        var event = new PhysicsUpdraftEvent(this, this._scene, origin, radiusOrEventOptions);
 
 
         event.dispose(false);
         event.dispose(false);
 
 
@@ -158,13 +188,13 @@ export class PhysicsHelper {
     /**
     /**
      * Creates a physics vortex event
      * Creates a physics vortex event
      * @param origin the of the vortex
      * @param origin the of the vortex
-     * @param radius the radius of the vortex
+     * @param radiusOrEventOptions the radius or the options of the vortex
      * @param strength the strength of the vortex
      * @param strength the strength of the vortex
      * @param height   the height of the vortex
      * @param height   the height of the vortex
      * @returns a Physics vortex event, or null
      * @returns a Physics vortex event, or null
      * A physics vortex event or null
      * A physics vortex event or null
      */
      */
-    public vortex(origin: Vector3, radius: number, strength: number, height: number): Nullable<PhysicsVortexEvent> {
+    public vortex(origin: Vector3, radiusOrEventOptions: number | PhysicsVortexEventOptions, strength?: number, height?: number): Nullable<PhysicsVortexEvent> {
         if (!this._physicsEngine) {
         if (!this._physicsEngine) {
             Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
             Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
             return null;
             return null;
@@ -174,7 +204,14 @@ export class PhysicsHelper {
             return null;
             return null;
         }
         }
 
 
-        var event = new PhysicsVortexEvent(this._scene, origin, radius, strength, height);
+        if (typeof radiusOrEventOptions === 'number') {
+            radiusOrEventOptions = new PhysicsVortexEventOptions();
+            radiusOrEventOptions.radius = <number><any>radiusOrEventOptions;
+            radiusOrEventOptions.strength = strength || radiusOrEventOptions.strength;
+            radiusOrEventOptions.height = height || radiusOrEventOptions.height;
+        }
+
+        var event = new PhysicsVortexEvent(this, this._scene, origin, radiusOrEventOptions);
 
 
         event.dispose(false);
         event.dispose(false);
 
 
@@ -184,26 +221,24 @@ export class PhysicsHelper {
 
 
 /**
 /**
  * Represents a physics radial explosion event
  * Represents a physics radial explosion event
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
  */
  */
-export class PhysicsRadialExplosionEvent {
+class PhysicsRadialExplosionEvent {
 
 
-    private _scene: Scene;
     private _sphere: Mesh; // create a sphere, so we can get the intersecting meshes inside
     private _sphere: Mesh; // create a sphere, so we can get the intersecting meshes inside
-    private _sphereOptions: { segments: number, diameter: number } = { segments: 32, diameter: 1 }; // TODO: make configurable
-    private _rays: Array<Ray> = [];
     private _dataFetched: boolean = false; // check if the data has been fetched. If not, do cleanup
     private _dataFetched: boolean = false; // check if the data has been fetched. If not, do cleanup
 
 
     /**
     /**
      * Initializes a radial explosioin event
      * Initializes a radial explosioin event
-     * @param scene BabylonJS scene
+     * @param _physicsHelper A physics helper
+     * @param _scene BabylonJS scene
+     * @param _options The options for the vortex event
      */
      */
-    constructor(scene: Scene) {
-        this._scene = scene;
+    constructor(private _physicsHelper: PhysicsHelper, private _scene: Scene, private _options: PhysicsRadialExplosionEventOptions) {
+        this._options = {...(new PhysicsRadialExplosionEventOptions()), ...this._options};
     }
     }
 
 
     /**
     /**
-     * Returns the data related to the radial explosion event (sphere & rays).
+     * Returns the data related to the radial explosion event (sphere).
      * @returns The radial explosion event data
      * @returns The radial explosion event data
      */
      */
     public getData(): PhysicsRadialExplosionEventData {
     public getData(): PhysicsRadialExplosionEventData {
@@ -211,7 +246,6 @@ export class PhysicsRadialExplosionEvent {
 
 
         return {
         return {
             sphere: this._sphere,
             sphere: this._sphere,
-            rays: this._rays,
         };
         };
     }
     }
 
 
@@ -219,17 +253,14 @@ export class PhysicsRadialExplosionEvent {
      * Returns the force and contact point of the impostor or false, if the impostor is not affected by the force/impulse.
      * Returns the force and contact point of the impostor or false, if the impostor is not affected by the force/impulse.
      * @param impostor A physics imposter
      * @param impostor A physics imposter
      * @param origin the origin of the explosion
      * @param origin the origin of the explosion
-     * @param radius the explosion radius
-     * @param strength the explosion strength
-     * @param falloff possible options: Constant & Linear
      * @returns {Nullable<PhysicsForceAndContactPoint>} A physics force and contact point, or null
      * @returns {Nullable<PhysicsForceAndContactPoint>} A physics force and contact point, or null
      */
      */
-    public getImpostorForceAndContactPoint(impostor: PhysicsImpostor, origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFalloff): Nullable<PhysicsForceAndContactPoint> {
+    public getImpostorForceAndContactPoint(impostor: PhysicsImpostor, origin: Vector3): Nullable<PhysicsForceAndContactPoint> {
         if (impostor.mass === 0) {
         if (impostor.mass === 0) {
             return null;
             return null;
         }
         }
 
 
-        if (!this._intersectsWithSphere(impostor, origin, radius)) {
+        if (!this._intersectsWithSphere(impostor, origin, this._options.radius)) {
             return null;
             return null;
         }
         }
 
 
@@ -240,8 +271,7 @@ export class PhysicsRadialExplosionEvent {
         var impostorObjectCenter = impostor.getObjectCenter();
         var impostorObjectCenter = impostor.getObjectCenter();
         var direction = impostorObjectCenter.subtract(origin);
         var direction = impostorObjectCenter.subtract(origin);
 
 
-        var ray = new Ray(origin, direction, radius);
-        this._rays.push(ray);
+        var ray = new Ray(origin, direction, this._options.radius);
         var hit = ray.intersectsMesh(<AbstractMesh>impostor.object);
         var hit = ray.intersectsMesh(<AbstractMesh>impostor.object);
 
 
         var contactPoint = hit.pickedPoint;
         var contactPoint = hit.pickedPoint;
@@ -250,13 +280,14 @@ export class PhysicsRadialExplosionEvent {
         }
         }
 
 
         var distanceFromOrigin = Vector3.Distance(origin, contactPoint);
         var distanceFromOrigin = Vector3.Distance(origin, contactPoint);
-        if (distanceFromOrigin > radius) {
+
+        if (distanceFromOrigin > this._options.radius) {
             return null;
             return null;
         }
         }
 
 
-        var multiplier = falloff === PhysicsRadialImpulseFalloff.Constant
-            ? strength
-            : strength * (1 - (distanceFromOrigin / radius));
+        var multiplier = this._options.falloff === PhysicsRadialImpulseFalloff.Constant
+            ? this._options.strength
+            : this._options.strength * (1 - (distanceFromOrigin / this._options.radius));
 
 
         var force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
         var force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
 
 
@@ -283,7 +314,7 @@ export class PhysicsRadialExplosionEvent {
 
 
     private _prepareSphere(): void {
     private _prepareSphere(): void {
         if (!this._sphere) {
         if (!this._sphere) {
-            this._sphere = SphereBuilder.CreateSphere("radialExplosionEventSphere", this._sphereOptions, this._scene);
+            this._sphere = SphereBuilder.CreateSphere("radialExplosionEventSphere", this._options.sphere, this._scene);
             this._sphere.isVisible = false;
             this._sphere.isVisible = false;
         }
         }
     }
     }
@@ -305,37 +336,26 @@ export class PhysicsRadialExplosionEvent {
 
 
 /**
 /**
  * Represents a gravitational field event
  * Represents a gravitational field event
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
  */
  */
-export class PhysicsGravitationalFieldEvent {
+class PhysicsGravitationalFieldEvent {
 
 
-    private _physicsHelper: PhysicsHelper;
-    private _scene: Scene;
-    private _origin: Vector3;
-    private _radius: number;
-    private _strength: number;
-    private _falloff: PhysicsRadialImpulseFalloff;
     private _tickCallback: any;
     private _tickCallback: any;
     private _sphere: Mesh;
     private _sphere: Mesh;
     private _dataFetched: boolean = false; // check if the has been fetched the data. If not, do cleanup
     private _dataFetched: boolean = false; // check if the has been fetched the data. If not, do cleanup
 
 
     /**
     /**
      * Initializes the physics gravitational field event
      * Initializes the physics gravitational field event
-     * @param physicsHelper A physics helper
-     * @param scene BabylonJS scene
-     * @param origin The origin position of the gravitational field event
-     * @param radius The radius of the gravitational field event
-     * @param strength The strength of the gravitational field event
-     * @param falloff The falloff for the gravitational field event
-     */
-    constructor(physicsHelper: PhysicsHelper, scene: Scene, origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFalloff = PhysicsRadialImpulseFalloff.Constant) {
-        this._physicsHelper = physicsHelper;
-        this._scene = scene;
-        this._origin = origin;
-        this._radius = radius;
-        this._strength = strength;
-        this._falloff = falloff;
+     * @param _physicsHelper A physics helper
+     * @param _scene BabylonJS scene
+     * @param _origin The origin position of the gravitational field event
+     * @param _options The options for the vortex event
+     */
+    constructor(private _physicsHelper: PhysicsHelper, private _scene: Scene, private _origin: Vector3, private _options: PhysicsRadialExplosionEventOptions) {
+        this._options = {...(new PhysicsRadialExplosionEventOptions()), ...this._options};
+
         this._tickCallback = this._tick.bind(this);
         this._tickCallback = this._tick.bind(this);
+
+        this._options.strength = this._options.strength * -1;
     }
     }
 
 
     /**
     /**
@@ -384,9 +404,9 @@ export class PhysicsGravitationalFieldEvent {
     private _tick() {
     private _tick() {
         // Since the params won't change, we fetch the event only once
         // Since the params won't change, we fetch the event only once
         if (this._sphere) {
         if (this._sphere) {
-            this._physicsHelper.applyRadialExplosionForce(this._origin, this._radius, this._strength * -1, this._falloff);
+            this._physicsHelper.applyRadialExplosionForce(this._origin, this._options);
         } else {
         } else {
-            var radialExplosionEvent = this._physicsHelper.applyRadialExplosionForce(this._origin, this._radius, this._strength * -1, this._falloff);
+            var radialExplosionEvent = this._physicsHelper.applyRadialExplosionForce(this._origin, this._options);
             if (radialExplosionEvent) {
             if (radialExplosionEvent) {
                 this._sphere = <Mesh>radialExplosionEvent.getData().sphere.clone('radialExplosionEventSphereClone');
                 this._sphere = <Mesh>radialExplosionEvent.getData().sphere.clone('radialExplosionEventSphereClone');
             }
             }
@@ -397,9 +417,8 @@ export class PhysicsGravitationalFieldEvent {
 
 
 /**
 /**
  * Represents a physics updraft event
  * Represents a physics updraft event
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
  */
  */
-export class PhysicsUpdraftEvent {
+class PhysicsUpdraftEvent {
 
 
     private _physicsEngine: PhysicsEngine;
     private _physicsEngine: PhysicsEngine;
     private _originTop: Vector3 = Vector3.Zero(); // the most upper part of the cylinder
     private _originTop: Vector3 = Vector3.Zero(); // the most upper part of the cylinder
@@ -411,20 +430,19 @@ export class PhysicsUpdraftEvent {
 
 
     /**
     /**
      * Initializes the physics updraft event
      * Initializes the physics updraft event
+     * @param _physicsHelper A physics helper
      * @param _scene BabylonJS scene
      * @param _scene BabylonJS scene
      * @param _origin The origin position of the updraft
      * @param _origin The origin position of the updraft
-     * @param _radius The radius of the updraft
-     * @param _strength The strength of the updraft
-     * @param _height The height of the updraft
-     * @param _updraftMode The mode of the updraft
+     * @param _options The options for the updraft event
      */
      */
-    constructor(private _scene: Scene, private _origin: Vector3, private _radius: number, private _strength: number, private _height: number, private _updraftMode: PhysicsUpdraftMode) {
+    constructor(private _physicsHelper: PhysicsHelper, private _scene: Scene, private _origin: Vector3, private _options: PhysicsUpdraftEventOptions) {
         this._physicsEngine = <PhysicsEngine>this._scene.getPhysicsEngine();
         this._physicsEngine = <PhysicsEngine>this._scene.getPhysicsEngine();
+        this._options = {...(new PhysicsUpdraftEventOptions()), ...this._options};
 
 
-        this._origin.addToRef(new Vector3(0, this._height / 2, 0), this._cylinderPosition);
-        this._origin.addToRef(new Vector3(0, this._height, 0), this._originTop);
+        this._origin.addToRef(new Vector3(0, this._options.height / 2, 0), this._cylinderPosition);
+        this._origin.addToRef(new Vector3(0, this._options.height, 0), this._originTop);
 
 
-        if (this._updraftMode === PhysicsUpdraftMode.Perpendicular) {
+        if (this._options.updraftMode === PhysicsUpdraftMode.Perpendicular) {
             this._originDirection = this._origin.subtract(this._originTop).normalize();
             this._originDirection = this._origin.subtract(this._originTop).normalize();
         }
         }
 
 
@@ -454,14 +472,14 @@ export class PhysicsUpdraftEvent {
     }
     }
 
 
     /**
     /**
-     * Disables the cortex.
+     * Disables the updraft.
      */
      */
     public disable() {
     public disable() {
         this._scene.unregisterBeforeRender(this._tickCallback);
         this._scene.unregisterBeforeRender(this._tickCallback);
     }
     }
 
 
     /**
     /**
-     * Disposes the sphere.
+     * Disposes the cylinder.
      * @param force Specifies if the updraft should be disposed by force
      * @param force Specifies if the updraft should be disposed by force
      */
      */
     public dispose(force: boolean = true) {
     public dispose(force: boolean = true) {
@@ -490,13 +508,13 @@ export class PhysicsUpdraftEvent {
 
 
         var impostorObjectCenter = impostor.getObjectCenter();
         var impostorObjectCenter = impostor.getObjectCenter();
 
 
-        if (this._updraftMode === PhysicsUpdraftMode.Perpendicular) {
+        if (this._options.updraftMode === PhysicsUpdraftMode.Perpendicular) {
             var direction = this._originDirection;
             var direction = this._originDirection;
         } else {
         } else {
             var direction = impostorObjectCenter.subtract(this._originTop);
             var direction = impostorObjectCenter.subtract(this._originTop);
         }
         }
 
 
-        var multiplier = this._strength * -1;
+        var multiplier = this._options.strength * -1;
 
 
         var force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
         var force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
 
 
@@ -519,8 +537,8 @@ export class PhysicsUpdraftEvent {
     private _prepareCylinder(): void {
     private _prepareCylinder(): void {
         if (!this._cylinder) {
         if (!this._cylinder) {
             this._cylinder = CylinderBuilder.CreateCylinder("updraftEventCylinder", {
             this._cylinder = CylinderBuilder.CreateCylinder("updraftEventCylinder", {
-                height: this._height,
-                diameter: this._radius * 2,
+                height: this._options.height,
+                diameter: this._options.radius * 2,
             }, this._scene);
             }, this._scene);
             this._cylinder.isVisible = false;
             this._cylinder.isVisible = false;
         }
         }
@@ -538,14 +556,11 @@ export class PhysicsUpdraftEvent {
 
 
 /**
 /**
  * Represents a physics vortex event
  * Represents a physics vortex event
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
  */
  */
-export class PhysicsVortexEvent {
+class PhysicsVortexEvent {
 
 
     private _physicsEngine: PhysicsEngine;
     private _physicsEngine: PhysicsEngine;
     private _originTop: Vector3 = Vector3.Zero(); // the most upper part of the cylinder
     private _originTop: Vector3 = Vector3.Zero(); // the most upper part of the cylinder
-    private _centripetalForceThreshold: number = 0.7; // at which distance, relative to the radius the centripetal forces should kick in
-    private _updraftMultiplier: number = 0.02;
     private _tickCallback: any;
     private _tickCallback: any;
     private _cylinder: Mesh;
     private _cylinder: Mesh;
     private _cylinderPosition: Vector3 = Vector3.Zero(); // to keep the cylinders position, because normally the origin is in the center and not on the bottom
     private _cylinderPosition: Vector3 = Vector3.Zero(); // to keep the cylinders position, because normally the origin is in the center and not on the bottom
@@ -553,17 +568,17 @@ export class PhysicsVortexEvent {
 
 
     /**
     /**
      * Initializes the physics vortex event
      * Initializes the physics vortex event
+     * @param _physicsHelper A physics helper
      * @param _scene The BabylonJS scene
      * @param _scene The BabylonJS scene
      * @param _origin The origin position of the vortex
      * @param _origin The origin position of the vortex
-     * @param _radius The radius of the vortex
-     * @param _strength The strength of the vortex
-     * @param _height The height of the vortex
+     * @param _options The options for the vortex event
      */
      */
-    constructor(private _scene: Scene, private _origin: Vector3, private _radius: number, private _strength: number, private _height: number) {
+    constructor(private _physicsHelper: PhysicsHelper, private _scene: Scene, private _origin: Vector3, private _options: PhysicsVortexEventOptions) {
         this._physicsEngine = <PhysicsEngine>this._scene.getPhysicsEngine();
         this._physicsEngine = <PhysicsEngine>this._scene.getPhysicsEngine();
+        this._options = {...(new PhysicsVortexEventOptions()), ...this._options};
 
 
-        this._origin.addToRef(new Vector3(0, this._height / 2, 0), this._cylinderPosition);
-        this._origin.addToRef(new Vector3(0, this._height, 0), this._originTop);
+        this._origin.addToRef(new Vector3(0, this._options.height / 2, 0), this._cylinderPosition);
+        this._origin.addToRef(new Vector3(0, this._options.height, 0), this._originTop);
 
 
         this._tickCallback = this._tick.bind(this);
         this._tickCallback = this._tick.bind(this);
 
 
@@ -630,33 +645,33 @@ export class PhysicsVortexEvent {
         var originOnPlane = new Vector3(this._origin.x, impostorObjectCenter.y, this._origin.z); // the distance to the origin as if both objects were on a plane (Y-axis)
         var originOnPlane = new Vector3(this._origin.x, impostorObjectCenter.y, this._origin.z); // the distance to the origin as if both objects were on a plane (Y-axis)
         var originToImpostorDirection = impostorObjectCenter.subtract(originOnPlane);
         var originToImpostorDirection = impostorObjectCenter.subtract(originOnPlane);
 
 
-        var ray = new Ray(originOnPlane, originToImpostorDirection, this._radius);
+        var ray = new Ray(originOnPlane, originToImpostorDirection, this._options.radius);
         var hit = ray.intersectsMesh(<AbstractMesh>impostor.object);
         var hit = ray.intersectsMesh(<AbstractMesh>impostor.object);
         var contactPoint = hit.pickedPoint;
         var contactPoint = hit.pickedPoint;
         if (!contactPoint) {
         if (!contactPoint) {
             return null;
             return null;
         }
         }
+        var absoluteDistanceFromOrigin = hit.distance / this._options.radius;
 
 
-        var absoluteDistanceFromOrigin = hit.distance / this._radius;
-        var perpendicularDirection = Vector3.Cross(originOnPlane, impostorObjectCenter).normalize();
         var directionToOrigin = contactPoint.normalize();
         var directionToOrigin = contactPoint.normalize();
-        if (absoluteDistanceFromOrigin > this._centripetalForceThreshold) {
+        if (absoluteDistanceFromOrigin > this._options.centripetalForceThreshold) {
             directionToOrigin = directionToOrigin.negate();
             directionToOrigin = directionToOrigin.negate();
         }
         }
 
 
-        // TODO: find a more physically based solution
-        if (absoluteDistanceFromOrigin > this._centripetalForceThreshold) {
-            var forceX = directionToOrigin.x * this._strength / 8;
-            var forceY = directionToOrigin.y * this._updraftMultiplier;
-            var forceZ = directionToOrigin.z * this._strength / 8;
+        if (absoluteDistanceFromOrigin > this._options.centripetalForceThreshold) {
+            var forceX = directionToOrigin.x * this._options.centripetalForceMultiplier;
+            var forceY = directionToOrigin.y * this._options.updraftForceMultiplier;
+            var forceZ = directionToOrigin.z * this._options.centripetalForceMultiplier;
         } else {
         } else {
-            var forceX = (perpendicularDirection.x + directionToOrigin.x) / 2;
-            var forceY = this._originTop.y * this._updraftMultiplier;
-            var forceZ = (perpendicularDirection.z + directionToOrigin.z) / 2;
+            var perpendicularDirection = Vector3.Cross(originOnPlane, impostorObjectCenter).normalize();
+
+            var forceX = (perpendicularDirection.x + directionToOrigin.x) * this._options.centrifugalForceMultiplier;
+            var forceY = this._originTop.y * this._options.updraftForceMultiplier;
+            var forceZ = (perpendicularDirection.z + directionToOrigin.z) * this._options.centrifugalForceMultiplier;
         }
         }
 
 
         var force = new Vector3(forceX, forceY, forceZ);
         var force = new Vector3(forceX, forceY, forceZ);
-        force = force.multiplyByFloats(this._strength, this._strength, this._strength);
+        force = force.multiplyByFloats(this._options.strength, this._options.strength, this._options.strength);
 
 
         return { force: force, contactPoint: impostorObjectCenter };
         return { force: force, contactPoint: impostorObjectCenter };
     }
     }
@@ -677,8 +692,8 @@ export class PhysicsVortexEvent {
     private _prepareCylinder(): void {
     private _prepareCylinder(): void {
         if (!this._cylinder) {
         if (!this._cylinder) {
             this._cylinder = CylinderBuilder.CreateCylinder("vortexEventCylinder", {
             this._cylinder = CylinderBuilder.CreateCylinder("vortexEventCylinder", {
-                height: this._height,
-                diameter: this._radius * 2,
+                height: this._options.height,
+                diameter: this._options.radius * 2,
             }, this._scene);
             }, this._scene);
             this._cylinder.isVisible = false;
             this._cylinder.isVisible = false;
         }
         }
@@ -695,19 +710,112 @@ export class PhysicsVortexEvent {
 }
 }
 
 
 /**
 /**
+ * Options fot the radial explosion event
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
+ */
+export class PhysicsRadialExplosionEventOptions {
+    /**
+     * The radius of the sphere for the radial explosion.
+     */
+    radius: number = 5;
+
+    /**
+     * The strenth of the explosion.
+     */
+    strength: number = 10;
+
+    /**
+     * The strenght of the force in correspondence to the distance of the affected object
+     */
+    falloff: PhysicsRadialImpulseFalloff = PhysicsRadialImpulseFalloff.Constant;
+
+    /**
+     * Sphere options for the radial explosion.
+     */
+    sphere: { segments: number, diameter: number } = { segments: 32, diameter: 1 };
+}
+
+/**
+ * Options fot the updraft event
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
+ */
+export class PhysicsUpdraftEventOptions {
+    /**
+     * The radius of the cylinder for the vortex
+     */
+    radius: number = 5;
+
+    /**
+     * The strenth of the updraft.
+     */
+    strength: number = 10;
+
+    /**
+     * The height of the cylinder for the updraft.
+     */
+    height: number = 10;
+
+    /**
+     * The mode for the the updraft.
+     */
+    updraftMode: PhysicsUpdraftMode = PhysicsUpdraftMode.Center;
+}
+
+/**
+ * Options fot the vortex event
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
+ */
+export class PhysicsVortexEventOptions {
+    /**
+     * The radius of the cylinder for the vortex
+     */
+    radius: number = 5;
+
+    /**
+     * The strenth of the vortex.
+     */
+    strength: number = 10;
+
+    /**
+     * The height of the cylinder for the vortex.
+     */
+    height: number = 10;
+
+    /**
+     * At which distance, relative to the radius the centripetal forces should kick in? Range: 0-1
+     */
+    centripetalForceThreshold: number = 0.7;
+
+    /**
+     * This multiplier determines with how much force the objects will be pushed sideways/around the vortex, when below the treshold.
+     */
+    centripetalForceMultiplier: number = 5;
+
+    /**
+     * This multiplier determines with how much force the objects will be pushed sideways/around the vortex, when above the treshold.
+     */
+    centrifugalForceMultiplier: number = 0.5;
+
+    /**
+     * This multiplier determines with how much force the objects will be pushed upwards, when in the vortex.
+     */
+    updraftForceMultiplier: number = 0.02;
+}
+
+/**
 * The strenght of the force in correspondence to the distance of the affected object
 * The strenght of the force in correspondence to the distance of the affected object
-* @see https://doc.babylonjs.com/how_to/using_the_physics_engine
+* @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
 */
 */
 export enum PhysicsRadialImpulseFalloff {
 export enum PhysicsRadialImpulseFalloff {
     /** Defines that impulse is constant in strength across it's whole radius */
     /** Defines that impulse is constant in strength across it's whole radius */
     Constant,
     Constant,
-    /** DEfines that impulse gets weaker if it's further from the origin */
+    /** Defines that impulse gets weaker if it's further from the origin */
     Linear
     Linear
 }
 }
 
 
 /**
 /**
  * The strength of the force in correspondence to the distance of the affected object
  * The strength of the force in correspondence to the distance of the affected object
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
  */
  */
 export enum PhysicsUpdraftMode {
 export enum PhysicsUpdraftMode {
     /** Defines that the upstream forces will pull towards the top center of the cylinder */
     /** Defines that the upstream forces will pull towards the top center of the cylinder */
@@ -718,7 +826,7 @@ export enum PhysicsUpdraftMode {
 
 
 /**
 /**
  * Interface for a physics force and contact point
  * Interface for a physics force and contact point
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
  */
  */
 export interface PhysicsForceAndContactPoint {
 export interface PhysicsForceAndContactPoint {
     /**
     /**
@@ -733,22 +841,18 @@ export interface PhysicsForceAndContactPoint {
 
 
 /**
 /**
  * Interface for radial explosion event data
  * Interface for radial explosion event data
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
  */
  */
 export interface PhysicsRadialExplosionEventData {
 export interface PhysicsRadialExplosionEventData {
     /**
     /**
      * A sphere used for the radial explosion event
      * A sphere used for the radial explosion event
      */
      */
     sphere: Mesh;
     sphere: Mesh;
-    /**
-     * An array of rays for the radial explosion event
-     */
-    rays: Array<Ray>;
 }
 }
 
 
 /**
 /**
  * Interface for gravitational field event data
  * Interface for gravitational field event data
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
  */
  */
 export interface PhysicsGravitationalFieldEventData {
 export interface PhysicsGravitationalFieldEventData {
     /**
     /**
@@ -759,7 +863,7 @@ export interface PhysicsGravitationalFieldEventData {
 
 
 /**
 /**
  * Interface for updraft event data
  * Interface for updraft event data
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
  */
  */
 export interface PhysicsUpdraftEventData {
 export interface PhysicsUpdraftEventData {
     /**
     /**
@@ -770,7 +874,7 @@ export interface PhysicsUpdraftEventData {
 
 
 /**
 /**
  * Interface for vortex event data
  * Interface for vortex event data
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
  */
  */
 export interface PhysicsVortexEventData {
 export interface PhysicsVortexEventData {
     /**
     /**

+ 121 - 0
src/Physics/physicsRaycastResult.ts

@@ -0,0 +1,121 @@
+import { Vector3 } from "../Maths/math";
+
+/**
+ * Holds the data for the raycast result
+ * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
+ */
+export class PhysicsRaycastResult {
+
+    private _hasHit: boolean = false;
+
+    private _hitDistance: number = 0;
+    private _hitNormalWorld: Vector3 = Vector3.Zero();
+    private _hitPointWorld: Vector3 = Vector3.Zero();
+    private _rayFromWorld: Vector3 = Vector3.Zero();
+    private _rayToWorld: Vector3 = Vector3.Zero();
+
+    /**
+     * Gets if there was a hit
+     */
+    get hasHit(): boolean {
+        return this._hasHit;
+    }
+
+    /**
+     * Gets the distance from the hit
+     */
+    get hitDistance(): number {
+        return this._hitDistance;
+    }
+
+    /**
+     * Gets the hit normal/direction in the world
+     */
+    get hitNormalWorld(): Vector3 {
+        return this._hitNormalWorld;
+    }
+
+    /**
+     * Gets the hit point in the world
+     */
+    get hitPointWorld(): Vector3 {
+        return this._hitPointWorld;
+    }
+
+    /**
+     * Gets the ray "start point" of the ray in the world
+     */
+    get rayFromWorld(): Vector3 {
+        return this._rayFromWorld;
+    }
+
+    /**
+     * Gets the ray "end point" of the ray in the world
+     */
+    get rayToWorld(): Vector3 {
+        return this._rayToWorld;
+    }
+
+    /**
+     * Sets the hit data (normal & point in world space)
+     * @param hitNormalWorld
+     * @param hitPointWorld
+     */
+    public setHitData(hitNormalWorld: IXYZ, hitPointWorld: IXYZ) {
+        this._hasHit = true;
+        this._hitNormalWorld = new Vector3(hitNormalWorld.x, hitNormalWorld.y, hitNormalWorld.z);
+        this._hitPointWorld = new Vector3(hitPointWorld.x, hitPointWorld.y, hitPointWorld.z);
+    }
+
+    /**
+     * Sets the distance from the start point to the hit point
+     * @param distance
+     */
+    public setHitDistance(distance: number) {
+        this._hitDistance = distance;
+    }
+
+    /**
+     * Calculates the distance manually
+     */
+    public calculateHitDistance() {
+        this._hitDistance = Vector3.Distance(this._rayFromWorld, this._hitPointWorld);
+    }
+
+    /**
+     * Resets all the values to default
+     * @param from The from point on world space
+     * @param to The to point on world space
+     */
+    public reset(from: Vector3 = Vector3.Zero(), to: Vector3 = Vector3.Zero()) {
+        this._rayFromWorld = from;
+        this._rayToWorld = to;
+
+        this._hasHit = false;
+        this._hitDistance = 0;
+
+        this._hitNormalWorld = Vector3.Zero();
+        this._hitPointWorld = Vector3.Zero();
+    }
+
+}
+
+/**
+ * Interface for the size containing width and height
+ */
+interface IXYZ {
+    /**
+     * X
+     */
+    x: number;
+
+    /**
+     * Y
+     */
+    y: number;
+
+    /**
+     * Z
+     */
+    z: number;
+}