Soft bodies
This commit is contained in:
parent
8da28b15a6
commit
13a3526273
|
@ -670,9 +670,9 @@ class ConvexHull {
|
|||
computeFaceNormals();
|
||||
}
|
||||
|
||||
var cb = new Vec4();
|
||||
var ab = new Vec4();
|
||||
function computeFaceNormals() {
|
||||
var cb = new Vec4();
|
||||
var ab = new Vec4();
|
||||
for (f in 0...face3s.length) {
|
||||
var face = face3s[f];
|
||||
var va = vertices[face.a];
|
||||
|
|
|
@ -33,7 +33,12 @@ class PhysicsWorld extends Trait {
|
|||
|
||||
public static var active:PhysicsWorld = null;
|
||||
|
||||
#if arm_physics_soft
|
||||
public var world:BtSoftRigidDynamicsWorldPointer;
|
||||
#else
|
||||
public var world:BtDiscreteDynamicsWorldPointer;
|
||||
#end
|
||||
|
||||
var dispatcher:BtCollisionDispatcherPointer;
|
||||
var contacts:Array<ContactPair> = [];
|
||||
var preUpdates:Array<Void->Void> = null;
|
||||
|
@ -60,13 +65,29 @@ class PhysicsWorld extends Trait {
|
|||
|
||||
var broadphase = BtDbvtBroadphase.create();
|
||||
|
||||
#if arm_physics_soft
|
||||
var collisionConfiguration = BtSoftBodyRigidBodyCollisionConfiguration.create();
|
||||
#else
|
||||
var collisionConfiguration = BtDefaultCollisionConfiguration.create();
|
||||
dispatcher = BtCollisionDispatcher.create(collisionConfiguration);
|
||||
#end
|
||||
|
||||
dispatcher = BtCollisionDispatcher.create(collisionConfiguration);
|
||||
var solver = BtSequentialImpulseConstraintSolver.create();
|
||||
|
||||
world = BtDiscreteDynamicsWorld.create(dispatcher, broadphase, solver, collisionConfiguration);
|
||||
var gravity = iron.Scene.active.raw.gravity == null ? [0, 0, -9.81] : iron.Scene.active.raw.gravity;
|
||||
|
||||
#if arm_physics_soft
|
||||
var softSolver = BtDefaultSoftBodySolver.create();
|
||||
world = BtSoftRigidDynamicsWorld.create(dispatcher, broadphase, solver, collisionConfiguration, softSolver);
|
||||
#if js
|
||||
world.ptr.getWorldInfo().set_m_gravity(BtVector3.create(gravity[0], gravity[1], gravity[2]).value);
|
||||
#elseif cpp
|
||||
world.ptr.getWorldInfo().m_gravity = BtVector3.create(gravity[0], gravity[1], gravity[2]).value;
|
||||
#end
|
||||
#else
|
||||
world = BtDiscreteDynamicsWorld.create(dispatcher, broadphase, solver, collisionConfiguration);
|
||||
#end
|
||||
|
||||
world.ptr.setGravity(BtVector3.create(gravity[0], gravity[1], gravity[2]).value);
|
||||
|
||||
Scene.active.notifyOnInit(function() {
|
||||
|
|
172
Sources/armory/trait/internal/SoftBody.hx
Normal file
172
Sources/armory/trait/internal/SoftBody.hx
Normal file
|
@ -0,0 +1,172 @@
|
|||
package armory.trait.internal;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Mat4;
|
||||
import iron.Trait;
|
||||
import iron.object.MeshObject;
|
||||
import iron.data.MeshData;
|
||||
import iron.data.SceneFormat;
|
||||
#if arm_physics_soft
|
||||
import armory.trait.internal.RigidBody;
|
||||
import armory.trait.internal.PhysicsWorld;
|
||||
import haxebullet.Bullet;
|
||||
#end
|
||||
|
||||
class SoftBody extends Trait {
|
||||
#if (!arm_physics_soft)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
static var physics:PhysicsWorld = null;
|
||||
|
||||
var shape:SoftShape;
|
||||
var bend:Float;
|
||||
var mass:Float;
|
||||
var margin:Float;
|
||||
|
||||
var softBody:BtSoftBodyPointer;
|
||||
|
||||
public function new(shape = SoftShape.Cloth, bend = 0.5, mass = 1.0, margin = 0.04) {
|
||||
super();
|
||||
this.shape = shape;
|
||||
this.bend = bend;
|
||||
this.mass = mass;
|
||||
this.margin = margin;
|
||||
|
||||
iron.system.Tween.timer(3, function() {
|
||||
notifyOnInit(init);
|
||||
});
|
||||
|
||||
// notifyOnInit(init);
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (physics == null) physics = armory.trait.internal.PhysicsWorld.active;
|
||||
|
||||
var softBodyHelpers = BtSoftBodyHelpers.create();
|
||||
var mo = cast(object, MeshObject);
|
||||
mo.frustumCulling = false;
|
||||
var mesh = mo.data.mesh;
|
||||
|
||||
var positions:haxe.ds.Vector<kha.FastFloat> = cast haxe.ds.Vector.fromData(mesh.positions.copy());
|
||||
for (i in 0...Std.int(positions.length / 3)) {
|
||||
positions[i * 3] *= object.transform.scale.x;
|
||||
positions[i * 3 + 1] *= object.transform.scale.y;
|
||||
positions[i * 3 + 2] *= object.transform.scale.z;
|
||||
positions[i * 3] += object.transform.loc.x;
|
||||
positions[i * 3 + 1] += object.transform.loc.y;
|
||||
positions[i * 3 + 2] += object.transform.loc.z;
|
||||
}
|
||||
object.transform.scale.set(1, 1, 1);
|
||||
object.transform.loc.set(0, 0, 0);
|
||||
object.transform.buildMatrix();
|
||||
|
||||
var wrdinfo = physics.world.ptr.getWorldInfo();
|
||||
var vecind = haxe.ds.Vector.fromData(mesh.indices[0]);
|
||||
var numtri = Std.int(mesh.indices[0].length / 3);
|
||||
#if js
|
||||
softBody = softBodyHelpers.CreateFromTriMesh(wrdinfo, positions, vecind, numtri);
|
||||
#elseif cpp
|
||||
untyped __cpp__("softBody = softBodyHelpers->CreateFromTriMesh(wrdinfo, positions->Pointer(), vecind->Pointer(), numtri);");
|
||||
#end
|
||||
|
||||
// softBody.ptr.generateClusters(4);
|
||||
#if js
|
||||
var cfg = softBody.ptr.get_m_cfg();
|
||||
cfg.set_viterations(10);
|
||||
cfg.set_piterations(10);
|
||||
// cfg.set_collisions(0x0001 + 0x0020 + 0x0040); // self collision
|
||||
// cfg.set_collisions(0x11); // Soft-rigid, soft-soft
|
||||
|
||||
if (shape == SoftShape.Volume) {
|
||||
cfg.set_kDF(0.1);
|
||||
cfg.set_kDP(0.01);
|
||||
cfg.set_kPR(bend);
|
||||
}
|
||||
#elseif cpp
|
||||
var cfg = softBody.ptr.m_cfg;
|
||||
cfg.viterations = 10;
|
||||
cfg.piterations = 10;
|
||||
// cfg.collisions = 0x0001 + 0x0020 + 0x0040;
|
||||
|
||||
if (shape == SoftShape.Volume) {
|
||||
cfg.kDF = 0.1;
|
||||
cfg.kDP = 0.01;
|
||||
cfg.kPR = bend;
|
||||
}
|
||||
#end
|
||||
softBody.ptr.setTotalMass(mass, false);
|
||||
|
||||
softBody.ptr.getCollisionShape().setMargin(0.2);
|
||||
|
||||
physics.world.ptr.addSoftBody(softBody, 1, -1);
|
||||
softBody.ptr.setActivationState(4);
|
||||
|
||||
notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
var va = new Vec4();
|
||||
var vb = new Vec4();
|
||||
var vc = new Vec4();
|
||||
var cb = new Vec4();
|
||||
var ab = new Vec4();
|
||||
function update() {
|
||||
var mesh = cast(object, MeshObject).data.mesh;
|
||||
|
||||
var v = mesh.vertexBuffer.lock();
|
||||
var l = mesh.structLength;
|
||||
var numVerts = Std.int(v.length / l);
|
||||
|
||||
#if js
|
||||
var nodes = softBody.ptr.get_m_nodes();
|
||||
#elseif cpp
|
||||
var nodes = softBody.ptr.m_nodes;
|
||||
#end
|
||||
|
||||
for (i in 0...numVerts) {
|
||||
var node = nodes.at(i);
|
||||
#if js
|
||||
var nodePos = node.get_m_x();
|
||||
var nodeNor = node.get_m_n();
|
||||
#elseif cpp
|
||||
var nodePos = node.m_x;
|
||||
var nodeNor = node.m_n;
|
||||
#end
|
||||
v.set(i * l, nodePos.x());
|
||||
v.set(i * l + 1, nodePos.y());
|
||||
v.set(i * l + 2, nodePos.z());
|
||||
v.set(i * l + 3, nodeNor.x());
|
||||
v.set(i * l + 4, nodeNor.y());
|
||||
v.set(i * l + 5, nodeNor.z());
|
||||
}
|
||||
// for (i in 0...Std.int(mesh.indices[0].length / 3)) {
|
||||
// var a = mesh.indices[0][i * 3];
|
||||
// var b = mesh.indices[0][i * 3 + 1];
|
||||
// var c = mesh.indices[0][i * 3 + 2];
|
||||
// va.set(v.get(a * l), v.get(a * l + 1), v.get(a * l + 2));
|
||||
// vb.set(v.get(b * l), v.get(b * l + 1), v.get(b * l + 2));
|
||||
// vc.set(v.get(c * l), v.get(c * l + 1), v.get(c * l + 2));
|
||||
// cb.subvecs(vc, vb);
|
||||
// ab.subvecs(va, vb);
|
||||
// cb.cross(ab);
|
||||
// cb.normalize();
|
||||
// v.set(a * l + 3, cb.x);
|
||||
// v.set(a * l + 4, cb.y);
|
||||
// v.set(a * l + 5, cb.z);
|
||||
// v.set(b * l + 3, cb.x);
|
||||
// v.set(b * l + 4, cb.y);
|
||||
// v.set(b * l + 5, cb.z);
|
||||
// v.set(c * l + 3, cb.x);
|
||||
// v.set(c * l + 4, cb.y);
|
||||
// v.set(c * l + 5, cb.z);
|
||||
// }
|
||||
mesh.vertexBuffer.unlock();
|
||||
}
|
||||
|
||||
#end
|
||||
}
|
||||
|
||||
@:enum abstract SoftShape(Int) from Int {
|
||||
var Cloth = 0;
|
||||
var Volume = 1;
|
||||
}
|
|
@ -2713,6 +2713,30 @@ class ArmoryExporter:
|
|||
x['parameters'].append(rb.type == 'PASSIVE')
|
||||
o['traits'].append(x)
|
||||
|
||||
# Soft bodies modifier
|
||||
soft_type = -1
|
||||
soft_mod = None
|
||||
for m in bobject.modifiers:
|
||||
if m.type == 'CLOTH':
|
||||
soft_type = 0
|
||||
soft_mod = m
|
||||
break
|
||||
elif m.type == 'SOFT_BODY':
|
||||
soft_type = 1 # Volume
|
||||
soft_mod = m
|
||||
break
|
||||
if soft_type >= 0:
|
||||
assets.add_khafile_def('arm_physics_soft')
|
||||
cloth_trait = {}
|
||||
cloth_trait['type'] = 'Script'
|
||||
cloth_trait['class_name'] = 'armory.trait.internal.SoftBody'
|
||||
if soft_type == 0:
|
||||
bend = soft_mod.settings.bending_stiffness
|
||||
elif soft_type == 1:
|
||||
bend = (soft_mod.settings.bend + 1.0) * 10
|
||||
cloth_trait['parameters'] = [soft_type, bend, soft_mod.settings.mass, bobject.soft_body_margin]
|
||||
o['traits'].append(cloth_trait)
|
||||
|
||||
if type == NodeTypeCamera:
|
||||
# Debug console enabled, attach console overlay to each camera
|
||||
if bpy.data.worlds['Arm'].arm_play_console:
|
||||
|
|
|
@ -106,6 +106,7 @@ def init_properties():
|
|||
bpy.types.Object.game_visible = bpy.props.BoolProperty(name="Visible", description="Render this object", default=True)
|
||||
bpy.types.Object.spawn = bpy.props.BoolProperty(name="Spawn", description="Auto-add this object when creating scene", default=True)
|
||||
bpy.types.Object.mobile = bpy.props.BoolProperty(name="Mobile", description="Object moves during gameplay", default=True)
|
||||
bpy.types.Object.soft_body_margin = bpy.props.FloatProperty(name="Soft Body Margin", description="Collision margin", default=0.04)
|
||||
# - Clips
|
||||
bpy.types.Object.bone_animation_enabled = bpy.props.BoolProperty(name="Bone Animation", description="Enable skinning", default=True)
|
||||
bpy.types.Object.object_animation_enabled = bpy.props.BoolProperty(name="Object Animation", description="Enable timeline animation", default=True)
|
||||
|
|
|
@ -109,7 +109,6 @@ class ObjectPropsPanel(bpy.types.Panel):
|
|||
layout.prop(animitem, "loop_prop")
|
||||
layout.prop(animitem, "reflect_prop")
|
||||
|
||||
# Menu in modifiers region
|
||||
class ModifiersPropsPanel(bpy.types.Panel):
|
||||
bl_label = "Armory Props"
|
||||
bl_space_type = "PROPERTIES"
|
||||
|
@ -130,6 +129,20 @@ class ModifiersPropsPanel(bpy.types.Panel):
|
|||
layout.prop(bpy.data.worlds['Arm'], 'generate_ocean_water_color')
|
||||
layout.prop(bpy.data.worlds['Arm'], 'generate_ocean_fade')
|
||||
|
||||
class PhysicsPropsPanel(bpy.types.Panel):
|
||||
bl_label = "Armory Props"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "physics"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
obj = bpy.context.object
|
||||
if obj == None:
|
||||
return
|
||||
|
||||
layout.prop(obj, 'soft_body_margin')
|
||||
|
||||
# Menu in data region
|
||||
class DataPropsPanel(bpy.types.Panel):
|
||||
bl_label = "Armory Props"
|
||||
|
|
Loading…
Reference in a new issue