Physics world

This commit is contained in:
Lubos Lenco 2015-11-26 22:30:19 +01:00
parent 7e1052be90
commit e44d9aa8a9
5 changed files with 708 additions and 14 deletions

View file

@ -117,8 +117,8 @@ void kore() {
if (texturing) {
vec4 texel = texture2D(stex, texCoord);
if(texel.a < 0.4)
discard;
//if(texel.a < 0.4)
// discard;
outColor = vec4(texel * outColor);
}

View file

@ -3,16 +3,22 @@ package cycles;
import lue.App;
import lue.Eg;
import lue.node.CameraNode;
import cycles.trait.PhysicsWorld;
class Root {
var cam:CameraNode;
public static var physics:PhysicsWorld;
public function new() {
var sceneNode = Eg.addScene("Scene");
cam = lue.node.Node.cameras[0];
physics = new PhysicsWorld();
Eg.addNodeTrait(sceneNode, physics);
App.requestRender(render);
}

View file

@ -0,0 +1,248 @@
package cycles.trait;
import haxebullet.Bullet;
import lue.trait.Trait;
import lue.sys.Time;
import lue.math.Vec3;
import lue.math.RayCaster;
class ContactPair {
public var a:Int;
public var b:Int;
public function new(a:Int, b:Int) {
this.a = a;
this.b = b;
}
}
class PhysicsWorld extends Trait {
#if js
public var world:BtDiscreteDynamicsWorld;
var dispatcher:BtCollisionDispatcher;
#elseif cpp
public var world:cpp.Pointer<BtDiscreteDynamicsWorld>;
var dispatcher:cpp.Pointer<BtCollisionDispatcher>;
#end
var contacts:Array<ContactPair> = [];
var rbMap:Map<Int, RigidBody>;
public function new() {
super();
rbMap = new Map();
#if js
//var min = new BtVector3(-100, -100, -100);
//var max = new BtVector3(100, 100, 100);
//var broadphase = new BtAxisSweep3(min, max);
var broadphase = new BtDbvtBroadphase();
var collisionConfiguration = new BtDefaultCollisionConfiguration();
dispatcher = new BtCollisionDispatcher(collisionConfiguration);
var solver = new BtSequentialImpulseConstraintSolver();
world = new BtDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
var g = new BtVector3(0, 0, -9.81);
world.setGravity(g);
#elseif cpp
//var min = BtVector3.create(-100, -100, -100);
//var max = BtVector3.create(100, 100, 100);
//var broadphase = BtAxisSweep3.create(min.value, max.value);
var broadphase = BtDbvtBroadphase.create();
var collisionConfiguration = BtDefaultCollisionConfiguration.create();
dispatcher = BtCollisionDispatcher.create(collisionConfiguration);
var solver = BtSequentialImpulseConstraintSolver.create();
world = BtDiscreteDynamicsWorld.create(dispatcher, broadphase, solver, collisionConfiguration);
var g = BtVector3.create(0, 0, -9.81);
world.value.setGravity(g.value);
#end
requestUpdate(update);
}
public function addRigidBody(body:RigidBody) {
#if js
world.addRigidBody(body.body);
#elseif cpp
world.value.addRigidBody(body.body);
#end
rbMap.set(body.id, body);
}
public function removeRigidBody(body:RigidBody) {
#if js
world.removeRigidBody(body.body);
Ammo.destroy(body.body);
#elseif cpp
world.value.removeRigidBody(body.body);
body.body.destroy();
#end
rbMap.remove(body.id);
}
public function getContacts(body:RigidBody):Array<RigidBody> {
if (contacts.length == 0) return null;
var res:Array<RigidBody> = [];
for (i in 0...contacts.length) {
var c = contacts[i];
#if js
if (c.a == untyped body.body.userIndex) {
res.push(rbMap.get(c.b));
}
else if (c.b == untyped body.body.userIndex) {
res.push(rbMap.get(c.a));
}
#elseif cpp
if (c.a == body.body.value.getUserIndex()) {
res.push(rbMap.get(c.b));
}
else if (c.b == body.body.value.getUserIndex()) {
res.push(rbMap.get(c.a));
}
#end
}
return res;
}
public function update() {
#if js
world.stepSimulation(1 / 60);
#elseif cpp
world.value.stepSimulation(1 / 60);
#end
updateContacts();
}
function updateContacts() {
contacts = [];
#if cpp
var numManifolds = dispatcher.value.getNumManifolds();
#else
var numManifolds = dispatcher.getNumManifolds();
#end
for (i in 0...numManifolds) {
#if js
var contactManifold = dispatcher.getManifoldByIndexInternal(i);
var obA = contactManifold.getBody0();
var obB = contactManifold.getBody1();
var bodyA = untyped Ammo.btRigidBody.prototype.upcast(obA);
var bodyB = untyped Ammo.btRigidBody.prototype.upcast(obB);
// TODO: remove ContactPair
var cp = new ContactPair(untyped bodyA.userIndex, untyped bodyB.userIndex);
#elseif cpp
var contactManifold = dispatcher.value.getManifoldByIndexInternal(i);
var obA = contactManifold.value.getBody0();
var obB = contactManifold.value.getBody1();
var cp = new ContactPair(obA.value.getUserIndex(), obB.value.getUserIndex());
#end
#if js
var numContacts = contactManifold.getNumContacts();
#elseif cpp
var numContacts = contactManifold.value.getNumContacts();
#end
for (j in 0...numContacts) {
#if js
var pt = contactManifold.getContactPoint(j);
#elseif cpp
var pt = contactManifold.value.getContactPoint(j);
#end
if (pt.getDistance() < 0) {
//var ptA = pt.getPositionWorldOnA();
//var ptB = pt.getPositionWorldOnB();
contacts.push(cp);
break; // TODO: only one contact point for now
}
}
}
}
#if js
public var rayCallback:ClosestRayResultCallback;
#elseif cpp
public var rayCallback:cpp.Pointer<ClosestRayResultCallback>;
#end
public function pickClosest(inputX:Float, inputY:Float):RigidBody {
var rayFrom = getRayFrom();
var rayTo = getRayTo(inputX, inputY);
#if js
rayCallback = new ClosestRayResultCallback(rayFrom, rayTo);
#elseif cpp
rayCallback = ClosestRayResultCallback.create(rayFrom.value, rayTo.value);
#end
#if js
world.rayTest(rayFrom, rayTo, rayCallback);
#elseif cpp
world.value.rayTest(rayFrom.value, rayTo.value, rayCallback.value);
#end
#if js
if (rayCallback.hasHit()) {
var co = rayCallback.get_m_collisionObject();
var body = untyped Ammo.btRigidBody.prototype.upcast(co);
return rbMap.get(untyped body.userIndex);
}
else { return null; }
#elseif cpp
if (rayCallback.value.hasHit()) {
var co = rayCallback.value.m_collisionObject;
return rbMap.get(co.value.getUserIndex());
}
else { return null; }
#end
}
#if cpp
public function getRayFrom():cpp.Pointer<BtVector3> {
#else
public function getRayFrom():BtVector3 {
#end
var camera = lue.node.Node.cameras[0];
#if js
return new BtVector3(camera.transform.pos.x, camera.transform.pos.y, camera.transform.pos.z);
#elseif cpp
return BtVector3.create(camera.transform.pos.x, camera.transform.pos.y, camera.transform.pos.z);
#end
}
#if cpp
public function getRayTo(inputX:Float, inputY:Float):cpp.Pointer<BtVector3> {
#else
public function getRayTo(inputX:Float, inputY:Float):BtVector3 {
#end
var camera = lue.node.Node.cameras[0];
var start = new Vec3();
var end = new Vec3();
RayCaster.getDirection(start, end, inputX, inputY, camera);
#if js
return new BtVector3(end.x, end.y, end.z);
#elseif cpp
return BtVector3.create(end.x, end.y, end.z);
#end
}
}

View file

@ -0,0 +1,421 @@
package cycles.trait;
import haxebullet.Bullet;
import lue.trait.Trait;
import lue.sys.Time;
import lue.math.Vec3;
import lue.node.Transform;
import lue.node.ModelNode;
import cycles.Root;
class RigidBody extends Trait {
public static inline var SHAPE_BOX = 0;
public static inline var SHAPE_SPHERE = 1;
public static inline var SHAPE_CONVEX_HULL = 2;
public static inline var SHAPE_MESH = 3;
public static inline var SHAPE_CONE = 4;
public static inline var SHAPE_CYLINDER = 5;
public static inline var SHAPE_CAPSULE = 6;
public static inline var SHAPE_TERRAIN = 7;
public static inline var SHAPE_STATIC_MESH = 8;
var shape:Int;
public var physics:PhysicsWorld;
public var transform:Transform;
public var mass:Float;
public var friction:Float;
#if js
public var body:BtRigidBody = null;
#elseif cpp
public var body:cpp.Pointer<BtRigidBody> = null;
#end
static var nextId = 0;
public var id = 0;
public var onCreated:Void->Void = null;
public function new(mass:Float = 1, shape:Int = SHAPE_BOX, friction:Float = 0.5) {
super();
this.mass = mass;
this.shape = shape;
this.friction = friction;
requestInit(init);
requestUpdate(update);
requestRemove(removeFromWorld);
}
public function init() {
transform = node.transform;
physics = Root.physics;
if (body != null) return;
#if js
var _shape:BtCollisionShape = null;
var _shapeConvex:BtConvexHullShape = null;
#elseif cpp
var _shape:cpp.Pointer<BtCollisionShape> = null;
var _shapeConvex:cpp.Pointer<BtConvexHullShape> = null;
#end
if (shape == SHAPE_BOX) {
#if js
_shape = new BtBoxShape(new BtVector3(
transform.size.x / 2,
transform.size.y / 2,
transform.size.z / 2));
#elseif cpp
_shape = BtBoxShape.create(BtVector3.create(
transform.size.x / 2,
transform.size.y / 2,
transform.size.z / 2).value);
#end
}
else if (shape == SHAPE_SPHERE) {
#if js
_shape = new BtSphereShape(transform.size.x / 2);
#elseif cpp
_shape = BtSphereShape.create(transform.size.x / 2);
#end
}
else if (shape == SHAPE_CONVEX_HULL || shape == SHAPE_MESH) { // Use convex hull for mesh for now
#if js
_shapeConvex = new BtConvexHullShape();
#elseif cpp
_shapeConvex = BtConvexHullShape.create();
#end
addPointsToConvexHull(_shapeConvex);
}
else if (shape == SHAPE_CONE) {
#if js
_shape = new BtConeShapeZ(
transform.size.x / 2, // Radius
transform.size.z); // Height
#elseif cpp
_shape = BtConeShapeZ.create(
transform.size.x / 2,
transform.size.z);
#end
}
else if (shape == SHAPE_CYLINDER) {
#if js
_shape = new BtCylinderShapeZ(new BtVector3(
transform.size.x / 2,
transform.size.y / 2,
transform.size.z / 2));
#elseif cpp
_shape = BtCylinderShapeZ.create(BtVector3.create(
transform.size.x / 2,
transform.size.y / 2,
transform.size.z / 2).value);
#end
}
else if (shape == SHAPE_CAPSULE) {
#if js
_shape = new BtCapsuleShapeZ(
(transform.size.x / 2),// * scaleX, // Radius
transform.size.z);// * scaleZ); // Height
#elseif cpp
_shape = BtCapsuleShapeZ.create(
transform.size.x / 4,
transform.size.z * 0.65);
#end
}
//else if (shape == SHAPE_TERRAIN) {
// throw "Terrain not yet supported, use static mesh instead.";
/*
#if js
var data:Array<Dynamic> = [];
_shape = new BtHeightfieldTerrainShape(3, 3, data, 1, -10, 10, 2, 0, true);
#elseif cpp
var data:Array<Dynamic> = [];
_shape = BtHeightfieldTerrainShape.create(3, 3, data, 1, -10, 10, 2, 0, true);
#end*/
//}
else if (shape == SHAPE_STATIC_MESH || shape == SHAPE_TERRAIN) {
#if js
var meshInterface = new BtTriangleMesh(true, true);
fillTriangleMesh(meshInterface);
_shape = new BtBvhTriangleMeshShape(meshInterface, true, true);
#elseif cpp
var meshInterface = BtTriangleMesh.create(true, true);
fillTriangleMesh(meshInterface);
_shape = BtBvhTriangleMeshShape.create(meshInterface, true, true);
#end
}
#if js
var _transform = new BtTransform();
_transform.setIdentity();
_transform.setOrigin(new BtVector3(
transform.pos.x,
transform.pos.y,
transform.pos.z));
_transform.setRotation(new BtQuaternion(
transform.rot.x,
transform.rot.y,
transform.rot.z,
transform.rot.w));
#elseif cpp
var _transform = BtTransform.create();
_transform.value.setIdentity();
_transform.value.setOrigin(BtVector3.create(
transform.pos.x,
transform.pos.y,
transform.pos.z).value);
_transform.value.setRotation(BtQuaternion.create(
transform.rot.x,
transform.rot.y,
transform.rot.z,
transform.rot.w).value);
#end
#if js
var _centerOfMassOffset = new BtTransform();
_centerOfMassOffset.setIdentity();
var _motionState = new BtDefaultMotionState(_transform, _centerOfMassOffset);
var _inertia = new BtVector3(0, 0, 0);
#elseif cpp
var _centerOfMassOffset = BtTransform.create();
_centerOfMassOffset.value.setIdentity();
var _motionState = BtDefaultMotionState.create(_transform.value, _centerOfMassOffset.value);
var _inertia = BtVector3.create(0, 0, 0);
#end
if (_shapeConvex == null) {
#if js
if (shape != SHAPE_STATIC_MESH && shape != SHAPE_TERRAIN) {
_shape.calculateLocalInertia(mass, _inertia);
}
var _bodyCI = new BtRigidBodyConstructionInfo(mass, _motionState, _shape, _inertia);
body = new BtRigidBody(_bodyCI);
body.setFriction(friction);
body.setRollingFriction(friction);
#elseif cpp
if (shape != SHAPE_STATIC_MESH && shape != SHAPE_TERRAIN) {
_shape.value.calculateLocalInertia(mass, _inertia.value);
}
var _bodyCI = BtRigidBodyConstructionInfo.create(mass, _motionState, _shape, _inertia.value);
body = BtRigidBody.create(_bodyCI.value);
body.value.setFriction(friction);
body.value.setRollingFriction(friction);
#end
}
else {
#if js
_shapeConvex.calculateLocalInertia(mass, _inertia);
var _bodyCI = new BtRigidBodyConstructionInfo(mass, _motionState, _shapeConvex, _inertia);
body = new BtRigidBody(_bodyCI);
#elseif cpp
_shapeConvex.value.calculateLocalInertia(mass, _inertia.value);
var _bodyCI = BtRigidBodyConstructionInfo.create(mass, _motionState, _shapeConvex, _inertia.value);
body = BtRigidBody.create(_bodyCI.value);
#end
}
id = nextId;
nextId++;
#if js
//body.setUserIndex(nextId);
untyped body.userIndex = id;
#elseif cpp
body.value.setUserIndex(id);
#end
physics.addRigidBody(this);
if (onCreated != null) onCreated();
}
function update() {
#if js
var trans = body.getWorldTransform();
#elseif cpp
var trans = body.value.getWorldTransform();
#end
var p = trans.getOrigin();
var q = trans.getRotation();
transform.pos.set(p.x(), p.y(), p.z());
transform.rot.set(q.x(), q.y(), q.z(), q.w());
transform.dirty = true;
transform.update();
}
public function removeFromWorld() {
physics.removeRigidBody(this);
}
public inline function activate() {
#if js
body.activate(false);
#elseif cpp
body.value.activate(false);
#end
}
public inline function disableGravity() {
// TODO: use setGravity instead
setLinearFactor(0, 0, 0);
setAngularFactor(0, 0, 0);
}
/*public inline function setGravity(v:Vec3) {
#if js
body.setGravity(new BtVector3(v.x, v.y, v.z));
#elseif cpp
body.value.setGravity(BtVector3.create(v.x, v.y, v.z).value);
#end
}*/
/*public inline function setActivationState(newState:Int) {
#if js
body.setActivationState(newState);
#elseif cpp
body.value.setActivationState(newState);
#end
}*/
public inline function applyImpulse(impulse:Vec3, pos:Vec3 = null) {
if (pos == null) {
#if js
body.applyCentralImpulse(new BtVector3(impulse.x, impulse.y, impulse.z));
#elseif cpp
body.value.applyCentralImpulse(BtVector3.create(impulse.x, impulse.y, impulse.z).value);
#end
}
else {
#if js
body.applyImpulse(new BtVector3(impulse.x, impulse.y, impulse.z),
new BtVector3(pos.x, pos.y, pos.z));
#elseif cpp
body.value.applyImpulse(BtVector3.create(impulse.x, impulse.y, impulse.z).value,
BtVector3.create(pos.x, pos.y, pos.z).value);
#end
}
}
public inline function setLinearFactor(x:Float, y:Float, z:Float) {
#if js
body.setLinearFactor(new BtVector3(x, y, z));
#elseif cpp
body.value.setLinearFactor(BtVector3.create(x, y, z).value);
#end
}
public inline function setAngularFactor(x:Float, y:Float, z:Float) {
#if js
body.setAngularFactor(new BtVector3(x, y, z));
#elseif cpp
body.value.setAngularFactor(BtVector3.create(x, y, z).value);
#end
}
// public inline function getLinearVelocity():BtVector3 {
// #if js
// return body.getLinearVelocity();
// #elseif cpp // Unable to compile in cpp
// return body.value.getLinearVelocity();
// #end
// }
public inline function setLinearVelocity(x:Float, y:Float, z:Float) {
#if js
body.setLinearVelocity(new BtVector3(x, y, z));
#elseif cpp
body.value.setLinearVelocity(BtVector3.create(x, y, z).value);
#end
}
// public inline function getAngularVelocity():BtVector3 {
// #if js
// return body.getAngularVelocity();
// #elseif cpp
// return body.value.getAngularVelocity();
// #end
// }
public inline function setAngularVelocity(x:Float, y:Float, z:Float) {
#if js
body.setAngularVelocity(new BtVector3(x, y, z));
#elseif cpp
body.value.setAngularVelocity(BtVector3.create(x, y, z).value);
#end
}
public function syncTransform() {
#if js
var trans = new BtTransform();
trans.setOrigin(new BtVector3(transform.pos.x, transform.pos.y, transform.pos.z));
trans.setRotation(new BtQuaternion(transform.rot.x, transform.rot.y, transform.rot.z, transform.rot.w));
body.setCenterOfMassTransform(trans);
#elseif cpp
var trans = BtTransform.create();
trans.value.setOrigin(BtVector3.create(transform.pos.x, transform.pos.y, transform.pos.z).value);
trans.value.setRotation(BtQuaternion.create(transform.rot.x, transform.rot.y, transform.rot.z, transform.rot.w).value);
body.value.setCenterOfMassTransform(trans.value);
#end
}
#if cpp
function addPointsToConvexHull(shape:cpp.Pointer<BtConvexHullShape>) {
#else
function addPointsToConvexHull(shape:BtConvexHullShape) {
#end
var positions = cast(node, ModelNode).resource.geometry.positions;
for (i in 0...Std.int(positions.length / 3)) {
#if js
shape.addPoint(new BtVector3(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]), true);
#elseif cpp
shape.value.addPoint(BtVector3.create(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]).value, true);
#end
}
}
#if cpp
function fillTriangleMesh(triangleMesh:cpp.Pointer<BtTriangleMesh>) {
#else
function fillTriangleMesh(triangleMesh:BtTriangleMesh) {
#end
var positions = cast(node, ModelNode).resource.geometry.positions;
var indices = cast(node, ModelNode).resource.geometry.indices;
for (i in 0...Std.int(indices[0].length / 3)) {
#if js
triangleMesh.addTriangle(
new BtVector3(positions[indices[0][i * 3 + 0] * 3 + 0],
positions[indices[0][i * 3 + 0] * 3 + 1],
positions[indices[0][i * 3 + 0] * 3 + 2]),
new BtVector3(positions[indices[0][i * 3 + 1] * 3 + 0],
positions[indices[0][i * 3 + 1] * 3 + 1],
positions[indices[0][i * 3 + 1] * 3 + 2]),
new BtVector3(positions[indices[0][i * 3 + 2] * 3 + 0],
positions[indices[0][i * 3 + 2] * 3 + 1],
positions[indices[0][i * 3 + 2] * 3 + 2])
);
#elseif cpp
triangleMesh.value.addTriangle(
BtVector3.create(positions[indices[0][i * 3 + 0] * 3 + 0],
positions[indices[0][i * 3 + 0] * 3 + 1],
positions[indices[0][i * 3 + 0] * 3 + 2]).value,
BtVector3.create(positions[indices[0][i * 3 + 1] * 3 + 0],
positions[indices[0][i * 3 + 1] * 3 + 1],
positions[indices[0][i * 3 + 1] * 3 + 2]).value,
BtVector3.create(positions[indices[0][i * 3 + 2] * 3 + 0],
positions[indices[0][i * 3 + 2] * 3 + 1],
positions[indices[0][i * 3 + 2] * 3 + 2]).value
);
#end
}
}
}

View file

@ -1271,10 +1271,15 @@ class LueExporter(bpy.types.Operator, ExportHelper):
else:
parento.nodes.append(o)
if not hasattr(o, 'nodes'):
o.nodes = []
for subnode in node.children:
if (subnode.parent_type != "BONE"):
self.ExportNode(subnode, scene, None, o)
# Export traits
# TODO: export only for geometry nodes and nodes
o.traits = []
for t in node.my_traitlist:
if t.enabled_prop == False:
continue
@ -1288,17 +1293,31 @@ class LueExporter(bpy.types.Operator, ExportHelper):
o.traits.append(x)
if not hasattr(o, 'nodes'):
o.nodes = []
for subnode in node.children:
if (subnode.parent_type != "BONE"):
self.ExportNode(subnode, scene, None, o)
# Rigid body trait
if node.rigid_body != None:
rb = node.rigid_body
shape = '0' # BOX
if rb.collision_shape == 'SPHERE':
shape = '1'
elif rb.collision_shape == 'CONVEX_HULL':
shape = '2'
elif rb.collision_shape == 'MESH':
shape = '3'
elif rb.collision_shape == 'CONE':
shape = '4'
elif rb.collision_shape == 'CYLINDER':
shape = '5'
elif rb.collision_shape == 'CAPSULE':
shape = '6'
body_mass = 0
if rb.enabled:
body_mass = rb.mass
x = Object()
x.type = 'Script'
x.class_name = 'RigidBody:' + str(body_mass) + \
':' + shape + \
":" + str(rb.friction)
o.traits.append(x)