|
@@ -8,6 +8,9 @@ import { VertexData } from "../../Meshes/mesh.vertexData";
|
|
import { Nullable } from "../../types";
|
|
import { Nullable } from "../../types";
|
|
import { AbstractMesh } from "../../Meshes/abstractMesh";
|
|
import { AbstractMesh } from "../../Meshes/abstractMesh";
|
|
import { Mesh } from "../../Meshes/mesh";
|
|
import { Mesh } from "../../Meshes/mesh";
|
|
|
|
+import { ShapeBuilder } from "../../Meshes/Builders/shapeBuilder";
|
|
|
|
+import { LinesBuilder } from "../../Meshes/Builders/linesBuilder";
|
|
|
|
+import { LinesMesh } from '../../Meshes/linesMesh';
|
|
import { PhysicsRaycastResult } from "../physicsRaycastResult";
|
|
import { PhysicsRaycastResult } from "../physicsRaycastResult";
|
|
|
|
|
|
declare var Ammo: any;
|
|
declare var Ammo: any;
|
|
@@ -194,7 +197,7 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
|
|
for (var mainImpostor of impostors) {
|
|
for (var mainImpostor of impostors) {
|
|
// After physics update make babylon world objects match physics world objects
|
|
// After physics update make babylon world objects match physics world objects
|
|
if (mainImpostor.soft) {
|
|
if (mainImpostor.soft) {
|
|
- this.afterSoftStep(mainImpostor);
|
|
|
|
|
|
+ this._afterSoftStep(mainImpostor);
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
mainImpostor.afterStep();
|
|
mainImpostor.afterStep();
|
|
@@ -219,10 +222,53 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Update babylon mesh vertices vertices to match physics world object
|
|
|
|
|
|
+ * Update babylon mesh to match physics world object
|
|
* @param impostor imposter to match
|
|
* @param impostor imposter to match
|
|
*/
|
|
*/
|
|
- public afterSoftStep(impostor: PhysicsImpostor): void {
|
|
|
|
|
|
+ private _afterSoftStep(impostor: PhysicsImpostor): void {
|
|
|
|
+ if (impostor.type === PhysicsImpostor.RopeImpostor) {
|
|
|
|
+ this._ropeStep(impostor);
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ this._softbodyOrClothStep(impostor);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Update babylon mesh vertices vertices to match physics world softbody or cloth
|
|
|
|
+ * @param impostor imposter to match
|
|
|
|
+ */
|
|
|
|
+ private _ropeStep(impostor: PhysicsImpostor): void {
|
|
|
|
+ var bodyVertices = impostor.physicsBody.get_m_nodes();
|
|
|
|
+ var nbVertices = bodyVertices.size();
|
|
|
|
+ var node: any;
|
|
|
|
+ var nodePositions: any;
|
|
|
|
+ var x, y, z: number;
|
|
|
|
+ var path: Array<Vector3> = new Array();
|
|
|
|
+ for (var n = 0; n < nbVertices; n++) {
|
|
|
|
+ node = bodyVertices.at(n);
|
|
|
|
+ nodePositions = node.get_m_x();
|
|
|
|
+ x = nodePositions.x();
|
|
|
|
+ y = nodePositions.y();
|
|
|
|
+ z = nodePositions.z();
|
|
|
|
+ path.push(new Vector3(x, y, z));
|
|
|
|
+ }
|
|
|
|
+ var object = impostor.object;
|
|
|
|
+ var shape = impostor.getParam("shape");
|
|
|
|
+ if (impostor._isFromLine) {
|
|
|
|
+ impostor.object = LinesBuilder.CreateLines("lines", {points: path, instance: <LinesMesh>object});
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ impostor.object = ShapeBuilder.ExtrudeShape("ext", {shape: shape, path: path, instance: <Mesh>object});
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Update babylon mesh vertices vertices to match physics world softbody or cloth
|
|
|
|
+ * @param impostor imposter to match
|
|
|
|
+ */
|
|
|
|
+ private _softbodyOrClothStep(impostor: PhysicsImpostor): void {
|
|
var normalDirection = (impostor.type === PhysicsImpostor.ClothImpostor) ? 1 : -1;
|
|
var normalDirection = (impostor.type === PhysicsImpostor.ClothImpostor) ? 1 : -1;
|
|
var object = impostor.object;
|
|
var object = impostor.object;
|
|
var vertexPositions = object.getVerticesData(VertexBuffer.PositionKind);
|
|
var vertexPositions = object.getVerticesData(VertexBuffer.PositionKind);
|
|
@@ -628,7 +674,6 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
|
|
nodeNormals.setY(triNorms[3 * i + 1]);
|
|
nodeNormals.setY(triNorms[3 * i + 1]);
|
|
nodeNormals.setZ(triNorms[3 * i + 2]);
|
|
nodeNormals.setZ(triNorms[3 * i + 2]);
|
|
}
|
|
}
|
|
- softBody.get_m_cfg().set_collisions(0x11);
|
|
|
|
return softBody;
|
|
return softBody;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -674,12 +719,76 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
|
|
impostor.getParam("fixedPoints"),
|
|
impostor.getParam("fixedPoints"),
|
|
true
|
|
true
|
|
);
|
|
);
|
|
- clothBody.get_m_cfg().set_collisions(0x11);
|
|
|
|
return clothBody;
|
|
return clothBody;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Create rope for an impostor
|
|
|
|
+ * @param impostor to create the softbody for
|
|
|
|
+ */
|
|
|
|
+ private _createRope(impostor: PhysicsImpostor) {
|
|
|
|
+ var len: number;
|
|
|
|
+ var segments: number;
|
|
|
|
+ var vertex_data = this._softVertexData(impostor);
|
|
|
|
+ var vertexPositions = vertex_data.positions;
|
|
|
|
+ var vertexNormals = vertex_data.normals;
|
|
|
|
+
|
|
|
|
+ if (vertexPositions === null || vertexNormals === null) {
|
|
|
|
+ return new Ammo.btCompoundShape();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //force the mesh to be updatable
|
|
|
|
+ vertex_data.applyToMesh(<Mesh>impostor.object, true);
|
|
|
|
+
|
|
|
|
+ impostor._isFromLine = true;
|
|
|
|
+
|
|
|
|
+ // If in lines mesh all normals will be zero
|
|
|
|
+ var vertexSquared: Array<number> = <Array<number>>vertexNormals.map((x: number) => x * x);
|
|
|
|
+ var reducer = (accumulator: number, currentValue: number): number => accumulator + currentValue;
|
|
|
|
+ var reduced: number = vertexSquared.reduce(reducer);
|
|
|
|
+
|
|
|
|
+ if (reduced === 0) { // line mesh
|
|
|
|
+ len = vertexPositions.length;
|
|
|
|
+ segments = len / 3 - 1;
|
|
|
|
+ this._tmpAmmoVectorA.setValue(vertexPositions[0], vertexPositions[1], vertexPositions[2]);
|
|
|
|
+ this._tmpAmmoVectorB.setValue(vertexPositions[len - 3], vertexPositions[len - 2], vertexPositions[len - 1]);
|
|
|
|
+ }
|
|
|
|
+ else { //extruded mesh
|
|
|
|
+ impostor._isFromLine = false;
|
|
|
|
+ var pathVectors = impostor.getParam("path");
|
|
|
|
+ var shape = impostor.getParam("shape");
|
|
|
|
+ if (shape === null) {
|
|
|
|
+ Logger.Warn("No shape available for extruded mesh");
|
|
|
|
+ return new Ammo.btCompoundShape();
|
|
|
|
+ }
|
|
|
|
+ if ((vertexPositions!.length % (3 * pathVectors.length)) !== 0) {
|
|
|
|
+ Logger.Warn("Path does not match extrusion");
|
|
|
|
+ return new Ammo.btCompoundShape();
|
|
|
|
+ }
|
|
|
|
+ len = pathVectors.length;
|
|
|
|
+ segments = len - 1;
|
|
|
|
+ this._tmpAmmoVectorA.setValue(pathVectors[0].x, pathVectors[0].y, pathVectors[0].z);
|
|
|
|
+ this._tmpAmmoVectorB.setValue(pathVectors[len - 1].x, pathVectors[len - 1].y, pathVectors[len - 1].z);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ impostor.segments = segments;
|
|
|
|
+
|
|
|
|
+ var fixedPoints = impostor.getParam("fixedPoints");
|
|
|
|
+ fixedPoints = (fixedPoints > 3) ? 3 : fixedPoints;
|
|
|
|
+
|
|
|
|
+ var ropeBody = new Ammo.btSoftBodyHelpers().CreateRope(
|
|
|
|
+ this.world.getWorldInfo(),
|
|
|
|
+ this._tmpAmmoVectorA,
|
|
|
|
+ this._tmpAmmoVectorB,
|
|
|
|
+ segments - 1,
|
|
|
|
+ fixedPoints
|
|
|
|
+ );
|
|
|
|
+ ropeBody.get_m_cfg().set_collisions(0x11);
|
|
|
|
+ return ropeBody;
|
|
|
|
+ }
|
|
|
|
+
|
|
// adds all verticies (including child verticies) to the convex hull shape
|
|
// adds all verticies (including child verticies) to the convex hull shape
|
|
private _addHullVerts(btConvexHullShape: any, topLevelObject: IPhysicsEnabledObject, object: IPhysicsEnabledObject) {
|
|
private _addHullVerts(btConvexHullShape: any, topLevelObject: IPhysicsEnabledObject, object: IPhysicsEnabledObject) {
|
|
var triangleCount = 0;
|
|
var triangleCount = 0;
|
|
@@ -827,9 +936,13 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
|
|
returnValue = this._createSoftbody(impostor);
|
|
returnValue = this._createSoftbody(impostor);
|
|
break;
|
|
break;
|
|
case PhysicsImpostor.ClothImpostor:
|
|
case PhysicsImpostor.ClothImpostor:
|
|
- // Only usable with a mesh that has sufficient and shared vertices
|
|
|
|
|
|
+ // Only usable with a ground mesh that has sufficient and shared vertices
|
|
returnValue = this._createCloth(impostor);
|
|
returnValue = this._createCloth(impostor);
|
|
break;
|
|
break;
|
|
|
|
+ case PhysicsImpostor.RopeImpostor:
|
|
|
|
+ // Only usable with a line mesh or an extruded mesh that is updatable
|
|
|
|
+ returnValue = this._createRope(impostor);
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
Logger.Warn("The impostor type is not currently supported by the ammo plugin.");
|
|
Logger.Warn("The impostor type is not currently supported by the ammo plugin.");
|
|
break;
|
|
break;
|
|
@@ -1159,12 +1272,12 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Append an anchor to a soft object
|
|
|
|
- * @param impostor soft impostor to add anchor to
|
|
|
|
- * @param otherImpostor rigid impostor as the anchor
|
|
|
|
|
|
+ * Append an anchor to a cloth object
|
|
|
|
+ * @param impostor is the cloth impostor to add anchor to
|
|
|
|
+ * @param otherImpostor is the rigid impostor to anchor to
|
|
* @param width ratio across width from 0 to 1
|
|
* @param width ratio across width from 0 to 1
|
|
* @param height ratio up height from 0 to 1
|
|
* @param height ratio up height from 0 to 1
|
|
- * @param influence the elasticity between soft impostor and anchor from 0, very stretchy to 1, no strech
|
|
|
|
|
|
+ * @param influence the elasticity between cloth impostor and anchor from 0, very stretchy to 1, little strech
|
|
* @param noCollisionBetweenLinkedBodies when true collisions between soft impostor and anchor are ignored; default false
|
|
* @param noCollisionBetweenLinkedBodies when true collisions between soft impostor and anchor are ignored; default false
|
|
*/
|
|
*/
|
|
public appendAnchor(impostor: PhysicsImpostor, otherImpostor: PhysicsImpostor, width: number, height: number, influence: number = 1, noCollisionBetweenLinkedBodies: boolean = false) {
|
|
public appendAnchor(impostor: PhysicsImpostor, otherImpostor: PhysicsImpostor, width: number, height: number, influence: number = 1, noCollisionBetweenLinkedBodies: boolean = false) {
|
|
@@ -1177,6 +1290,19 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
|
|
+ * Append an hook to a rope object
|
|
|
|
+ * @param impostor is the rope impostor to add hook to
|
|
|
|
+ * @param otherImpostor is the rigid impostor to hook to
|
|
|
|
+ * @param length ratio along the rope from 0 to 1
|
|
|
|
+ * @param influence the elasticity between soft impostor and anchor from 0, very stretchy to 1, little strech
|
|
|
|
+ * @param noCollisionBetweenLinkedBodies when true collisions between soft impostor and anchor are ignored; default false
|
|
|
|
+ */
|
|
|
|
+ public appendHook(impostor: PhysicsImpostor, otherImpostor: PhysicsImpostor, length: number, influence: number = 1, noCollisionBetweenLinkedBodies: boolean = false) {
|
|
|
|
+ var node = Math.round(impostor.segments * length);
|
|
|
|
+ impostor.physicsBody.appendAnchor(node, otherImpostor.physicsBody, noCollisionBetweenLinkedBodies, influence);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
* Sleeps the physics body and stops it from being active
|
|
* Sleeps the physics body and stops it from being active
|
|
* @param impostor impostor to sleep
|
|
* @param impostor impostor to sleep
|
|
*/
|
|
*/
|