123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- module BABYLON {
-
- /**
- * The strenght of the force in correspondence to the distance of the affected object
- */
- export enum PhysicsRadialImpulseFallof {
- Constant, // impulse is constant in strength across it's whole radius
- Linear // impulse gets weaker if it's further from the origin
- }
-
- export class PhysicsHelper {
-
- private _scene: Scene;
- private _physicsEngine: Nullable<PhysicsEngine>;
- constructor(scene: Scene) {
- this._scene = scene;
- this._physicsEngine = this._scene.getPhysicsEngine();
-
- if (!this._physicsEngine) {
- Tools.Warn('Physics engine not enabled. Please enable the physics before you can use the methods.');
- }
- }
-
- /**
- * @param {Vector3} origin the origin of the explosion
- * @param {number} radius the explosion radius
- * @param {number} strength the explosion strength
- * @param {PhysicsRadialImpulseFallof} falloff possible options: Constant & Linear. Defaults to Constant
- */
- public applyRadialExplosionImpulse(origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFallof = PhysicsRadialImpulseFallof.Constant) {
- if (!this._physicsEngine) {
- Tools.Warn('Physics engine not enabled. Please enable the physics before you call this method.');
- return null;
- }
-
- var impostors = this._physicsEngine.getImpostors();
- if (impostors.length === 0) {
- return null;
- }
- var event = new PhysicsRadialExplosionEvent(this._scene);
- for (var i = 0; i < impostors.length; ++i) {
- var impostor = impostors[i];
- var impostorForceAndContactPoint = event.getImpostorForceAndContactPoint(
- impostor,
- origin,
- radius,
- strength,
- falloff
- );
- if (impostorForceAndContactPoint === null) {
- continue;
- }
- impostor.applyImpulse(
- impostorForceAndContactPoint.force,
- impostorForceAndContactPoint.contactPoint
- );
- }
- event.cleanup(false);
- return event;
- }
- /**
- * @param {Vector3} origin the origin of the explosion
- * @param {number} radius the explosion radius
- * @param {number} strength the explosion strength
- * @param {PhysicsRadialImpulseFallof} falloff possible options: Constant & Linear. Defaults to Constant
- */
- public applyRadialExplosionForce(origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFallof = PhysicsRadialImpulseFallof.Constant) {
- if (!this._physicsEngine) {
- Tools.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
- return null;
- }
-
- var impostors = this._physicsEngine.getImpostors();
- if (impostors.length === 0) {
- return null;
- }
- var event = new PhysicsRadialExplosionEvent(this._scene);
- for (var i = 0; i < impostors.length; ++i) {
- var impostor = impostors[i];
- var impostorForceAndContactPoint = event.getImpostorForceAndContactPoint(
- impostor,
- origin,
- radius,
- strength,
- falloff
- );
- if (impostorForceAndContactPoint === null) {
- continue;
- }
- impostor.applyForce(
- impostorForceAndContactPoint.force,
- impostorForceAndContactPoint.contactPoint
- );
- }
- event.cleanup(false);
- return event;
- }
- /**
- * @param {Vector3} origin the origin of the explosion
- * @param {number} radius the explosion radius
- * @param {number} strength the explosion strength
- * @param {PhysicsRadialImpulseFallof} falloff possible options: Constant & Linear. Defaults to Constant
- */
- public gravitationalField(origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFallof = PhysicsRadialImpulseFallof.Constant) {
- if (!this._physicsEngine) {
- Tools.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
- return null;
- }
- var impostors = this._physicsEngine.getImpostors();
- if (impostors.length === 0) {
- return null;
- }
- var event = new PhysicsGravitationalFieldEvent(
- this,
- this._scene,
- origin,
- radius,
- strength,
- falloff
- );
- event.cleanup(false);
- return event;
- }
- }
- /***** Radial explosion *****/
- export class PhysicsRadialExplosionEvent {
-
- private _scene: Scene;
- private _radialSphere: Mesh; // create a sphere, so we can get the intersecting meshes inside
- private _rays: Array<Ray> = [];
- private _dataFetched: boolean = false; // check if the data has been fetched. If not, do cleanup
- constructor(scene: Scene) {
- this._scene = scene;
- }
- /**
- * Returns the data related to the radial explosion event (radialSphere & rays).
- * @returns {PhysicsRadialExplosionEventData}
- */
- public getData(): PhysicsRadialExplosionEventData {
- this._dataFetched = true;
- return {
- radialSphere: this._radialSphere,
- rays: this._rays,
- };
- }
- /**
- * Returns the force and contact point of the impostor or false, if the impostor is not affected by the force/impulse.
- * @param impostor
- * @param {Vector3} origin the origin of the explosion
- * @param {number} radius the explosion radius
- * @param {number} strength the explosion strength
- * @param {PhysicsRadialImpulseFallof} falloff possible options: Constant & Linear
- * @returns {Nullable<PhysicsForceAndContactPoint>}
- */
- public getImpostorForceAndContactPoint(impostor: PhysicsImpostor, origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFallof): Nullable<PhysicsForceAndContactPoint> {
- if (impostor.mass === 0) {
- return null;
- }
- if (!this._intersectsWithRadialSphere(impostor, origin, radius)) {
- return null;
- }
- var impostorObject = (<Mesh>impostor.object);
- var impostorObjectCenter = impostor.getObjectCenter();
- var direction = impostorObjectCenter.subtract(origin);
- var ray = new Ray(origin, direction, radius);
- this._rays.push(ray);
- var hit = ray.intersectsMesh(impostorObject);
- var contactPoint = hit.pickedPoint;
- if (!contactPoint) {
- return null;
- }
- var distanceFromOrigin = BABYLON.Vector3.Distance(origin, contactPoint);
- if (distanceFromOrigin > radius) {
- return null;
- }
- var multiplier = falloff === PhysicsRadialImpulseFallof.Constant
- ? strength
- : strength * (1 - (distanceFromOrigin / radius));
- var force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
- return { force: force, contactPoint: contactPoint };
- }
- /**
- * Disposes the radialSphere.
- * @param {bolean} force
- */
- public cleanup(force: boolean = true) {
- if (force) {
- this._radialSphere.dispose();
- } else {
- setTimeout(() => {
- if (!this._dataFetched) {
- this._radialSphere.dispose();
- }
- }, 0);
- }
- }
- /*** Helpers ***/
- private _prepareRadialSphere() {
- if (!this._radialSphere) {
- this._radialSphere = BABYLON.Mesh.CreateSphere(
- "radialSphere",
- 32,
- 1,
- this._scene
- );
- this._radialSphere.isVisible = false;
- }
- }
- private _intersectsWithRadialSphere(impostor: PhysicsImpostor, origin: Vector3, radius: number): boolean {
- var impostorObject = <Mesh>impostor.object;
- this._prepareRadialSphere();
- this._radialSphere.position = origin;
- this._radialSphere.scaling = new Vector3(radius * 2, radius * 2, radius * 2);
- this._radialSphere._updateBoundingInfo();
- this._radialSphere.computeWorldMatrix(true);
- return this._radialSphere.intersectsMesh(
- impostorObject,
- true
- );
- }
- }
- export interface PhysicsRadialExplosionEventData {
- radialSphere: Mesh;
- rays: Array<Ray>;
- }
- export interface PhysicsForceAndContactPoint {
- force: Vector3;
- contactPoint: Vector3;
- }
- /***** Gravitational Field *****/
- export class PhysicsGravitationalFieldEvent {
- private _physicsHelper: PhysicsHelper;
- private _scene: Scene;
- private _origin: Vector3;
- private _radius: number;
- private _strength: number;
- private _falloff: PhysicsRadialImpulseFallof;
- private _tickCallback: any;
- private _radialSphere: Mesh;
- private _dataFetched: boolean = false; // check if the has been fetched the data. If not, do cleanup
- constructor(
- physicsHelper: PhysicsHelper,
- scene: Scene,
- origin: Vector3,
- radius: number,
- strength: number,
- falloff: PhysicsRadialImpulseFallof = PhysicsRadialImpulseFallof.Constant
- ) {
- this._physicsHelper = physicsHelper;
- this._scene = scene;
- this._origin = origin;
- this._radius = radius;
- this._strength = strength;
- this._falloff = falloff;
- this._tickCallback = this._tick.bind(this);
- }
- /**
- * Returns the data related to the gravitational field event (radialSphere).
- * @returns {PhysicsGravitationalFieldEventData}
- */
- public getData(): PhysicsGravitationalFieldEventData {
- this._dataFetched = true;
- return {
- radialSphere: this._radialSphere,
- };
- }
- /**
- * Enables the gravitational field.
- */
- public enable() {
- this._tickCallback.call(this);
- this._scene.registerBeforeRender(this._tickCallback);
- }
- /**
- * Disables the gravitational field.
- */
- public disable() {
- this._scene.unregisterBeforeRender(this._tickCallback);
- }
- /**
- * Disposes the radialSphere.
- * @param {bolean} force
- */
- public cleanup(force: boolean = true) {
- if (force) {
- this._radialSphere.dispose();
- } else {
- setTimeout(() => {
- if (!this._dataFetched) {
- this._radialSphere.dispose();
- }
- }, 0);
- }
- }
- private _tick() {
- // Since the params won't change, we fetch the event only once
- if (this._radialSphere) {
- this._physicsHelper.applyRadialExplosionForce(
- this._origin,
- this._radius,
- this._strength * -1,
- this._falloff
- );
- } else {
- var radialExplosionEvent = <PhysicsRadialExplosionEvent>this._physicsHelper.applyRadialExplosionForce(
- this._origin,
- this._radius,
- this._strength * -1,
- this._falloff
- );
- this._radialSphere = <Mesh>radialExplosionEvent.getData().radialSphere.clone('radialSphereClone');
- }
- }
- }
- export interface PhysicsGravitationalFieldEventData {
- radialSphere: Mesh;
- }
- }
|