189 lines
5.1 KiB
Haxe
189 lines
5.1 KiB
Haxe
package armory.trait.physics.bullet;
|
|
|
|
#if arm_bullet
|
|
|
|
import iron.math.Vec4;
|
|
import iron.math.Mat4;
|
|
import iron.math.Quat;
|
|
import iron.Trait;
|
|
import iron.object.Object;
|
|
import iron.object.MeshObject;
|
|
import iron.object.Transform;
|
|
import iron.data.MeshData;
|
|
import iron.data.SceneFormat;
|
|
import armory.trait.physics.RigidBody;
|
|
import armory.trait.physics.PhysicsWorld;
|
|
|
|
class PhysicsHook extends Trait {
|
|
var target:Object;
|
|
var targetName:String;
|
|
var targetTransform:Transform;
|
|
var verts:Array<Float>;
|
|
|
|
var constraint:bullet.Bt.Generic6DofConstraint = null;
|
|
|
|
#if arm_physics_soft
|
|
var hookRB:bullet.Bt.RigidBody = null;
|
|
#end
|
|
|
|
static var nullvec = true;
|
|
static var vec1:bullet.Bt.Vector3;
|
|
static var quat1:bullet.Bt.Quaternion;
|
|
static var trans1:bullet.Bt.Transform;
|
|
static var trans2:bullet.Bt.Transform;
|
|
static var quat = new Quat();
|
|
|
|
public function new(targetName:String, verts:Array<Float>) {
|
|
super();
|
|
|
|
if (nullvec) {
|
|
nullvec = false;
|
|
vec1 = new bullet.Bt.Vector3(0, 0, 0);
|
|
quat1 = new bullet.Bt.Quaternion(0, 0, 0, 0);
|
|
trans1 = new bullet.Bt.Transform();
|
|
trans2 = new bullet.Bt.Transform();
|
|
}
|
|
|
|
this.targetName = targetName;
|
|
this.verts = verts;
|
|
|
|
iron.Scene.active.notifyOnInit(function() {
|
|
notifyOnInit(init);
|
|
notifyOnUpdate(update);
|
|
});
|
|
}
|
|
|
|
function init() {
|
|
// Hook to empty axes
|
|
target = targetName != "" ? iron.Scene.active.getChild(targetName) : null;
|
|
targetTransform = target != null ? target.transform : object.transform;
|
|
|
|
var physics = PhysicsWorld.active;
|
|
|
|
// Soft body hook
|
|
#if arm_physics_soft
|
|
var sb:SoftBody = object.getTrait(SoftBody);
|
|
if (sb != null && sb.ready) {
|
|
|
|
// Place static rigid body at target location
|
|
trans1.setIdentity();
|
|
vec1.setX(targetTransform.loc.x);
|
|
vec1.setY(targetTransform.loc.y);
|
|
vec1.setZ(targetTransform.loc.z);
|
|
trans1.setOrigin(vec1);
|
|
quat1.setX(targetTransform.rot.x);
|
|
quat1.setY(targetTransform.rot.y);
|
|
quat1.setZ(targetTransform.rot.z);
|
|
quat1.setW(targetTransform.rot.w);
|
|
trans1.setRotation(quat1);
|
|
var centerOfMassOffset = trans2;
|
|
centerOfMassOffset.setIdentity();
|
|
var mass = 0.0;
|
|
var motionState = new bullet.Bt.DefaultMotionState(trans1, centerOfMassOffset);
|
|
var inertia = vec1;
|
|
inertia.setX(0);
|
|
inertia.setY(0);
|
|
inertia.setZ(0);
|
|
var shape = new bullet.Bt.SphereShape(0.01);
|
|
shape.calculateLocalInertia(mass, inertia);
|
|
var bodyCI = new bullet.Bt.RigidBodyConstructionInfo(mass, motionState, shape, inertia);
|
|
hookRB = new bullet.Bt.RigidBody(bodyCI);
|
|
|
|
#if js
|
|
var nodes = sb.body.get_m_nodes();
|
|
#elseif cpp
|
|
var nodes = sb.body.m_nodes;
|
|
#end
|
|
|
|
var geom = cast(object, MeshObject).data.geom;
|
|
var numNodes = Std.int(geom.positions.length / 4);
|
|
for (i in 0...numNodes) {
|
|
var node = nodes.at(i);
|
|
#if js
|
|
var nodePos = node.get_m_x();
|
|
#elseif cpp
|
|
var nodePos = node.m_x;
|
|
#end
|
|
|
|
// Find nodes at marked vertex group locations
|
|
var numVerts = Std.int(verts.length / 3);
|
|
for (j in 0...numVerts) {
|
|
var x = verts[j * 3] + sb.vertOffsetX;
|
|
var y = verts[j * 3 + 1] + sb.vertOffsetY;
|
|
var z = verts[j * 3 + 2] + sb.vertOffsetZ;
|
|
|
|
// Anchor node to rigid body
|
|
if (Math.abs(nodePos.x() - x) < 0.01 && Math.abs(nodePos.y() - y) < 0.01 && Math.abs(nodePos.z() - z) < 0.01) {
|
|
sb.body.appendAnchor(i, hookRB, false, 1.0 / numVerts);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
#end
|
|
|
|
// Rigid body hook
|
|
var rb1:RigidBody = object.getTrait(RigidBody);
|
|
if (rb1 != null && rb1.ready) {
|
|
trans1.setIdentity();
|
|
vec1.setX(targetTransform.worldx() - object.transform.worldx());
|
|
vec1.setY(targetTransform.worldy() - object.transform.worldy());
|
|
vec1.setZ(targetTransform.worldz() - object.transform.worldz());
|
|
trans1.setOrigin(vec1);
|
|
constraint = new bullet.Bt.Generic6DofConstraint(rb1.body, trans1, false);
|
|
vec1.setX(0);
|
|
vec1.setY(0);
|
|
vec1.setZ(0);
|
|
constraint.setLinearLowerLimit(vec1);
|
|
constraint.setLinearUpperLimit(vec1);
|
|
vec1.setX(-10);
|
|
vec1.setY(-10);
|
|
vec1.setZ(-10);
|
|
constraint.setAngularLowerLimit(vec1);
|
|
vec1.setX(10);
|
|
vec1.setY(10);
|
|
vec1.setZ(10);
|
|
constraint.setAngularUpperLimit(vec1);
|
|
physics.world.addConstraint(constraint, false);
|
|
return;
|
|
}
|
|
|
|
// Rigid body or soft body not initialized yet
|
|
notifyOnInit(init);
|
|
}
|
|
|
|
function update() {
|
|
#if arm_physics_soft
|
|
if (hookRB != null) {
|
|
trans1.setIdentity();
|
|
vec1.setX(targetTransform.world.getLoc().x);
|
|
vec1.setY(targetTransform.world.getLoc().y);
|
|
vec1.setZ(targetTransform.world.getLoc().z);
|
|
trans1.setOrigin(vec1);
|
|
quat.fromMat(targetTransform.world);
|
|
quat1.setX(quat.x);
|
|
quat1.setY(quat.y);
|
|
quat1.setZ(quat.z);
|
|
quat1.setW(quat.w);
|
|
trans1.setRotation(quat1);
|
|
hookRB.setWorldTransform(trans1);
|
|
}
|
|
#end
|
|
|
|
// if (constraint != null) {
|
|
// vec1.setX(targetTransform.worldx() - object.transform.worldx());
|
|
// vec1.setY(targetTransform.worldy() - object.transform.worldy());
|
|
// vec1.setZ(targetTransform.worldz() - object.transform.worldz());
|
|
// var pivot = vec1;
|
|
// #if js
|
|
// constraint.getFrameOffsetA().setOrigin(pivot);
|
|
// #elseif cpp
|
|
// constraint.setFrameOffsetAOrigin(pivot);
|
|
// #end
|
|
// }
|
|
}
|
|
|
|
}
|
|
|
|
#end
|