even more inane code cleanup, more lua bindings, multiple bodies for an entity (doesn't work?), ragdoll (doesn't work)
This commit is contained in:
parent
40157df205
commit
6deb8795c5
@ -350,7 +350,7 @@
|
||||
"max": 0.01 // 0.2
|
||||
},
|
||||
"debug draw": {
|
||||
"dynamic": false
|
||||
"dynamic": true
|
||||
},
|
||||
"fixed step": true,
|
||||
"substeps": 4
|
||||
|
||||
18
bin/data/entities/ragdoll.json
Normal file
18
bin/data/entities/ragdoll.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Ragdoll",
|
||||
"assets": [ "./scripts/ragdoll.lua" ],
|
||||
"behaviors": [
|
||||
"SoundEmitterBehavior"
|
||||
],
|
||||
"transform": {
|
||||
"position": [ -1.00137, 0.748778, -51.6508 ],
|
||||
"rotation": {
|
||||
"axis": [ 0, 1, 0 ],
|
||||
"angle": 0
|
||||
},
|
||||
"scale": [ 1, 1, 1 ]
|
||||
},
|
||||
"metadata": {
|
||||
"holdable": true
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,7 @@ ent:bind( "tick", function(self)
|
||||
local angle = Vector3f.signedAngle( transform.forward, target, axis )
|
||||
local rot = Quaternion.axisAngle( axis, angle * time.delta() * 4 )
|
||||
|
||||
if physicsBody:hasBody() then
|
||||
if physicsBody:initialized() then
|
||||
physicsBody:applyRotation( rot )
|
||||
else
|
||||
transform:rotate( rot )
|
||||
|
||||
@ -86,7 +86,7 @@ ent:bind( "tick", function(self)
|
||||
end
|
||||
|
||||
if state > 0 and rot ~= nil then
|
||||
if physicsBody:hasBody() then
|
||||
if physicsBody:initialized() then
|
||||
physicsBody:applyRotation( rot )
|
||||
else
|
||||
transform:rotate( rot )
|
||||
|
||||
@ -165,12 +165,12 @@ ent:bind( "tick", function(self)
|
||||
local prop, depth = physicsBody:rayCast( center, direction )
|
||||
if depth >= 0 and prop and not string.matched( prop:name(), "/^worldspawn/" ) then
|
||||
local heldObjectTransform = prop:getComponent("Transform")
|
||||
local heldObjectPhysicsState = prop:getComponent("PhysicsBody")
|
||||
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
||||
|
||||
local strength = 500
|
||||
local distanceSquared = (heldObjectTransform.position - flattenedTransform.position):magnitude()
|
||||
|
||||
heldObjectPhysicsState:applyImpulse( flattenedTransform.forward * -heldObjectPhysicsState:getMass() * strength / distanceSquared )
|
||||
heldObjectPhysicsBody:applyImpulse( flattenedTransform.forward * -heldObjectPhysicsBody:getMass() * strength / distanceSquared )
|
||||
if timers.physcannon:elapsed() > 1.0 then
|
||||
timers.physcannon:reset()
|
||||
|
||||
@ -189,14 +189,14 @@ ent:bind( "tick", function(self)
|
||||
|
||||
local prop = entities.get( heldObject.uid )
|
||||
local heldObjectTransform = prop:getComponent("Transform")
|
||||
local heldObjectPhysicsState = prop:getComponent("PhysicsBody")
|
||||
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
||||
|
||||
if mouse1 and timers.physcannon:elapsed() > 0.5 then
|
||||
timers.physcannon:reset()
|
||||
|
||||
heldObject.uid = 0
|
||||
heldObjectPhysicsState:enableGravity(true)
|
||||
heldObjectPhysicsState:applyImpulse( flattenedTransform.forward * heldObjectPhysicsState:getMass() * 50 )
|
||||
heldObjectPhysicsBody:enableGravity(true)
|
||||
heldObjectPhysicsBody:applyImpulse( flattenedTransform.forward * heldObjectPhysicsBody:getMass() * 50 )
|
||||
|
||||
playSound("phys_launch"..math.random(1,4))
|
||||
else
|
||||
@ -214,10 +214,10 @@ ent:bind( "tick", function(self)
|
||||
if distance > 0.001 then
|
||||
if timers.holp:elapsed() > 0.125 then
|
||||
timers.holp:reset()
|
||||
heldObjectPhysicsState:setVelocity( delta * 20 )
|
||||
heldObjectPhysicsBody:setVelocity( delta * 20 )
|
||||
end
|
||||
else
|
||||
heldObjectPhysicsState:setVelocity( Vector3f(0,0,0) )
|
||||
heldObjectPhysicsBody:setVelocity( Vector3f(0,0,0) )
|
||||
end
|
||||
else
|
||||
heldObjectTransform.position = flattenedTransform.position + forward
|
||||
@ -240,8 +240,9 @@ ent:addHook( "entity:Use.%UID%", function( payload )
|
||||
|
||||
heldObject.uid = payload.uid
|
||||
heldObject.distance = offset:norm()
|
||||
|
||||
prop:getComponent("PhysicsBody"):enableGravity(false)
|
||||
|
||||
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
||||
heldObjectPhysicsBody:enableGravity(false)
|
||||
|
||||
print( prop:name() )
|
||||
else
|
||||
@ -250,9 +251,9 @@ ent:addHook( "entity:Use.%UID%", function( payload )
|
||||
elseif heldObject.uid ~= 0 then
|
||||
validUse = true
|
||||
local prop = entities.get( heldObject.uid )
|
||||
local heldObjectPhysicsState = prop:getComponent("PhysicsBody")
|
||||
heldObjectPhysicsState:enableGravity(true)
|
||||
heldObjectPhysicsState:applyImpulse( heldObject.momentum )
|
||||
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
||||
heldObjectPhysicsBody:enableGravity(true)
|
||||
heldObjectPhysicsBody:applyImpulse( heldObject.momentum )
|
||||
|
||||
heldObject.uid = 0
|
||||
heldObject.distance = 0
|
||||
|
||||
73
bin/data/entities/scripts/ragdoll.lua
Normal file
73
bin/data/entities/scripts/ragdoll.lua
Normal file
@ -0,0 +1,73 @@
|
||||
local ent = ent
|
||||
local scene = entities.currentScene()
|
||||
local controller = entities.controller()
|
||||
|
||||
local timer = Timer.new()
|
||||
if not timer:running() then
|
||||
timer:start();
|
||||
end
|
||||
|
||||
local transform = ent:getComponent("Transform")
|
||||
local physicsBody = ent:getComponent("PhysicsBody")
|
||||
local metadata = ent:getComponent("Metadata")
|
||||
|
||||
local bodies = {
|
||||
torso = { Vector3f(0, 1.0, 0), Vector3f(0.2, 0.3, 0.15), 20.0 },
|
||||
head = { Vector3f(0, 1.6, 0), Vector3f(0.15, 0.15, 0.15), 5.0 },
|
||||
|
||||
armLU = { Vector3f(-0.4, 1.2, 0), Vector3f(0.1, 0.2, 0.1), 3.0 },
|
||||
armLL = { Vector3f(-0.4, 0.7, 0), Vector3f(0.08, 0.2, 0.08), 2.0 },
|
||||
armRU = { Vector3f( 0.4, 1.2, 0), Vector3f(0.1, 0.2, 0.1), 3.0 },
|
||||
armRL = { Vector3f( 0.4, 0.7, 0), Vector3f(0.08, 0.2, 0.08), 2.0 },
|
||||
|
||||
legLU = { Vector3f(-0.2, 0.5, 0), Vector3f(0.12, 0.25, 0.12), 6.0 },
|
||||
legLL = { Vector3f(-0.2, -0.1, 0), Vector3f(0.1, 0.25, 0.1), 4.0 },
|
||||
legRU = { Vector3f( 0.2, 0.5, 0), Vector3f(0.12, 0.25, 0.12), 6.0 },
|
||||
legRL = { Vector3f( 0.2, -0.1, 0), Vector3f(0.1, 0.25, 0.1), 4.0 },
|
||||
}
|
||||
local constraints = {
|
||||
neck = { "torso", "head", Vector3f( 0, 1.4, 0 ), Vector3f( 0, 1, 0 ), math.pi / 4.0, math.pi / 8.0 },
|
||||
|
||||
shoulderL = { "torso", "armLU", Vector3f( -0.3, 1.4, 0 ), Vector3f( -1, 0, 0 ), math.pi / 2.0, math.pi / 4.0 },
|
||||
shoulderR = { "torso", "armRU", Vector3f( 0.3, 1.4, 0 ), Vector3f( 1, 0, 0 ), math.pi / 2.0, math.pi / 4.0 },
|
||||
|
||||
elbowL = { "armLU", "armLL", Vector3f( -0.4, 0.95, 0 ), Vector3f( 1, 0, 0 ) },
|
||||
elbowR = { "armRU", "armRL", Vector3f( 0.4, 0.95, 0 ), Vector3f( 1, 0, 0 ) },
|
||||
|
||||
hipL = { "torso", "legLU", Vector3f( -0.2, 0.75, 0 ), Vector3f( 0, -1, 0 ), math.pi / 3.0, math.pi / 8.0 },
|
||||
hipR = { "torso", "legRU", Vector3f( 0.2, 0.75, 0 ), Vector3f( 0, -1, 0 ), math.pi / 3.0, math.pi / 8.0 },
|
||||
|
||||
kneeL = { "legLU", "legLL", Vector3f( -0.2, 0.2, 0 ), Vector3f( 1, 0, 0 ) },
|
||||
kneeR = { "legRU", "legRL", Vector3f( 0.2, 0.2, 0 ), Vector3f( 1, 0, 0 ) },
|
||||
}
|
||||
|
||||
for k, _ in pairs( bodies ) do
|
||||
position = bodies[k][1]
|
||||
box = OBB( position, bodies[k][2] )
|
||||
mass = bodies[k][3]
|
||||
|
||||
body = physics.create( ent, mass, Vector3f() )
|
||||
body:asObb( box )
|
||||
body:setGravity( Vector3f( 0, 0, 0 ) )
|
||||
|
||||
bodies[k] = body
|
||||
end
|
||||
|
||||
for k, _ in pairs( constraints ) do
|
||||
bodyA = bodies[constraints[k][1]]
|
||||
bodyB = bodies[constraints[k][2]]
|
||||
|
||||
joint = constraints[k][3]
|
||||
axis = constraints[k][4]
|
||||
swingLimit = constraints[k][5]
|
||||
twistLimit = constraints[k][6]
|
||||
|
||||
constraint = bodyA:constrain( bodyB )
|
||||
if swingLimit == nil or twistLimit == nil then
|
||||
constraint:asHinge( joint, axis )
|
||||
else
|
||||
constraint:asConeTwist( joint, axis, swingLimit, twistLimit )
|
||||
end
|
||||
|
||||
constraints[k] = constraint
|
||||
end
|
||||
@ -3,7 +3,7 @@
|
||||
"assets": [
|
||||
// { "filename": "./models/mds_mcdonalds.glb" }
|
||||
{ "filename": "./models/mds_mcdonalds/graph.json" }
|
||||
,{ "filename": "/ball.json", "delay": 1 }
|
||||
,{ "filename": "/ragdoll.json", "delay": 1 }
|
||||
],
|
||||
"metadata": {
|
||||
"graph": {
|
||||
|
||||
@ -14,4 +14,13 @@
|
||||
|
||||
namespace impl {
|
||||
void solveConstraint( pod::Constraint& constraint, float dt );
|
||||
}
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::Constraint& UF_API constrain( pod::PhysicsBody&, pod::PhysicsBody& );
|
||||
void UF_API unconstrain( pod::PhysicsBody& );
|
||||
|
||||
void UF_API setConstraintLimits( pod::Constraint& constraint, float lower, float upper );
|
||||
}
|
||||
}
|
||||
@ -8,9 +8,6 @@ namespace impl {
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::Constraint& UF_API constrain( uf::Object&, uf::Object&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, uf::Object&, uf::Object&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrainBallSocket( pod::Constraint& constraint, const pod::Vector3f& joint );
|
||||
}
|
||||
}
|
||||
@ -8,9 +8,6 @@ namespace impl {
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::Constraint& UF_API constrain( uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f&, float, float );
|
||||
pod::Constraint& UF_API constrain( pod::World&, uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f&, float, float );
|
||||
pod::Constraint& UF_API constrain( pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f&, float, float );
|
||||
pod::Constraint& UF_API constrain( pod::World&, pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f&, float, float );
|
||||
pod::Constraint& UF_API constrainConeTwist( pod::Constraint& constraint, const pod::Vector3f& joint, const pod::Vector3f& axis, float swingLimit = M_PI / 4.0f, float twistLimit = M_PI / 8.0f );
|
||||
}
|
||||
}
|
||||
@ -5,13 +5,9 @@
|
||||
namespace impl {
|
||||
void solveDistanceConstraint( pod::Constraint& constraint, float dt );
|
||||
}
|
||||
/*
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::Constraint& UF_API constrain( uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrainDistance( pod::Constraint& constraint, const pod::Vector3f& pA, const pod::Vector3f& pB, bool isRope = false );
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -8,9 +8,6 @@ namespace impl {
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::Constraint& UF_API constrain( uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrainHinge( pod::Constraint& constraint, const pod::Vector3f& joint, const pod::Vector3f& axis );
|
||||
}
|
||||
}
|
||||
@ -14,4 +14,11 @@ namespace impl {
|
||||
float targetVelocity, float maxTorque,
|
||||
float& accumulatedImpulse, float dt
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::Constraint& UF_API constrainMotor( pod::Constraint& constraint, float targetVelocity, float maxForceOrTorque );
|
||||
}
|
||||
}
|
||||
@ -5,13 +5,9 @@
|
||||
namespace impl {
|
||||
void solveSliderConstraint( pod::Constraint& constraint, float dt );
|
||||
}
|
||||
/*
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::Constraint& UF_API constrain( uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrainSlider( pod::Constraint& constraint, const pod::Vector3f& joint, const pod::Vector3f& axis, float lowerLimit, float upperLimit );
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
@ -5,13 +5,9 @@
|
||||
namespace impl {
|
||||
void solveSpringConstraint( pod::Constraint& constraint, float dt );
|
||||
}
|
||||
/*
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::Constraint& UF_API constrain( uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrainSpring( pod::Constraint& constraint, const pod::Vector3f& pA, const pod::Vector3f& pB, float stiffness, float damping );
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
@ -5,13 +5,9 @@
|
||||
namespace impl {
|
||||
void solveWeldConstraint( pod::Constraint& constraint, float dt );
|
||||
}
|
||||
/*
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::Constraint& UF_API constrain( uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, uf::Object&, uf::Object&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, pod::PhysicsBody&, pod::PhysicsBody&, const pod::Vector3f&, const pod::Vector3f& );
|
||||
pod::Constraint& UF_API constrainWeld( pod::Constraint& constraint, const pod::Vector3f& joint, const pod::Vector3f& axis );
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
@ -60,13 +60,5 @@ namespace uf {
|
||||
pod::PhysicsBody& UF_API create( pod::World&, uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
void UF_API destroy( uf::Object& );
|
||||
void UF_API destroy( pod::PhysicsBody& );
|
||||
|
||||
pod::Constraint& UF_API constrain( uf::Object&, uf::Object& );
|
||||
pod::Constraint& UF_API constrain( pod::PhysicsBody&, pod::PhysicsBody& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, uf::Object&, uf::Object& );
|
||||
pod::Constraint& UF_API constrain( pod::World&, pod::PhysicsBody&, pod::PhysicsBody& );
|
||||
|
||||
void UF_API unconstrain( pod::PhysicsBody& );
|
||||
void UF_API unconstrain( uf::Object& );
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,6 @@ namespace impl {
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::PhysicsBody& UF_API create( uf::Object& object, const pod::AABB& aabb, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API create( pod::World&, uf::Object& object, const pod::AABB& aabb, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API initialize( pod::PhysicsBody& body, const pod::AABB& aabb );
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,6 @@ namespace impl {
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::PhysicsBody& UF_API create( uf::Object& object, const pod::Capsule& capsule, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API create( pod::World&, uf::Object& object, const pod::Capsule& capsule, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API initialize( pod::PhysicsBody& body, const pod::Capsule& capsule );
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,6 @@ namespace impl {
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::PhysicsBody& UF_API create( uf::Object&, const uf::Mesh& mesh, float mass = 0.0f, const pod::Vector3f& = {}, bool convex = false );
|
||||
pod::PhysicsBody& UF_API create( pod::World&, uf::Object&, const uf::Mesh& mesh, float mass = 0.0f, const pod::Vector3f& = {}, bool convex = false );
|
||||
pod::PhysicsBody& UF_API initialize( pod::PhysicsBody& body, const uf::Mesh& mesh, bool convex = false );
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,6 @@ namespace impl {
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::PhysicsBody& UF_API create( uf::Object& object, const pod::OBB& obb, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API create( pod::World&, uf::Object& object, const pod::OBB& obb, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API initialize( pod::PhysicsBody& body, const pod::OBB& obb );
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,6 @@ namespace impl {
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::PhysicsBody& UF_API create( uf::Object& object, const pod::Plane& plane, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API create( pod::World&, uf::Object& object, const pod::Plane& plane, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API initialize( pod::PhysicsBody& body, const pod::Plane& plane );
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,6 @@ namespace impl {
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::PhysicsBody& UF_API create( pod::World&, uf::Object& object, const pod::Sphere& sphere, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API create( uf::Object& object, const pod::Sphere& sphere, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API initialize( pod::PhysicsBody& body, const pod::Sphere& sphere );
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,6 @@ namespace impl {
|
||||
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
pod::PhysicsBody& UF_API create( uf::Object& object, const pod::TriangleWithNormal& tri, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API create( pod::World&, uf::Object& object, const pod::TriangleWithNormal& tri, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||
pod::PhysicsBody& UF_API initialize( pod::PhysicsBody& body, const pod::TriangleWithNormal& triangle );
|
||||
}
|
||||
}
|
||||
@ -383,11 +383,9 @@ namespace pod {
|
||||
pod::World* world = NULL;
|
||||
uf::Object* object = NULL;
|
||||
pod::Transform<>* transform = NULL;
|
||||
pod::PhysicsBody* next = NULL;
|
||||
|
||||
bool isStatic = false;
|
||||
|
||||
float mass = 1.0f;
|
||||
float inverseMass = 1.0f; // for fast division
|
||||
float inverseMass = 0.0f;
|
||||
int32_t viewIndex = -1; // -1 means it's not an aliased view
|
||||
|
||||
pod::Vector3f offset = {};
|
||||
@ -483,7 +481,7 @@ namespace uf {
|
||||
typedef pod::Math::num_t num_t;
|
||||
namespace time = uf::time; // to-do: have separate values from the physics system
|
||||
|
||||
extern UF_API pod::World world;
|
||||
//extern UF_API pod::World world;
|
||||
extern UF_API pod::PhysicsSettings settings;
|
||||
}
|
||||
}
|
||||
@ -73,7 +73,7 @@ namespace {
|
||||
{
|
||||
auto& phyziks = metadataJson["physics"];
|
||||
|
||||
collider.stats.mass = phyziks["mass"].as(collider.stats.mass);
|
||||
if ( phyziks["mass"].as<float>() != 0.0f ) collider.stats.inverseMass = 1.0f / phyziks["mass"].as<float>();
|
||||
collider.stats.friction = phyziks["friction"].as(collider.stats.friction);
|
||||
collider.stats.restitution = phyziks["restitution"].as(collider.stats.restitution);
|
||||
collider.stats.inertia = uf::vector::decode( phyziks["inertia"], collider.stats.inertia );
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
|
||||
#define UF_GRAPH_EXTENDED 1
|
||||
#define UF_GRAPH_SPARSE_READ_MESH 1
|
||||
// to-do: fix LOD1+ breaking, fix physics mesh not updating
|
||||
// to-do: fix LOD1+ breaking
|
||||
|
||||
namespace {
|
||||
bool newGraphAdded = true;
|
||||
@ -1330,16 +1330,16 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
|
||||
}
|
||||
#if !UF_GRAPH_EXTENDED
|
||||
if ( isMesh ) {
|
||||
auto& physicsBody = entity.getComponent<pod::PhysicsBody>();
|
||||
float mass = phyziks["mass"].as(physicsBody.mass);
|
||||
|
||||
physicsBody.material.staticFriction = phyziks["friction"].as(physicsBody.material.staticFriction);
|
||||
physicsBody.material.restitution = phyziks["restitution"].as(physicsBody.material.restitution);
|
||||
physicsBody.inverseInertiaTensor = uf::vector::decode( phyziks["inertia"], physicsBody.inverseInertiaTensor );
|
||||
physicsBody.gravity = uf::vector::decode( phyziks["gravity"], physicsBody.gravity );
|
||||
float mass = phyziks["mass"].as(0.0f);
|
||||
auto center = uf::vector::decode( phyziks["center"], pod::Vector3f{} );
|
||||
|
||||
uf::physics::create( entity.as<uf::Object>(), mesh, mass, center, type != "mesh" );
|
||||
|
||||
auto& body = rig.initialized() ? rig.get() : uf::physics::create( entity, mass, center );
|
||||
uf::physics::initialize( body, mesh, type != "mesh" );
|
||||
|
||||
body.material.staticFriction = phyziks["friction"].as(body.material.staticFriction);
|
||||
body.material.restitution = phyziks["restitution"].as(body.material.restitution);
|
||||
body.inverseInertiaTensor = uf::vector::decode( phyziks["inertia"], body.inverseInertiaTensor );
|
||||
body.gravity = uf::vector::decode( phyziks["gravity"], body.gravity );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -1987,7 +1987,6 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
|
||||
}
|
||||
}
|
||||
// bind mesh to physics state
|
||||
// to-do: test if this works in the internal physics system (the entire reason why I wrote it was because of this mess)
|
||||
{
|
||||
auto phyziks = tag["physics"];
|
||||
if ( !ext::json::isObject( phyziks ) ) phyziks = metadataJson["physics"];
|
||||
@ -2002,16 +2001,16 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
|
||||
uf::physics::destroy( entity );
|
||||
}
|
||||
|
||||
auto& physicsBody = entity.getComponent<pod::PhysicsBody>();
|
||||
float mass = phyziks["mass"].as(physicsBody.mass);
|
||||
|
||||
physicsBody.material.staticFriction = phyziks["friction"].as(physicsBody.material.staticFriction);
|
||||
physicsBody.material.restitution = phyziks["restitution"].as(physicsBody.material.restitution);
|
||||
physicsBody.inverseInertiaTensor = uf::vector::decode( phyziks["inertia"], physicsBody.inverseInertiaTensor );
|
||||
physicsBody.gravity = uf::vector::decode( phyziks["gravity"], physicsBody.gravity );
|
||||
float mass = phyziks["mass"].as(0.0f);
|
||||
auto center = uf::vector::decode( phyziks["center"], pod::Vector3f{} );
|
||||
|
||||
uf::physics::create( entity.as<uf::Object>(), mesh, mass, center, type != "mesh" );
|
||||
|
||||
auto& body = uf::physics::create( entity, mass, center );
|
||||
uf::physics::initialize( body, mesh, type != "mesh" );
|
||||
|
||||
body.material.staticFriction = phyziks["friction"].as(body.material.staticFriction);
|
||||
body.material.restitution = phyziks["restitution"].as(body.material.restitution);
|
||||
body.inverseInertiaTensor = uf::vector::decode( phyziks["inertia"], body.inverseInertiaTensor );
|
||||
body.gravity = uf::vector::decode( phyziks["gravity"], body.gravity );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,13 +132,14 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
|
||||
if ( ext::json::isObject(metadataJson["physics"]) ) {
|
||||
auto& metadataJsonPhysics = metadataJson["physics"];
|
||||
auto type = metadataJsonPhysics["type"].as<uf::stl::string>();
|
||||
float mass = metadataJsonPhysics["mass"].as<float>();
|
||||
float mass = metadataJsonPhysics["mass"].as<float>(0.0f);
|
||||
|
||||
bool recenter = metadataJsonPhysics["recenter"].as<bool>();
|
||||
pod::Vector3f offset = uf::vector::decode( metadataJsonPhysics["offset"], pod::Vector3f{} );
|
||||
|
||||
auto offset = uf::vector::decode( metadataJsonPhysics["offset"], pod::Vector3f{} );
|
||||
// if ( offset == pod::Vector3f{} ) recenter = true;
|
||||
|
||||
auto& body = this->getComponent<pod::PhysicsBody>();
|
||||
if ( !body.world ) uf::physics::create( *this, mass, offset );
|
||||
if ( type == "bounding box" || type == "box" || type == "obb" ) {
|
||||
pod::Vector3f center = uf::vector::decode( metadataJsonPhysics["center"], pod::Vector3f{0.0f, 0.0f, 0.0f} );
|
||||
pod::Vector3f extent = uf::vector::decode( metadataJsonPhysics["extent"], pod::Vector3f{0.5f, 0.5f, 0.5f} );
|
||||
@ -148,7 +149,7 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
|
||||
center = {};
|
||||
}
|
||||
|
||||
uf::physics::create( self, pod::OBB{ .center = center, .extent = extent }, mass, offset );
|
||||
uf::physics::initialize( body, pod::OBB{ .center = center, .extent = extent } );
|
||||
} else if ( type == "aabb" ) {
|
||||
pod::Vector3f min = uf::vector::decode( metadataJsonPhysics["min"], pod::Vector3f{-0.5f, -0.5f, -0.5f} );
|
||||
pod::Vector3f max = uf::vector::decode( metadataJsonPhysics["max"], pod::Vector3f{0.5f, 0.5f, 0.5f} );
|
||||
@ -162,42 +163,42 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
|
||||
offset = center;
|
||||
}
|
||||
|
||||
uf::physics::create( self, pod::AABB{ .min = min, .max = max }, mass, offset );
|
||||
uf::physics::initialize( body, pod::AABB{ .min = min, .max = max } );
|
||||
} else if ( type == "plane" ) {
|
||||
pod::Vector3f direction = uf::vector::decode( metadataJsonPhysics["direction"], pod::Vector3f{} );
|
||||
float o = metadataJsonPhysics["offset"].as<float>();
|
||||
|
||||
uf::physics::create( self, pod::Plane{ direction, o }, mass, offset );
|
||||
uf::physics::initialize( body, pod::Plane{ direction, o } );
|
||||
} else if ( type == "sphere" ) {
|
||||
float radius = metadataJsonPhysics["radius"].as<float>();
|
||||
|
||||
uf::physics::create( self, pod::Sphere{ radius }, mass, offset );
|
||||
uf::physics::initialize( body, pod::Sphere{ radius } );
|
||||
} else if ( type == "capsule" ) {
|
||||
float radius = metadataJsonPhysics["radius"].as<float>();
|
||||
float halfHeight = metadataJsonPhysics["height"].as<float>() * 0.5f;
|
||||
|
||||
uf::physics::create( self, pod::Capsule{ radius, halfHeight }, mass, offset );
|
||||
uf::physics::initialize( body, pod::Capsule{ radius, halfHeight } );
|
||||
} else if ( type == "mesh" ) {
|
||||
// ...
|
||||
} else {
|
||||
UF_EXCEPTION("unregistered type: {}", type);
|
||||
}
|
||||
|
||||
auto gravity = uf::vector::decode( metadataJsonPhysics["gravity"], body.gravity );
|
||||
if ( metadataJsonPhysics["category"].is<uf::stl::string>() ){
|
||||
uf::physics::setColliderCategory( body, metadataJsonPhysics["category"].as<uf::stl::string>() );
|
||||
}
|
||||
if ( metadataJsonPhysics["mask"].is<uf::stl::string>() ){
|
||||
uf::physics::setColliderMask( body, metadataJsonPhysics["mask"].as<uf::stl::string>() );
|
||||
}
|
||||
uf::physics::setGravity( body, gravity );
|
||||
|
||||
if ( this->hasComponent<pod::PhysicsBody>() ) {
|
||||
auto& physicsBody = this->getComponent<pod::PhysicsBody>();
|
||||
|
||||
auto gravity = uf::vector::decode( metadataJsonPhysics["gravity"], physicsBody.gravity );
|
||||
|
||||
if ( metadataJsonPhysics["category"].is<uf::stl::string>() ){
|
||||
uf::physics::setColliderCategory( physicsBody, metadataJsonPhysics["category"].as<uf::stl::string>() );
|
||||
}
|
||||
if ( metadataJsonPhysics["mask"].is<uf::stl::string>() ){
|
||||
uf::physics::setColliderMask( physicsBody, metadataJsonPhysics["mask"].as<uf::stl::string>() );
|
||||
}
|
||||
uf::physics::setGravity( physicsBody, gravity );
|
||||
|
||||
physicsBody.velocity = uf::vector::decode( metadataJsonPhysics["velocity"], physicsBody.velocity );
|
||||
physicsBody.angularVelocity = uf::vector::decode( metadataJsonPhysics["angularVelocity"], physicsBody.angularVelocity );
|
||||
|
||||
if ( metadataJsonPhysics["inertia"].is<bool>() && !metadataJsonPhysics["inertia"].as<bool>() ) {
|
||||
physicsBody.inverseInertiaTensor = { 0.0f, 0.0f, 0.0f };
|
||||
}
|
||||
body.velocity = uf::vector::decode( metadataJsonPhysics["velocity"], body.velocity );
|
||||
body.angularVelocity = uf::vector::decode( metadataJsonPhysics["angularVelocity"], body.angularVelocity );
|
||||
body.material.staticFriction = metadataJsonPhysics["friction"].as(body.material.staticFriction);
|
||||
body.material.restitution = metadataJsonPhysics["restitution"].as(body.material.restitution);
|
||||
if ( metadataJsonPhysics["inertia"].is<bool>() && !metadataJsonPhysics["inertia"].as<bool>() ) {
|
||||
body.inverseInertiaTensor = { 0.0f, 0.0f, 0.0f };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -156,6 +156,11 @@ namespace binds {
|
||||
double previous(){ return uf::physics::time::previous; };
|
||||
double delta(){ return uf::physics::time::delta; };
|
||||
}
|
||||
namespace physics {
|
||||
pod::PhysicsBody& create( uf::Object& object, float mass = 0.0f, const pod::Vector3f& center = {} ) {
|
||||
return uf::physics::create( object, mass, center );
|
||||
}
|
||||
}
|
||||
namespace json {
|
||||
uf::stl::string pretty( const uf::stl::string& json ){
|
||||
uf::Serializer serializer = json;
|
||||
@ -254,6 +259,11 @@ void ext::lua::initialize() {
|
||||
time.set("previous", UF_LUA_C_FUN(::binds::time::previous));
|
||||
time.set("delta", UF_LUA_C_FUN(::binds::time::delta));
|
||||
}
|
||||
// `physics` table
|
||||
{
|
||||
auto physics = state["physics"].get_or_create<sol::table>();
|
||||
physics.set("create", UF_LUA_C_FUN(::binds::physics::create));
|
||||
}
|
||||
// `json` table
|
||||
{
|
||||
auto json = state["json"].get_or_create<sol::table>();
|
||||
|
||||
15
engine/src/ext/lua/usertypes/mesh.cpp
Normal file
15
engine/src/ext/lua/usertypes/mesh.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include <uf/ext/lua/lua.h>
|
||||
#if UF_USE_LUA
|
||||
#include <uf/utils/mesh/mesh.h>
|
||||
|
||||
namespace binds {
|
||||
void updateDescriptor( uf::Mesh& self ) {
|
||||
self.updateDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
#include <uf/ext/lua/component.h>
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(uf::Mesh,
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( updateDescriptor, UF_LUA_C_FUN( ::binds::updateDescriptor ) )
|
||||
)
|
||||
#endif
|
||||
@ -3,59 +3,229 @@
|
||||
#include <uf/utils/math/physics.h>
|
||||
|
||||
namespace binds {
|
||||
bool hasBody( pod::PhysicsBody& self ) { return !!self.object; }
|
||||
pod::Vector3f& velocity( pod::PhysicsBody& self ) { return self.velocity; }
|
||||
pod::Vector3f& angularVelocity( pod::PhysicsBody& self ) { return self.angularVelocity; }
|
||||
namespace body {
|
||||
bool initialized( pod::PhysicsBody& self ) { return !!self.world; }
|
||||
pod::Vector3f& velocity( pod::PhysicsBody& self ) { return self.velocity; }
|
||||
pod::Vector3f& angularVelocity( pod::PhysicsBody& self ) { return self.angularVelocity; }
|
||||
|
||||
void setVelocity( pod::PhysicsBody& self, const pod::Vector3f& v ) { uf::physics::setVelocity( self, v ); }
|
||||
void setAngularVelocity( pod::PhysicsBody& self, const pod::Quaternion<>& q, float dt = 0 ) { uf::physics::setAngularVelocity( self, q, dt ); }
|
||||
void setVelocity( pod::PhysicsBody& self, const pod::Vector3f& v ) { uf::physics::setVelocity( self, v ); }
|
||||
void setAngularVelocity( pod::PhysicsBody& self, const pod::Quaternion<>& q, float dt = 0 ) { uf::physics::setAngularVelocity( self, q, dt ); }
|
||||
|
||||
void applyVelocity( pod::PhysicsBody& self, const pod::Vector3f& v ) { uf::physics::applyVelocity( self, v ); }
|
||||
void applyAngularVelocity( pod::PhysicsBody& self, const pod::Quaternion<>& q, float dt = 0 ) { uf::physics::applyAngularVelocity( self, q, dt ); }
|
||||
|
||||
float getMass( const pod::PhysicsBody& self ) { return self.mass; }
|
||||
void setMass( pod::PhysicsBody& self, float mass ) { self.mass = mass; }
|
||||
void applyVelocity( pod::PhysicsBody& self, const pod::Vector3f& v ) { uf::physics::applyVelocity( self, v ); }
|
||||
void applyAngularVelocity( pod::PhysicsBody& self, const pod::Quaternion<>& q, float dt = 0 ) { uf::physics::applyAngularVelocity( self, q, dt ); }
|
||||
|
||||
float getMass( const pod::PhysicsBody& self ) { return self.inverseMass == 0.0f ? 0.0f : 1.0f / self.inverseMass; }
|
||||
void setMass( pod::PhysicsBody& self, float mass ) { self.inverseMass = ( mass == 0.0f ? 0.0f : 1.0f / mass ); }
|
||||
|
||||
void enableGravity( pod::PhysicsBody& state, bool s ) {
|
||||
if ( !state.object ) return;
|
||||
if ( s ) {
|
||||
uf::physics::setGravity( state, pod::Vector3f{ 0, -9.81f, 0 } );
|
||||
} else {
|
||||
uf::physics::setGravity( state );
|
||||
void setGravity( pod::PhysicsBody& self, const pod::Vector3f& gravity ) {
|
||||
uf::physics::setGravity( self, gravity );
|
||||
}
|
||||
void enableGravity( pod::PhysicsBody& self, bool s ) {
|
||||
if ( s ) uf::physics::setGravity( self, pod::Vector3f{ 0, -9.81f, 0 } );
|
||||
else uf::physics::setGravity( self );
|
||||
}
|
||||
|
||||
void applyRotation( pod::PhysicsBody& self, const pod::Quaternion<>& q ) {
|
||||
return uf::physics::applyRotation( self, q );
|
||||
}
|
||||
|
||||
std::tuple<uf::Object*, float> rayCast( pod::PhysicsBody& self, const pod::Vector3f& center, const pod::Vector3f& direction ) {
|
||||
pod::RayQuery query = uf::physics::rayCast( pod::Ray{center, uf::vector::normalize( direction )}, self, uf::vector::norm( direction ) );
|
||||
uf::Object* object = query.hit ? query.body->object : NULL;
|
||||
float depth = query.hit ? query.contact.penetration : -1;
|
||||
return std::make_tuple( object, depth );
|
||||
}
|
||||
|
||||
pod::PhysicsBody& asAabb( pod::PhysicsBody& self, const pod::AABB& shape ) {
|
||||
return uf::physics::initialize( self, shape );
|
||||
}
|
||||
pod::PhysicsBody& asObb( pod::PhysicsBody& self, const pod::OBB& shape ) {
|
||||
return uf::physics::initialize( self, shape );
|
||||
}
|
||||
pod::PhysicsBody& asSphere( pod::PhysicsBody& self, const pod::Sphere& shape ) {
|
||||
return uf::physics::initialize( self, shape );
|
||||
}
|
||||
pod::PhysicsBody& asPlane( pod::PhysicsBody& self, const pod::Plane& shape ) {
|
||||
return uf::physics::initialize( self, shape );
|
||||
}
|
||||
pod::PhysicsBody& asCapsule( pod::PhysicsBody& self, const pod::Capsule& shape ) {
|
||||
return uf::physics::initialize( self, shape );
|
||||
}
|
||||
pod::PhysicsBody& asMesh( pod::PhysicsBody& self, const uf::Mesh& shape, bool convex = false ) {
|
||||
return uf::physics::initialize( self, shape, convex );
|
||||
}
|
||||
|
||||
pod::Constraint& constrain( pod::PhysicsBody& a, pod::PhysicsBody& b ) {
|
||||
return uf::physics::constrain( a, b );
|
||||
}
|
||||
void unconstrain( pod::PhysicsBody& body ) {
|
||||
return uf::physics::unconstrain( body );
|
||||
}
|
||||
}
|
||||
|
||||
void applyRotation( pod::PhysicsBody& state, const pod::Quaternion<>& q ) {
|
||||
return uf::physics::applyRotation( state, q );
|
||||
}
|
||||
|
||||
std::tuple<uf::Object*, float> rayCast( pod::PhysicsBody& self, const pod::Vector3f& center, const pod::Vector3f& direction ) {
|
||||
pod::RayQuery query = uf::physics::rayCast( pod::Ray{center, uf::vector::normalize( direction )}, self, uf::vector::norm( direction ) );
|
||||
uf::Object* object = query.hit ? query.body->object : NULL;
|
||||
float depth = query.hit ? query.contact.penetration : -1;
|
||||
return std::make_tuple( object, depth );
|
||||
namespace constraint {
|
||||
void setLimits( pod::Constraint& self, float lower, float upper ) {
|
||||
return uf::physics::setConstraintLimits( self, lower, upper );
|
||||
}
|
||||
pod::Constraint& asBallSocket( pod::Constraint& self, const pod::Vector3f& joint ) {
|
||||
return uf::physics::constrainBallSocket( self, joint );
|
||||
}
|
||||
pod::Constraint& asConeTwist( pod::Constraint& self, const pod::Vector3f& joint, const pod::Vector3f& axis, float swingLimit = M_PI / 4.0f, float twistLimit = M_PI / 8.0f ) {
|
||||
return uf::physics::constrainConeTwist( self, joint, axis, swingLimit, twistLimit );
|
||||
}
|
||||
pod::Constraint& asDistance( pod::Constraint& self, const pod::Vector3f& pA, const pod::Vector3f& pB, bool isRope = false ) {
|
||||
return uf::physics::constrainDistance( self, pA, pB, isRope );
|
||||
}
|
||||
pod::Constraint& asHinge( pod::Constraint& self, const pod::Vector3f& joint, const pod::Vector3f& axis ) {
|
||||
return uf::physics::constrainHinge( self, joint, axis );
|
||||
}
|
||||
pod::Constraint& asMotor( pod::Constraint& self, float targetVelocity, float maxForceOrTorque ) {
|
||||
return uf::physics::constrainMotor( self, targetVelocity, maxForceOrTorque );
|
||||
}
|
||||
pod::Constraint& asSlider( pod::Constraint& self, const pod::Vector3f& joint, const pod::Vector3f& axis, float lowerLimit, float upperLimit ) {
|
||||
return uf::physics::constrainSlider( self, joint, axis, lowerLimit, upperLimit );
|
||||
}
|
||||
pod::Constraint& asSpring( pod::Constraint& self, const pod::Vector3f& pA, const pod::Vector3f& pB, float stiffness, float damping ) {
|
||||
return uf::physics::constrainSpring( self, pA, pB, stiffness, damping );
|
||||
}
|
||||
pod::Constraint& asWeld( pod::Constraint& self, const pod::Vector3f& joint, const pod::Vector3f& axis ) {
|
||||
return uf::physics::constrainWeld( self, joint, axis );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <uf/ext/lua/component.h>
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::AABB,
|
||||
sol::call_constructor, sol::initializers(
|
||||
[]( pod::AABB& self ) {
|
||||
return self = {};
|
||||
},
|
||||
[]( pod::AABB& self, const pod::AABB& copy ) {
|
||||
return self = copy;
|
||||
},
|
||||
[]( pod::AABB& self, const pod::Vector3f& min, const pod::Vector3f& max ) {
|
||||
return self = pod::AABB{ min, max };
|
||||
}
|
||||
),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::AABB::min),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::AABB::max)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::OBB,
|
||||
sol::call_constructor, sol::initializers(
|
||||
[]( pod::OBB& self ) {
|
||||
return self = {};
|
||||
},
|
||||
[]( pod::OBB& self, const pod::OBB& copy ) {
|
||||
return self = copy;
|
||||
},
|
||||
[]( pod::OBB& self, const pod::Vector3f& center, const pod::Vector3f& extent ) {
|
||||
return self = pod::OBB{ center, extent };
|
||||
}
|
||||
),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::OBB::center),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::OBB::extent)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Sphere,
|
||||
sol::call_constructor, sol::initializers(
|
||||
[]( pod::Sphere& self ) {
|
||||
return self = {};
|
||||
},
|
||||
[]( pod::Sphere& self, const pod::Sphere& copy ) {
|
||||
return self = copy;
|
||||
},
|
||||
[]( pod::Sphere& self, float radius ) {
|
||||
return self = pod::Sphere{ radius };
|
||||
}
|
||||
),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Sphere::radius)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Capsule,
|
||||
sol::call_constructor, sol::initializers(
|
||||
[]( pod::Capsule& self ) {
|
||||
return self = {};
|
||||
},
|
||||
[]( pod::Capsule& self, const pod::Capsule& copy ) {
|
||||
return self = copy;
|
||||
},
|
||||
[]( pod::Capsule& self, float radius, float height ) {
|
||||
return self = pod::Capsule{ radius, height * 0.5f };
|
||||
}
|
||||
),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Capsule::radius),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Capsule::halfHeight)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Plane,
|
||||
sol::call_constructor, sol::initializers(
|
||||
[]( pod::Plane& self ) {
|
||||
return self = {};
|
||||
},
|
||||
[]( pod::Plane& self, const pod::Plane& copy ) {
|
||||
return self = copy;
|
||||
},
|
||||
[]( pod::Plane& self, const pod::Vector3f& normal, float offset ) {
|
||||
return self = pod::Plane{ normal, offset };
|
||||
}
|
||||
),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Plane::normal),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Plane::offset)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Ray,
|
||||
sol::call_constructor, sol::initializers(
|
||||
[]( pod::Ray& self ) {
|
||||
return self = {};
|
||||
},
|
||||
[]( pod::Ray& self, const pod::Ray& copy ) {
|
||||
return self = copy;
|
||||
},
|
||||
[]( pod::Ray& self, const pod::Vector3f& origin, const pod::Vector3f& direction ) {
|
||||
return self = pod::Ray{ origin, direction };
|
||||
}
|
||||
),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Ray::origin),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Ray::direction)
|
||||
)
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::PhysicsBody,
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( hasBody, UF_LUA_C_FUN(::binds::hasBody) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( velocity, UF_LUA_C_FUN(::binds::velocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( angularVelocity, UF_LUA_C_FUN(::binds::angularVelocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( initialized, UF_LUA_C_FUN(::binds::body::initialized) ),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER( pod::PhysicsBody::velocity ),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER( pod::PhysicsBody::angularVelocity ),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setVelocity, UF_LUA_C_FUN(::binds::setVelocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyVelocity, UF_LUA_C_FUN(::binds::applyVelocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setVelocity, UF_LUA_C_FUN(::binds::body::setVelocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyVelocity, UF_LUA_C_FUN(::binds::body::applyVelocity) ),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setAngularVelocity, UF_LUA_C_FUN(::binds::setAngularVelocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyAngularVelocity, UF_LUA_C_FUN(::binds::applyAngularVelocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setAngularVelocity, UF_LUA_C_FUN(::binds::body::setAngularVelocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyAngularVelocity, UF_LUA_C_FUN(::binds::body::applyAngularVelocity) ),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyImpulse, UF_LUA_C_FUN(uf::physics::applyImpulse) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyRotation, UF_LUA_C_FUN(::binds::applyRotation) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( enableGravity, UF_LUA_C_FUN(::binds::enableGravity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( rayCast, UF_LUA_C_FUN(::binds::rayCast) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyRotation, UF_LUA_C_FUN(::binds::body::applyRotation) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setGravity, UF_LUA_C_FUN(::binds::body::setGravity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( enableGravity, UF_LUA_C_FUN(::binds::body::enableGravity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( rayCast, UF_LUA_C_FUN(::binds::body::rayCast) ),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( getMass, UF_LUA_C_FUN(::binds::getMass) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setMass, UF_LUA_C_FUN(::binds::setMass) )
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( getMass, UF_LUA_C_FUN(::binds::body::getMass) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setMass, UF_LUA_C_FUN(::binds::body::setMass) ),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asAabb, UF_LUA_C_FUN(::binds::body::asAabb) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asObb, UF_LUA_C_FUN(::binds::body::asObb) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asSphere, UF_LUA_C_FUN(::binds::body::asSphere) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asPlane, UF_LUA_C_FUN(::binds::body::asPlane) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asCapsule, UF_LUA_C_FUN(::binds::body::asCapsule) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asMesh, UF_LUA_C_FUN(::binds::body::asMesh) ),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( constrain, UF_LUA_C_FUN(::binds::body::constrain) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( unconstrain, UF_LUA_C_FUN(::binds::body::unconstrain) )
|
||||
)
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Constraint,
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setLimits, UF_LUA_C_FUN(::binds::constraint::setLimits) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asBallSocket, UF_LUA_C_FUN(::binds::constraint::asBallSocket) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asConeTwist, UF_LUA_C_FUN(::binds::constraint::asConeTwist) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asDistance, UF_LUA_C_FUN(::binds::constraint::asDistance) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asHinge, UF_LUA_C_FUN(::binds::constraint::asHinge) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asMotor, UF_LUA_C_FUN(::binds::constraint::asMotor) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asSlider, UF_LUA_C_FUN(::binds::constraint::asSlider) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asSpring, UF_LUA_C_FUN(::binds::constraint::asSpring) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asWeld, UF_LUA_C_FUN(::binds::constraint::asWeld) )
|
||||
)
|
||||
|
||||
#endif
|
||||
@ -189,7 +189,7 @@ void impl::buildBroadphaseBVH( pod::BVH& bvh, const uf::stl::vector<pod::Physics
|
||||
|
||||
// populate initial indices and bounds
|
||||
for ( auto i = 0; i < bodies.size(); ++i ) {
|
||||
if ( filters && bodies[i]->isStatic != filterType ) continue;
|
||||
if ( filters && ( bodies[i]->inverseMass == 0.0f ) != filterType ) continue;
|
||||
|
||||
bounds[i] = bodies[i]->bounds;
|
||||
bvh.indices.emplace_back(i);
|
||||
|
||||
@ -48,7 +48,7 @@ void impl::buildIslands( const pod::BVH::pairs_t& pairs, const uf::stl::vector<p
|
||||
|
||||
// union all pairs
|
||||
for ( auto& [a, b] : pairs ) {
|
||||
if ( !bodies[a]->isStatic && !bodies[b]->isStatic ) {
|
||||
if ( bodies[a]->inverseMass != 0.0f && bodies[b]->inverseMass != 0.0f ) {
|
||||
unionizer.unite(a, b);
|
||||
}
|
||||
}
|
||||
@ -58,7 +58,7 @@ void impl::buildIslands( const pod::BVH::pairs_t& pairs, const uf::stl::vector<p
|
||||
auto itB = bodyToIndex.find(constraint->b);
|
||||
|
||||
if (itA != bodyToIndex.end() && itB != bodyToIndex.end()) {
|
||||
if ( !constraint->a->isStatic && !constraint->b->isStatic ) {
|
||||
if ( constraint->a->inverseMass != 0.0f && constraint->b->inverseMass != 0.0f ) {
|
||||
unionizer.unite(itA->second, itB->second);
|
||||
}
|
||||
}
|
||||
@ -72,7 +72,7 @@ void impl::buildIslands( const pod::BVH::pairs_t& pairs, const uf::stl::vector<p
|
||||
islands.reserve(bodies.size());
|
||||
|
||||
for ( auto i = 0; i < bodies.size(); i++ ) {
|
||||
if ( bodies[i]->isStatic ) continue;
|
||||
if ( bodies[i]->inverseMass == 0.0f ) continue;
|
||||
|
||||
pod::BVH::index_t root = unionizer.find(i);
|
||||
|
||||
@ -89,8 +89,8 @@ void impl::buildIslands( const pod::BVH::pairs_t& pairs, const uf::stl::vector<p
|
||||
if ( !impl::shouldCollide( *bodies[a], *bodies[b] ) ) continue;
|
||||
|
||||
// just in case
|
||||
pod::BVH::index_t dynamicIndex = bodies[a]->isStatic ? b : a;
|
||||
if ( bodies[a]->isStatic && bodies[b]->isStatic ) continue;
|
||||
pod::BVH::index_t dynamicIndex = bodies[a]->inverseMass == 0.0f ? b : a;
|
||||
if ( bodies[a]->inverseMass == 0.0f && bodies[b]->inverseMass == 0.0f ) continue;
|
||||
|
||||
pod::BVH::index_t root = unionizer.find(a);
|
||||
if ( rootToIsland.find(root) != rootToIsland.end() ) {
|
||||
@ -115,8 +115,8 @@ void impl::buildIslands( const pod::BVH::pairs_t& pairs, const uf::stl::vector<p
|
||||
|
||||
// Wake bodies if connected by a constraint and one is awake
|
||||
if ( constraint->a->activity.awake || constraint->b->activity.awake ) {
|
||||
if (!constraint->a->isStatic) impl::wakeBody( *constraint->a );
|
||||
if (!constraint->b->isStatic) impl::wakeBody( *constraint->b );
|
||||
if (constraint->a->inverseMass != 0.0f) impl::wakeBody( *constraint->a );
|
||||
if (constraint->b->inverseMass != 0.0f) impl::wakeBody( *constraint->b );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ void impl::wakeBody( pod::PhysicsBody& body ) {
|
||||
|
||||
body.activity.awake = true;
|
||||
|
||||
if ( body.isStatic ) {
|
||||
if ( body.inverseMass == 0.0f ) {
|
||||
body.bounds = impl::computeAABB( body );
|
||||
if ( body.world ) body.world->staticBvh.dirty = true;
|
||||
}
|
||||
@ -104,13 +104,13 @@ bool impl::shouldCollide( const pod::Collider& a, const pod::Collider& b ) {
|
||||
return ( a.category & b.mask ) && ( b.category & a.mask );
|
||||
}
|
||||
bool impl::shouldCollide( const pod::PhysicsBody& a, const pod::PhysicsBody& b ) {
|
||||
if ( a.isStatic && b.isStatic ) return false; // this shouldn't ever happen if we're segregating static bodies from dynamic bodies in the broadphase
|
||||
if ( a.inverseMass == 0.0f && b.inverseMass == 0.0f ) return false; // this shouldn't ever happen if we're segregating static bodies from dynamic bodies in the broadphase
|
||||
return impl::shouldCollide( a.collider, b.collider );
|
||||
}
|
||||
|
||||
// returns an inverse inertia matrix from an inertia tensor
|
||||
pod::Matrix3f impl::computeWorldInverseInertia( const pod::PhysicsBody& b ) {
|
||||
if ( b.isStatic || b.inverseMass == 0.0f ) return pod::Matrix3f{};
|
||||
if ( b.inverseMass == 0.0f ) return pod::Matrix3f{};
|
||||
|
||||
pod::Matrix3f invI_local = uf::matrix::diagonal( b.inverseInertiaTensor );
|
||||
pod::Matrix3f R = uf::quaternion::matrix3(b.transform->orientation);
|
||||
|
||||
@ -25,4 +25,42 @@ void impl::solveConstraint( pod::Constraint& constraint, float dt ) {
|
||||
return impl::solveSpringConstraint( constraint, dt );
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void uf::physics::setConstraintLimits( pod::Constraint& constraint, float lower, float upper ) {
|
||||
switch ( constraint.type ) {
|
||||
case pod::ConstraintType::SLIDER:
|
||||
constraint.slider.lowerLimit = lower;
|
||||
constraint.slider.upperLimit = upper;
|
||||
break;
|
||||
case pod::ConstraintType::CONE_TWIST:
|
||||
constraint.coneTwist.swingLimit = lower;
|
||||
constraint.coneTwist.twistLimit = upper;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pod::Constraint& uf::physics::constrain( pod::PhysicsBody& a, pod::PhysicsBody& b ) {
|
||||
auto& world = *a.world;
|
||||
// allocate constraint struct (pointer cringe because the vector WILL resize)
|
||||
auto* pointer = world.constraints.emplace_back(new pod::Constraint);
|
||||
auto& constraint = *pointer;
|
||||
constraint.a = &a;
|
||||
constraint.b = &b;
|
||||
return constraint;
|
||||
}
|
||||
|
||||
void uf::physics::unconstrain( pod::PhysicsBody& body ) {
|
||||
auto& world = *body.world;
|
||||
auto& constraints = world.constraints;
|
||||
// remove all constraints that reference this body
|
||||
for ( auto it = constraints.begin(); it != constraints.end(); ) {
|
||||
auto* constraint = *it;
|
||||
if ( constraint->a == &body || constraint->b == &body ) {
|
||||
it = constraints.erase(it);
|
||||
delete constraint;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,25 +46,16 @@ void impl::solveBallSocketConstraint( pod::Constraint& constraint, float dt ) {
|
||||
impl::applyImpulseTo( a, b, rA, rB, impulse, joint.accumulatedImpulse );
|
||||
}
|
||||
|
||||
pod::Constraint& uf::physics::constrain( pod::World& world, pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& joint ) {
|
||||
auto& constraint = uf::physics::constrain( world, a, b );
|
||||
constraint.type = pod::ConstraintType::BALL_AND_SOCKET;
|
||||
// transform joint into local space
|
||||
auto tA = impl::getTransform( a );
|
||||
auto tB = impl::getTransform( b );
|
||||
pod::Constraint& uf::physics::constrainBallSocket( pod::Constraint& constraint, const pod::Vector3f& p ) {
|
||||
auto& joint = constraint.ballSocket;
|
||||
|
||||
constraint.ballSocket.localAnchorA = uf::transform::applyInverse( tA, joint );
|
||||
constraint.ballSocket.localAnchorB = uf::transform::applyInverse( tB, joint );
|
||||
constraint.ballSocket.accumulatedImpulse = {};
|
||||
auto tA = impl::getTransform( *constraint.a );
|
||||
auto tB = impl::getTransform( *constraint.b );
|
||||
|
||||
constraint.type = pod::ConstraintType::BALL_AND_SOCKET;
|
||||
joint.localAnchorA = uf::transform::applyInverse( tA, p );
|
||||
joint.localAnchorB = uf::transform::applyInverse( tB, p );
|
||||
joint.accumulatedImpulse = {};
|
||||
|
||||
return constraint;
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( pod::World& world, uf::Object& a, uf::Object& b, const pod::Vector3f& joint ) {
|
||||
return constrain( world, a.getComponent<pod::PhysicsBody>(), b.getComponent<pod::PhysicsBody>(), joint );
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& joint ) {
|
||||
return constrain( uf::physics::getWorld(), a, b, joint );
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( uf::Object& a, uf::Object& b, const pod::Vector3f& joint ) {
|
||||
return constrain( uf::physics::getWorld(), a.getComponent<pod::PhysicsBody>(), b.getComponent<pod::PhysicsBody>(), joint );
|
||||
}
|
||||
@ -104,8 +104,8 @@ void impl::solveConeTwistConstraint( pod::Constraint& constraint, float dt ) {
|
||||
joint.accumulatedAngularImpulse.y = unconstrainedTwist;
|
||||
|
||||
auto impulseVector = (swingAxis * swingDelta) + (twistAxis * twistDelta);
|
||||
if ( !a.isStatic ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulseVector );
|
||||
if ( !b.isStatic ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulseVector );
|
||||
if ( a.inverseMass != 0.0f ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulseVector );
|
||||
if ( b.inverseMass != 0.0f ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulseVector );
|
||||
|
||||
return;
|
||||
}
|
||||
@ -119,8 +119,8 @@ void impl::solveConeTwistConstraint( pod::Constraint& constraint, float dt ) {
|
||||
float bias = (uf::physics::settings.baumgarteCorrectionPercent / dt) * swingError;
|
||||
float j = -(uf::vector::dot(relAngularVel, swingAxis) + bias) / invMassN;
|
||||
auto impulse = swingAxis * impl::accumulateImpulseTo( j, joint.accumulatedAngularImpulse.x, -FLT_MAX, 0.0f );
|
||||
if ( !a.isStatic ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulse );
|
||||
if ( !b.isStatic ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulse );
|
||||
if ( a.inverseMass != 0.0f ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulse );
|
||||
if ( b.inverseMass != 0.0f ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulse );
|
||||
}
|
||||
|
||||
// twist fallback: solve 1D
|
||||
@ -133,48 +133,37 @@ void impl::solveConeTwistConstraint( pod::Constraint& constraint, float dt ) {
|
||||
float min = (twistError > 0.0f) ? -FLT_MAX : 0.0f;
|
||||
float max = (twistError > 0.0f) ? 0.0f : FLT_MAX;
|
||||
auto impulse = twistAxis * impl::accumulateImpulseTo( j, joint.accumulatedAngularImpulse.y, min, max );
|
||||
if ( !a.isStatic ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulse );
|
||||
if ( !b.isStatic ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulse );
|
||||
if ( a.inverseMass != 0.0f ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulse );
|
||||
if ( b.inverseMass != 0.0f ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulse );
|
||||
}
|
||||
}
|
||||
|
||||
pod::Constraint& uf::physics::constrain( pod::World& world, pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& joint, const pod::Vector3f& axis, float swingLimit, float twistLimit ) {
|
||||
auto& constraint = uf::physics::constrain( world, a, b );
|
||||
pod::Constraint& uf::physics::constrainConeTwist( pod::Constraint& constraint, const pod::Vector3f& p, const pod::Vector3f& a, float swingLimit, float twistLimit ) {
|
||||
auto tA = impl::getTransform( *constraint.a );
|
||||
auto tB = impl::getTransform( *constraint.b );
|
||||
|
||||
auto axis = uf::vector::normalize( a );
|
||||
auto tangent = uf::vector::normalize( impl::computeTangent( axis ) );
|
||||
|
||||
auto invqA = uf::quaternion::inverse( tA.orientation );
|
||||
auto invqB = uf::quaternion::inverse( tB.orientation );
|
||||
|
||||
auto& joint = constraint.coneTwist;
|
||||
constraint.type = pod::ConstraintType::CONE_TWIST;
|
||||
|
||||
// transform joint into local space
|
||||
auto tA = impl::getTransform( a );
|
||||
auto tB = impl::getTransform( b );
|
||||
|
||||
auto normAxis = uf::vector::normalize( axis );
|
||||
auto worldRefAxis = uf::vector::normalize( impl::computeTangent( normAxis ) );
|
||||
|
||||
auto invOriA = uf::quaternion::inverse( tA.orientation );
|
||||
auto invOriB = uf::quaternion::inverse( tB.orientation );
|
||||
|
||||
constraint.coneTwist.localAnchorA = uf::transform::applyInverse( tA, joint );
|
||||
constraint.coneTwist.localAnchorB = uf::transform::applyInverse( tB, joint );
|
||||
joint.localAnchorA = uf::transform::applyInverse( tA, p );
|
||||
joint.localAnchorB = uf::transform::applyInverse( tB, p );
|
||||
|
||||
constraint.coneTwist.accumulatedImpulse = {};
|
||||
constraint.coneTwist.accumulatedAngularImpulse = {};
|
||||
joint.accumulatedImpulse = {};
|
||||
joint.accumulatedAngularImpulse = {};
|
||||
|
||||
constraint.coneTwist.localTwistAxisA = uf::quaternion::rotate( invOriA, normAxis );
|
||||
constraint.coneTwist.localTwistAxisB = uf::quaternion::rotate( invOriB, normAxis );
|
||||
joint.localTwistAxisA = uf::quaternion::rotate( invqA, axis );
|
||||
joint.localTwistAxisB = uf::quaternion::rotate( invqB, axis );
|
||||
|
||||
constraint.coneTwist.localReferenceAxisA = uf::quaternion::rotate( invOriA, worldRefAxis );
|
||||
constraint.coneTwist.localReferenceAxisB = uf::quaternion::rotate( invOriB, worldRefAxis );
|
||||
joint.localReferenceAxisA = uf::quaternion::rotate( invqA, tangent );
|
||||
joint.localReferenceAxisB = uf::quaternion::rotate( invqB, tangent );
|
||||
|
||||
constraint.coneTwist.swingLimit = swingLimit;
|
||||
constraint.coneTwist.twistLimit = twistLimit;
|
||||
joint.swingLimit = swingLimit;
|
||||
joint.twistLimit = twistLimit;
|
||||
|
||||
return constraint;
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( pod::World& world, uf::Object& a, uf::Object& b, const pod::Vector3f& joint, const pod::Vector3f& axis, float swingLimit, float twistLimit ) {
|
||||
return constrain( world, a.getComponent<pod::PhysicsBody>(), b.getComponent<pod::PhysicsBody>(), joint, axis, swingLimit, twistLimit );
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& joint, const pod::Vector3f& axis, float swingLimit, float twistLimit ) {
|
||||
return constrain( uf::physics::getWorld(), a, b, joint, axis, swingLimit, twistLimit );
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( uf::Object& a, uf::Object& b, const pod::Vector3f& joint, const pod::Vector3f& axis, float swingLimit, float twistLimit ) {
|
||||
return constrain( uf::physics::getWorld(), a.getComponent<pod::PhysicsBody>(), b.getComponent<pod::PhysicsBody>(), joint, axis, swingLimit, twistLimit );
|
||||
}
|
||||
@ -37,4 +37,20 @@ void impl::solveDistanceConstraint( pod::Constraint& constraint, float dt ) {
|
||||
float j = -(relVelAlongNormal + bias) / invMassN;
|
||||
|
||||
impl::applyImpulseTo( a, b, rA, rB, normal, j, joint.accumulatedImpulse, -FLT_MAX, joint.isRope ? 0 : FLT_MAX );
|
||||
}
|
||||
|
||||
pod::Constraint& uf::physics::constrainDistance( pod::Constraint& constraint, const pod::Vector3f& pA, const pod::Vector3f& pB, bool isRope ) {
|
||||
auto tA = impl::getTransform( *constraint.a );
|
||||
auto tB = impl::getTransform( *constraint.b );
|
||||
|
||||
auto& joint = constraint.distance;
|
||||
constraint.type = pod::ConstraintType::DISTANCE;
|
||||
joint.localAnchorA = uf::transform::applyInverse( tA, pA );
|
||||
joint.localAnchorB = uf::transform::applyInverse( tB, pB );
|
||||
|
||||
joint.targetDistance = uf::vector::distance( pB, pA );
|
||||
joint.accumulatedImpulse = 0.0f;
|
||||
joint.isRope = isRope;
|
||||
|
||||
return constraint;
|
||||
}
|
||||
@ -47,8 +47,8 @@ void impl::solveHingeConstraint( pod::Constraint& constraint, float dt ) {
|
||||
for ( auto i = 0; i < 2; ++i ) {
|
||||
auto jDelta = impl::accumulateImpulseTo( impulse[i], joint.accumulatedAngularImpulse[i] );
|
||||
auto j = tangents[i] * jDelta;
|
||||
if ( !a.isStatic ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, j );
|
||||
if ( !b.isStatic ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, j );
|
||||
if ( a.inverseMass != 0.0f ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, j );
|
||||
if ( b.inverseMass != 0.0f ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, j );
|
||||
}
|
||||
|
||||
if ( motor.enabled ) {
|
||||
@ -56,29 +56,19 @@ void impl::solveHingeConstraint( pod::Constraint& constraint, float dt ) {
|
||||
}
|
||||
}
|
||||
|
||||
pod::Constraint& uf::physics::constrain( pod::World& world, pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& joint, const pod::Vector3f& axis ) {
|
||||
auto& constraint = uf::physics::constrain( world, a, b );
|
||||
constraint.type = pod::ConstraintType::HINGE;
|
||||
// transform joint into local space
|
||||
auto tA = impl::getTransform( a );
|
||||
auto tB = impl::getTransform( b );
|
||||
auto normAxis = uf::vector::normalize( axis );
|
||||
pod::Constraint& uf::physics::constrainHinge( pod::Constraint& constraint, const pod::Vector3f& p, const pod::Vector3f& a ) {
|
||||
auto tA = impl::getTransform( *constraint.a );
|
||||
auto tB = impl::getTransform( *constraint.b );
|
||||
auto axis = uf::vector::normalize( a );
|
||||
|
||||
constraint.hinge.localAnchorA = uf::transform::applyInverse( tA, joint );
|
||||
constraint.hinge.localAnchorB = uf::transform::applyInverse( tB, joint );
|
||||
constraint.hinge.accumulatedImpulse = {};
|
||||
constraint.hinge.localAxisA = uf::quaternion::rotate( uf::quaternion::inverse(tA.orientation), normAxis );
|
||||
constraint.hinge.localAxisB = uf::quaternion::rotate( uf::quaternion::inverse(tB.orientation), normAxis );
|
||||
constraint.hinge.accumulatedAngularImpulse = {};
|
||||
auto& joint = constraint.hinge;
|
||||
constraint.type = pod::ConstraintType::HINGE;
|
||||
joint.localAnchorA = uf::transform::applyInverse( tA, p );
|
||||
joint.localAnchorB = uf::transform::applyInverse( tB, p );
|
||||
joint.accumulatedImpulse = {};
|
||||
joint.localAxisA = uf::quaternion::rotate( uf::quaternion::inverse( tA.orientation ), axis );
|
||||
joint.localAxisB = uf::quaternion::rotate( uf::quaternion::inverse( tB.orientation ), axis );
|
||||
joint.accumulatedAngularImpulse = {};
|
||||
|
||||
return constraint;
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( pod::World& world, uf::Object& a, uf::Object& b, const pod::Vector3f& joint, const pod::Vector3f& axis ) {
|
||||
return constrain( world, a.getComponent<pod::PhysicsBody>(), b.getComponent<pod::PhysicsBody>(), joint, axis );
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& joint, const pod::Vector3f& axis ) {
|
||||
return constrain( uf::physics::getWorld(), a, b, joint, axis );
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( uf::Object& a, uf::Object& b, const pod::Vector3f& joint, const pod::Vector3f& axis ) {
|
||||
return constrain( uf::physics::getWorld(), a.getComponent<pod::PhysicsBody>(), b.getComponent<pod::PhysicsBody>(), joint, axis );
|
||||
}
|
||||
@ -40,6 +40,17 @@ void impl::solve1DAngularMotor(
|
||||
auto jDelta = impl::accumulateImpulseTo( j, accumulatedImpulse, -maxImpulse, maxImpulse );
|
||||
|
||||
pod::Vector3f impulse = axis * jDelta;
|
||||
if ( !a.isStatic ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulse );
|
||||
if ( !b.isStatic ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulse );
|
||||
if ( a.inverseMass != 0.0f ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulse );
|
||||
if ( b.inverseMass != 0.0f ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulse );
|
||||
}
|
||||
|
||||
pod::Constraint& uf::physics::constrainMotor( pod::Constraint& constraint, float targetVelocity, float maxForceOrTorque ) {
|
||||
auto& motor = constraint.motor;
|
||||
|
||||
motor.enabled = true;
|
||||
motor.targetVelocity = targetVelocity;
|
||||
motor.maxMotorTorque = maxForceOrTorque;
|
||||
motor.accumulatedMotorImpulse = 0.0f;
|
||||
|
||||
return constraint;
|
||||
}
|
||||
@ -53,8 +53,8 @@ void impl::solveSliderConstraint( pod::Constraint& constraint, float dt ) {
|
||||
pod::Vector3f impulse = uf::matrix::multiply( Kinv, rhs );
|
||||
joint.accumulatedAngularImpulse += impulse;
|
||||
|
||||
if ( !a.isStatic ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulse );
|
||||
if ( !b.isStatic ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulse );
|
||||
if ( a.inverseMass != 0.0f ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulse );
|
||||
if ( b.inverseMass != 0.0f ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulse );
|
||||
}
|
||||
{
|
||||
pod::Vector3f t1 = wrA;
|
||||
@ -101,4 +101,35 @@ void impl::solveSliderConstraint( pod::Constraint& constraint, float dt ) {
|
||||
float max = ( currentDist < joint.lowerLimit ) ? FLT_MAX : 0.0f;
|
||||
impl::applyImpulseTo( a, b, rA, rB, waA, j, joint.accumulatedLimitImpulse, min, max );
|
||||
}
|
||||
}
|
||||
|
||||
pod::Constraint& uf::physics::constrainSlider( pod::Constraint& constraint, const pod::Vector3f& p, const pod::Vector3f& a, float lowerLimit, float upperLimit ) {
|
||||
auto tA = impl::getTransform( *constraint.a );
|
||||
auto tB = impl::getTransform( *constraint.b );
|
||||
|
||||
auto axis = uf::vector::normalize( a);
|
||||
auto tangent = uf::vector::normalize( impl::computeTangent(axis) );
|
||||
|
||||
auto invqA = uf::quaternion::inverse( tA.orientation );
|
||||
auto invqB = uf::quaternion::inverse( tB.orientation );
|
||||
|
||||
auto& joint = constraint.slider;
|
||||
constraint.type = pod::ConstraintType::SLIDER;
|
||||
joint.localAnchorA = uf::transform::applyInverse( tA, p );
|
||||
joint.localAnchorB = uf::transform::applyInverse( tB, p );
|
||||
|
||||
joint.localAxisA = uf::quaternion::rotate( invqA, axis );
|
||||
joint.localAxisB = uf::quaternion::rotate( invqB, axis );
|
||||
|
||||
joint.localReferenceAxisA = uf::quaternion::rotate( invqA, tangent );
|
||||
joint.localReferenceAxisB = uf::quaternion::rotate( invqB, tangent );
|
||||
|
||||
joint.lowerLimit = lowerLimit;
|
||||
joint.upperLimit = upperLimit;
|
||||
|
||||
joint.accumulatedLinearImpulse = {};
|
||||
joint.accumulatedAngularImpulse = {};
|
||||
joint.accumulatedLimitImpulse = 0.0f;
|
||||
|
||||
return constraint;
|
||||
}
|
||||
@ -33,12 +33,29 @@ void impl::solveSpringConstraint( pod::Constraint& constraint, float dt ) {
|
||||
if ( invMassN < EPS ) return;
|
||||
|
||||
float gamma = joint.damping + (dt * joint.stiffness);
|
||||
gamma = (gamma > EPS) ? (1.0f / (dt * gamma)) : 0.0f;
|
||||
gamma = (gamma > EPS) ? (1.0f / (dt * gamma)) : 0.0f;
|
||||
|
||||
float beta = dt * joint.stiffness * gamma;
|
||||
|
||||
float bias = distanceError * (beta / dt);
|
||||
float j = -(relVelAlongNormal + bias + (gamma * joint.accumulatedImpulse)) / (invMassN + gamma);
|
||||
float j = -(relVelAlongNormal + bias + (gamma * joint.accumulatedImpulse)) / (invMassN + gamma);
|
||||
|
||||
impl::applyImpulseTo( a, b, rA, rB, normal, j, joint.accumulatedImpulse );
|
||||
}
|
||||
|
||||
pod::Constraint& uf::physics::constrainSpring( pod::Constraint& constraint, const pod::Vector3f& pA, const pod::Vector3f& pB, float stiffness, float damping ) {
|
||||
auto tA = impl::getTransform( *constraint.a );
|
||||
auto tB = impl::getTransform( *constraint.b );
|
||||
|
||||
auto& joint = constraint.spring;
|
||||
constraint.type = pod::ConstraintType::SPRING;
|
||||
joint.localAnchorA = uf::transform::applyInverse( tA, pA );
|
||||
joint.localAnchorB = uf::transform::applyInverse( tB, pB );
|
||||
|
||||
joint.restLength = uf::vector::distance( pB, pA );
|
||||
joint.stiffness = stiffness;
|
||||
joint.damping = damping;
|
||||
joint.accumulatedImpulse = 0.0f;
|
||||
|
||||
return constraint;
|
||||
}
|
||||
@ -42,6 +42,33 @@ void impl::solveWeldConstraint( pod::Constraint& constraint, float dt ) {
|
||||
|
||||
joint.accumulatedAngularImpulse += impulse;
|
||||
|
||||
if ( !a.isStatic ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulse );
|
||||
if ( !b.isStatic ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulse );
|
||||
if ( a.inverseMass != 0.0f ) a.angularVelocity -= uf::matrix::multiply( ctxA.invI, impulse );
|
||||
if ( b.inverseMass != 0.0f ) b.angularVelocity += uf::matrix::multiply( ctxB.invI, impulse );
|
||||
}
|
||||
|
||||
pod::Constraint& uf::physics::constrainWeld( pod::Constraint& constraint, const pod::Vector3f& p, const pod::Vector3f& a ) {
|
||||
auto tA = impl::getTransform( *constraint.a );
|
||||
auto tB = impl::getTransform( *constraint.b );
|
||||
|
||||
auto axis = uf::vector::normalize( a );
|
||||
auto tangent = uf::vector::normalize( impl::computeTangent(axis) );
|
||||
|
||||
auto invqA = uf::quaternion::inverse( tA.orientation );
|
||||
auto invqB = uf::quaternion::inverse( tB.orientation );
|
||||
|
||||
auto& joint = constraint.weld;
|
||||
constraint.type = pod::ConstraintType::WELD;
|
||||
joint.localAnchorA = uf::transform::applyInverse( tA, p );
|
||||
joint.localAnchorB = uf::transform::applyInverse( tB, p );
|
||||
|
||||
joint.localAxisA = uf::quaternion::rotate( invqA, axis );
|
||||
joint.localAxisB = uf::quaternion::rotate( invqB, axis );
|
||||
|
||||
joint.localReferenceAxisA = uf::quaternion::rotate( invqA, tangent );
|
||||
joint.localReferenceAxisB = uf::quaternion::rotate( invqB, tangent );
|
||||
|
||||
joint.accumulatedLinearImpulse = {};
|
||||
joint.accumulatedAngularImpulse = {};
|
||||
|
||||
return constraint;
|
||||
}
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
#include <uf/engine/scene/scene.h>
|
||||
|
||||
#define UF_PHYSICS_TEST 0
|
||||
#define UF_PHYSICS_TEST 1
|
||||
|
||||
pod::PhysicsSettings uf::physics::settings;
|
||||
|
||||
@ -215,13 +215,12 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
}
|
||||
|
||||
for ( auto* b : bodies ) {
|
||||
if ( b->isStatic ) continue;
|
||||
if ( b->inverseMass == 0.0f ) continue;
|
||||
impl::snapVelocity( *b, dt );
|
||||
}
|
||||
}
|
||||
|
||||
void uf::physics::setMass( pod::PhysicsBody& body, float mass ) {
|
||||
body.mass = mass;
|
||||
body.inverseMass = 1.0f / mass;
|
||||
uf::physics::updateInertia( body );
|
||||
}
|
||||
@ -264,29 +263,30 @@ pod::Vector3f uf::physics::getGravity( pod::PhysicsBody& body ) {
|
||||
}
|
||||
|
||||
void uf::physics::updateInertia( pod::PhysicsBody& body ) {
|
||||
if ( body.isStatic || body.mass <= 0 ) {
|
||||
if ( body.inverseMass == 0.0f ) {
|
||||
body.inverseInertiaTensor = { 0.0f, 0.0f, 0.0f };
|
||||
return;
|
||||
}
|
||||
|
||||
float mass = 1.0f / body.inverseMass;
|
||||
pod::Vector3f inertiaTensor = {};
|
||||
switch ( body.collider.type ) {
|
||||
case pod::ShapeType::AABB: {
|
||||
pod::Vector3f dims = (body.collider.aabb.max - body.collider.aabb.min);
|
||||
pod::Vector3f dimsSq = dims * dims;
|
||||
inertiaTensor = pod::Vector3f{ dimsSq.y + dimsSq.z, dimsSq.x + dimsSq.z, dimsSq.x + dimsSq.y } * (body.mass / 12.0f);
|
||||
inertiaTensor = pod::Vector3f{ dimsSq.y + dimsSq.z, dimsSq.x + dimsSq.z, dimsSq.x + dimsSq.y } * (mass / 12.0f);
|
||||
inertiaTensor = uf::vector::max( inertiaTensor, { EPS, EPS, EPS } );
|
||||
body.inverseInertiaTensor = 1.0f / inertiaTensor;
|
||||
} break;
|
||||
case pod::ShapeType::OBB: {
|
||||
pod::Vector3f dims = body.collider.obb.extent * 2.0f;
|
||||
pod::Vector3f dimsSq = dims * dims;
|
||||
inertiaTensor = pod::Vector3f{ dimsSq.y + dimsSq.z, dimsSq.x + dimsSq.z, dimsSq.x + dimsSq.y } * (body.mass / 12.0f);
|
||||
inertiaTensor = pod::Vector3f{ dimsSq.y + dimsSq.z, dimsSq.x + dimsSq.z, dimsSq.x + dimsSq.y } * (mass / 12.0f);
|
||||
inertiaTensor = uf::vector::max( inertiaTensor, { EPS, EPS, EPS } );
|
||||
body.inverseInertiaTensor = 1.0f / inertiaTensor;
|
||||
} break;
|
||||
case pod::ShapeType::SPHERE: {
|
||||
float I = 0.4f * body.mass * body.collider.sphere.radius * body.collider.sphere.radius;
|
||||
float I = 0.4f * mass * body.collider.sphere.radius * body.collider.sphere.radius;
|
||||
float invI = 1.0f / I;
|
||||
inertiaTensor = { I, I, I };
|
||||
body.inverseInertiaTensor = { invI, invI, invI };
|
||||
@ -294,10 +294,9 @@ void uf::physics::updateInertia( pod::PhysicsBody& body ) {
|
||||
case pod::ShapeType::CAPSULE: {
|
||||
float r = body.collider.capsule.radius;
|
||||
float h = body.collider.capsule.halfHeight * 2.0f; // full cyl height
|
||||
float m = body.mass;
|
||||
|
||||
float Ixx = 0.25f * m * r * r + (1.0f/12.0f) * m * h * h;
|
||||
float Iyy = 0.5f * m * r * r;
|
||||
float Ixx = 0.25f * mass * r * r + (1.0f/12.0f) * mass * h * h;
|
||||
float Iyy = 0.5f * mass * r * r;
|
||||
float Izz = Ixx;
|
||||
|
||||
inertiaTensor = { Ixx, Iyy, Izz };
|
||||
@ -310,7 +309,7 @@ void uf::physics::updateInertia( pod::PhysicsBody& body ) {
|
||||
#if 1
|
||||
pod::Vector3f dims = (body.bounds.max - body.bounds.min);
|
||||
pod::Vector3f dimsSq = dims * dims;
|
||||
inertiaTensor = pod::Vector3f{ dimsSq.y + dimsSq.z, dimsSq.x + dimsSq.z, dimsSq.x + dimsSq.y } * (body.mass / 12.0f);
|
||||
inertiaTensor = pod::Vector3f{ dimsSq.y + dimsSq.z, dimsSq.x + dimsSq.z, dimsSq.x + dimsSq.y } * (mass / 12.0f);
|
||||
inertiaTensor = uf::vector::max( inertiaTensor, { EPS, EPS, EPS } );
|
||||
body.inverseInertiaTensor = 1.0f / inertiaTensor;
|
||||
#else
|
||||
@ -336,7 +335,7 @@ void uf::physics::updateInertia( pod::PhysicsBody& body ) {
|
||||
const auto& box = bvh.bounds[i];
|
||||
|
||||
auto extents = box.max - box.min;
|
||||
float mass = body.mass * extents.x * extents.y * extents.z / totalVolume;
|
||||
float mass = mass * extents.x * extents.y * extents.z / totalVolume;
|
||||
|
||||
// inertia tensor of a box about its center
|
||||
float x2 = extents.x * extents.x;
|
||||
@ -370,12 +369,12 @@ void uf::physics::updateInertia( pod::PhysicsBody& body ) {
|
||||
}
|
||||
}
|
||||
void uf::physics::applyForce( pod::PhysicsBody& body, const pod::Vector3f& force ) {
|
||||
if ( body.isStatic ) return;
|
||||
if ( body.inverseMass == 0.0f ) return;
|
||||
impl::wakeBody( body );
|
||||
body.forceAccumulator += force;
|
||||
}
|
||||
void uf::physics::applyForceAtPoint( pod::PhysicsBody& body, const pod::Vector3f& force, const pod::Vector3f& point ) {
|
||||
if ( body.isStatic ) return;
|
||||
if ( body.inverseMass == 0.0f ) return;
|
||||
impl::wakeBody( body );
|
||||
// linear force
|
||||
body.forceAccumulator += force;
|
||||
@ -384,11 +383,11 @@ void uf::physics::applyForceAtPoint( pod::PhysicsBody& body, const pod::Vector3f
|
||||
body.torqueAccumulator += uf::vector::cross( r, force );
|
||||
}
|
||||
void uf::physics::applyImpulse( pod::PhysicsBody& body, const pod::Vector3f& impulse ) {
|
||||
if ( body.isStatic ) return; impl::wakeBody( body );
|
||||
if ( body.inverseMass == 0.0f ) return; impl::wakeBody( body );
|
||||
body.velocity += impulse * body.inverseMass;
|
||||
}
|
||||
void uf::physics::applyTorque( pod::PhysicsBody& body, const pod::Vector3f& torque ) {
|
||||
if ( body.isStatic ) return; impl::wakeBody( body );
|
||||
if ( body.inverseMass == 0.0f ) return; impl::wakeBody( body );
|
||||
body.torqueAccumulator += torque;
|
||||
}
|
||||
void uf::physics::setVelocity( pod::PhysicsBody& body, const pod::Vector3f& v ) {
|
||||
@ -451,18 +450,29 @@ pod::World& uf::physics::getWorld() {
|
||||
|
||||
// body creation
|
||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, float mass, const pod::Vector3f& offset ) {
|
||||
// bind to component
|
||||
pod::PhysicsBody& body = object.getComponent<pod::PhysicsBody>();
|
||||
auto& root = object.getComponent<pod::PhysicsBody>();
|
||||
auto isRoot = !root.world;
|
||||
auto& body = isRoot ? root : *(new pod::PhysicsBody);
|
||||
// initial initialization
|
||||
body.world = &world;
|
||||
body.object = &object;
|
||||
body.transform/*.reference*/ = &object.getComponent<pod::Transform<>>();
|
||||
body.offset = offset;
|
||||
body.mass = mass;
|
||||
body.inverseMass = mass == 0.0f ? 0.0f : 1.0f / mass;
|
||||
body.isStatic = mass == 0.0f;
|
||||
body.collider.type = {};
|
||||
|
||||
if ( body.isStatic ) {
|
||||
// append next in chain
|
||||
int children = 0;
|
||||
if ( !isRoot ) {
|
||||
auto* current = &root;
|
||||
while ( current->next ) {
|
||||
++children;
|
||||
current = current->next;
|
||||
}
|
||||
current->next = &body;
|
||||
}
|
||||
|
||||
if ( body.inverseMass == 0.0f ) {
|
||||
uf::physics::setColliderCategory(body, "STATIC");
|
||||
uf::physics::setColliderMask(body, "STATIC");
|
||||
world.staticBvh.dirty = true; // mark as dirty
|
||||
@ -472,23 +482,29 @@ pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, fl
|
||||
world.dynamicBvh.dirty = true; // mark as dirty
|
||||
}
|
||||
|
||||
world.bodies.emplace_back(&body); // insert into world
|
||||
// insert into world if not already inserted
|
||||
if ( std::find( world.bodies.begin(), world.bodies.end(), &body ) == world.bodies.end() ) {
|
||||
world.bodies.emplace_back( &body );
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( uf::Object& object, float mass, const pod::Vector3f& offset ) {
|
||||
// bind to scene
|
||||
// auto& root = object.getRootParent<>(); // in the event a scene is being initialized that is not the root scene, use the root parent instead
|
||||
// auto& world = root.getComponent<pod::World>();
|
||||
return create( getWorld(), object, mass, offset );
|
||||
|
||||
}
|
||||
|
||||
void uf::physics::destroy( uf::Object& object ) {
|
||||
if ( !object.hasComponent<pod::PhysicsBody>() ) return;
|
||||
|
||||
return destroy( object.getComponent<pod::PhysicsBody>() );
|
||||
auto& root = object.getComponent<pod::PhysicsBody>();
|
||||
auto* current = &root;
|
||||
while ( current != NULL ) {
|
||||
auto* next = current->next;
|
||||
uf::physics::destroy( *current );
|
||||
if ( current != &root ) delete current;
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
void uf::physics::destroy( pod::PhysicsBody& body ) {
|
||||
auto& world = *body.world;
|
||||
@ -511,42 +527,6 @@ void uf::physics::destroy( pod::PhysicsBody& body ) {
|
||||
}
|
||||
}
|
||||
|
||||
pod::Constraint& uf::physics::constrain( pod::World& world, pod::PhysicsBody& a, pod::PhysicsBody& b ) {
|
||||
// allocate constraint struct (pointer cringe because the vector WILL resize)
|
||||
auto* pointer = world.constraints.emplace_back(new pod::Constraint);
|
||||
auto& constraint = *pointer;
|
||||
constraint.a = &a;
|
||||
constraint.b = &b;
|
||||
return constraint;
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( pod::World& world, uf::Object& a, uf::Object& b ) {
|
||||
return constrain( world, a.getComponent<pod::PhysicsBody>(), b.getComponent<pod::PhysicsBody>() );
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( pod::PhysicsBody& a, pod::PhysicsBody& b ) {
|
||||
return constrain( getWorld(), a, b );
|
||||
}
|
||||
pod::Constraint& uf::physics::constrain( uf::Object& a, uf::Object& b ) {
|
||||
return constrain( getWorld(), a.getComponent<pod::PhysicsBody>(), b.getComponent<pod::PhysicsBody>() );
|
||||
}
|
||||
|
||||
void uf::physics::unconstrain( pod::PhysicsBody& body ) {
|
||||
auto& world = *body.world;
|
||||
auto& constraints = world.constraints;
|
||||
// remove all constraints that reference this body
|
||||
for ( auto it = constraints.begin(); it != constraints.end(); ) {
|
||||
auto* constraint = *it;
|
||||
if ( constraint->a == &body || constraint->b == &body ) {
|
||||
it = constraints.erase(it);
|
||||
delete constraint;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
void uf::physics::unconstrain( uf::Object& object ) {
|
||||
return unconstrain( object.getComponent<pod::PhysicsBody>() );
|
||||
}
|
||||
|
||||
#if UF_PHYSICS_TEST
|
||||
#include "tests.inl"
|
||||
#endif
|
||||
@ -4,7 +4,7 @@
|
||||
#include <uf/utils/math/physics/narrowphase.h>
|
||||
|
||||
pod::SolverBodyContext impl::solverBodyContext( const pod::PhysicsBody& body ) {
|
||||
return { body.isStatic ? 0.0f : body.inverseMass, impl::computeWorldInverseInertia( body ) };
|
||||
return { body.inverseMass == 0.0f ? 0.0f : body.inverseMass, impl::computeWorldInverseInertia( body ) };
|
||||
}
|
||||
|
||||
float impl::computeEffectiveMass( const pod::SolverBodyContext& a, const pod::SolverBodyContext& b, const pod::JacobianRow& row ) {
|
||||
@ -60,24 +60,24 @@ float impl::computeAngularMassMatrixLine( const pod::SolverBodyContext& a, const
|
||||
}
|
||||
|
||||
void impl::applyImpulseTo( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& rA, const pod::Vector3f& rB, const pod::Vector3f& impulse ) {
|
||||
if ( !a.isStatic ) {
|
||||
if ( a.inverseMass != 0.0f ) {
|
||||
a.velocity -= impulse * a.inverseMass;
|
||||
pod::Matrix3f invIa = impl::computeWorldInverseInertia( a );
|
||||
a.angularVelocity -= uf::matrix::multiply( invIa, uf::vector::cross(rA, impulse) );
|
||||
}
|
||||
if ( !b.isStatic ) {
|
||||
if ( b.inverseMass != 0.0f ) {
|
||||
b.velocity += impulse * b.inverseMass;
|
||||
pod::Matrix3f invIb = impl::computeWorldInverseInertia( b );
|
||||
b.angularVelocity += uf::matrix::multiply( invIb, uf::vector::cross(rB, impulse) );
|
||||
}
|
||||
}
|
||||
void impl::applyPseudoImpulseTo( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& rA, const pod::Vector3f& rB, const pod::Vector3f& impulse ) {
|
||||
if ( !a.isStatic ) {
|
||||
if ( a.inverseMass != 0.0f ) {
|
||||
a.pseudoVelocity -= impulse * a.inverseMass;
|
||||
pod::Matrix3f invIa = impl::computeWorldInverseInertia( a );
|
||||
a.pseudoAngularVelocity -= uf::matrix::multiply( invIa, uf::vector::cross(rA, impulse) );
|
||||
}
|
||||
if ( !b.isStatic ) {
|
||||
if ( b.inverseMass != 0.0f ) {
|
||||
b.pseudoVelocity += impulse * b.inverseMass;
|
||||
pod::Matrix3f invIb = impl::computeWorldInverseInertia( b );
|
||||
b.pseudoAngularVelocity += uf::matrix::multiply( invIb, uf::vector::cross(rB, impulse) );
|
||||
@ -155,7 +155,7 @@ pod::Vector3f impl::accumulateImpulseTo(
|
||||
}
|
||||
|
||||
void impl::applyRollingResistance( pod::PhysicsBody& body, float dt ) {
|
||||
if ( body.isStatic ) return;
|
||||
if ( body.inverseMass == 0.0f ) return;
|
||||
|
||||
float rollingFriction = 0.02f; // to-do: derive from material
|
||||
float angularSpeed2 = uf::vector::magnitude( body.angularVelocity );
|
||||
@ -183,7 +183,7 @@ void impl::snapVelocity( pod::PhysicsBody& body, float dt, float threshold ) {
|
||||
|
||||
void impl::integrate( pod::PhysicsBody& body, float dt ) {
|
||||
// only integrate awake and dynamic bodies
|
||||
if ( !body.activity.awake || body.isStatic || body.mass == 0 ) return;
|
||||
if ( !body.activity.awake || body.inverseMass == 0.0f ) return;
|
||||
|
||||
auto& world = *body.world;
|
||||
|
||||
|
||||
@ -99,15 +99,11 @@ void impl::drawAabb( const pod::PhysicsBody& body ) {
|
||||
impl::addLine( corners[2], corners[6] ); impl::addLine( corners[3], corners[7] );
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, const pod::AABB& aabb, float mass, const pod::Vector3f& offset ) {
|
||||
auto& body = uf::physics::create( world, object, mass, offset );
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::AABB& aabb ) {
|
||||
body.collider.type = pod::ShapeType::AABB;
|
||||
body.collider.aabb = aabb;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
|
||||
uf::physics::updateInertia( body );
|
||||
return body;
|
||||
}
|
||||
pod::PhysicsBody& uf::physics::create( uf::Object& object, const pod::AABB& aabb, float mass, const pod::Vector3f& offset ) {
|
||||
return create( uf::physics::getWorld(), object, aabb, mass, offset );
|
||||
}
|
||||
@ -129,15 +129,10 @@ void impl::drawCapsule( const pod::PhysicsBody& body ) {
|
||||
impl::addLine( p2 + forwardOffset, p2 - forwardOffset );
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, const pod::Capsule& capsule, float mass, const pod::Vector3f& offset ) {
|
||||
auto& body = uf::physics::create( world, object, mass, offset );
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::Capsule& capsule ) {
|
||||
body.collider.type = pod::ShapeType::CAPSULE;
|
||||
body.collider.capsule = capsule;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
return body;
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( uf::Object& object, const pod::Capsule& capsule, float mass, const pod::Vector3f& offset ) {
|
||||
return create( uf::physics::getWorld(), object, capsule, mass, offset );
|
||||
}
|
||||
@ -204,8 +204,7 @@ void impl::drawMesh( const pod::PhysicsBody& body ) {
|
||||
}
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, const uf::Mesh& mesh, float mass, const pod::Vector3f& offset, bool convex ) {
|
||||
auto& body = uf::physics::create( world, object, mass, offset );
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const uf::Mesh& mesh, bool convex ) {
|
||||
if ( !convex ) {
|
||||
body.collider.type = pod::ShapeType::MESH;
|
||||
body.collider.mesh.mesh = &mesh;
|
||||
@ -225,7 +224,4 @@ pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, co
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
return body;
|
||||
}
|
||||
pod::PhysicsBody& uf::physics::create( uf::Object& object, const uf::Mesh& mesh, float mass, const pod::Vector3f& offset, bool convex ) {
|
||||
return create( uf::physics::getWorld(), object, mesh, mass, offset, convex );
|
||||
}
|
||||
@ -323,16 +323,11 @@ void impl::drawObb( const pod::PhysicsBody& body ) {
|
||||
impl::addLine( corners[2], corners[6] ); impl::addLine( corners[3], corners[7] );
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, const pod::OBB& obb, float mass, const pod::Vector3f& offset ) {
|
||||
auto& body = uf::physics::create( world, object, mass, offset );
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::OBB& obb ) {
|
||||
body.collider.type = pod::ShapeType::OBB;
|
||||
body.collider.obb = obb;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
|
||||
uf::physics::updateInertia( body );
|
||||
return body;
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( uf::Object& object, const pod::OBB& obb, float mass, const pod::Vector3f& offset ) {
|
||||
return create( uf::physics::getWorld(), object, obb, mass, offset );
|
||||
}
|
||||
@ -87,15 +87,10 @@ void impl::drawPlane( const pod::PhysicsBody& body ) {
|
||||
impl::addLine( p1, p3 );
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, const pod::Plane& plane, float mass, const pod::Vector3f& offset ) {
|
||||
auto& body = uf::physics::create( world, object, mass, offset );
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::Plane& plane ) {
|
||||
body.collider.type = pod::ShapeType::PLANE;
|
||||
body.collider.plane = plane;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
return body;
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( uf::Object& object, const pod::Plane& plane, float mass, const pod::Vector3f& offset ) {
|
||||
return create( uf::physics::getWorld(), object, plane, mass, offset );
|
||||
}
|
||||
@ -100,15 +100,10 @@ void impl::drawSphere( const pod::PhysicsBody& body ) {
|
||||
}
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, const pod::Sphere& sphere, float mass, const pod::Vector3f& offset ) {
|
||||
auto& body = uf::physics::create( world, object, mass, offset );
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::Sphere& sphere ) {
|
||||
body.collider.type = pod::ShapeType::SPHERE;
|
||||
body.collider.sphere = sphere;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
return body;
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( uf::Object& object, const pod::Sphere& sphere, float mass, const pod::Vector3f& offset ) {
|
||||
return create( uf::physics::getWorld(), object, sphere, mass, offset );
|
||||
}
|
||||
@ -368,8 +368,7 @@ void impl::drawTriangle( const pod::PhysicsBody& body ) {
|
||||
impl::addLine( v2, v0 );
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, const pod::TriangleWithNormal& tri, float mass, const pod::Vector3f& offset ) {
|
||||
auto& body = uf::physics::create( world, object, mass, offset );
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::TriangleWithNormal& tri ) {
|
||||
body.collider.type = pod::ShapeType::TRIANGLE;
|
||||
body.collider.triangle = tri;
|
||||
if ( uf::vector::magnitude( body.collider.triangle.normal ) < 0.001f ) {
|
||||
@ -378,8 +377,4 @@ pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, co
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
return body;
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::create( uf::Object& object, const pod::TriangleWithNormal& triangle, float mass, const pod::Vector3f& offset ) {
|
||||
return create( uf::physics::getWorld(), object, triangle, mass, offset );
|
||||
}
|
||||
@ -6,10 +6,8 @@
|
||||
namespace impl {
|
||||
template<size_t N, typename T = float>
|
||||
bool blockNxNSolver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
|
||||
pod::Matrix<T,N> K = {};
|
||||
|
||||
auto ctxA = pod::SolverBodyContext{ a.isStatic ? 0.0f : a.inverseMass, impl::computeWorldInverseInertia(a) };
|
||||
auto ctxB = pod::SolverBodyContext{ b.isStatic ? 0.0f : b.inverseMass, impl::computeWorldInverseInertia(b) };
|
||||
auto ctxA = impl::solverBodyContext( a );
|
||||
auto ctxB = impl::solverBodyContext( b );
|
||||
|
||||
auto pA = impl::getPosition( a, true );
|
||||
auto pB = impl::getPosition( b, true );
|
||||
@ -18,13 +16,14 @@ namespace impl {
|
||||
auto gB = uf::physics::getGravity( b );
|
||||
float vSlop = std::sqrt( std::max( uf::vector::magnitude( gA ), uf::vector::magnitude( gB ) ) ) * dt;
|
||||
|
||||
pod::Matrix<T,N> K = {};
|
||||
for ( auto i = 0; i < N; i++ ) {
|
||||
auto& pI = manifold.points[i];
|
||||
auto rowI = pod::JacobianRow{ pI.point - pA, pI.point - pB, pI.normal };
|
||||
auto& cI = manifold.points[i];
|
||||
auto rowI = pod::JacobianRow{ cI.point - pA, cI.point - pB, cI.normal };
|
||||
|
||||
for ( auto j = 0; j < N; j++ ) {
|
||||
auto& pJ = manifold.points[j];
|
||||
auto rowJ = pod::JacobianRow{ pJ.point - pA, pJ.point - pB, pJ.normal };
|
||||
auto& cJ = manifold.points[j];
|
||||
auto rowJ = pod::JacobianRow{ cJ.point - pA, cJ.point - pB, cJ.normal };
|
||||
K(i,j) = impl::computeMassMatrixLine( ctxA, ctxB, rowI, rowJ );
|
||||
}
|
||||
|
||||
@ -94,8 +93,8 @@ namespace impl {
|
||||
|
||||
for ( auto i = 0; i < N; i++ ) {
|
||||
auto& contact = manifold.points[i];
|
||||
pod::Vector3f rA = manifold.points[i].point - pA;
|
||||
pod::Vector3f rB = manifold.points[i].point - pB;
|
||||
pod::Vector3f rA = contact.point - pA;
|
||||
pod::Vector3f rB = contact.point - pB;
|
||||
|
||||
// normal impulse
|
||||
{
|
||||
|
||||
@ -4,17 +4,16 @@
|
||||
#include <uf/utils/math/physics/solvers/iterativeImpulse.h>
|
||||
|
||||
void impl::iterativeImpulseSolver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Contact& contact, float dt ) {
|
||||
pod::Vector3f rA = contact.point - impl::getPosition( a, true );
|
||||
pod::Vector3f rB = contact.point - impl::getPosition( b, true );
|
||||
auto rA = contact.point - impl::getPosition( a, true );
|
||||
auto rB = contact.point - impl::getPosition( b, true );
|
||||
|
||||
float invMassN = impl::computeEffectiveMass(a, b, rA, rB, contact.normal);
|
||||
|
||||
|
||||
// normal impulse
|
||||
{
|
||||
pod::Vector3f vA = a.velocity + uf::vector::cross(a.angularVelocity, rA);
|
||||
pod::Vector3f vB = b.velocity + uf::vector::cross(b.angularVelocity, rB);
|
||||
pod::Vector3f rv = vB - vA;
|
||||
auto vA = a.velocity + uf::vector::cross(a.angularVelocity, rA);
|
||||
auto vB = b.velocity + uf::vector::cross(b.angularVelocity, rB);
|
||||
auto rv = vB - vA;
|
||||
|
||||
auto gA = uf::physics::getGravity( a );
|
||||
auto gB = uf::physics::getGravity( b );
|
||||
@ -34,8 +33,8 @@ void impl::iterativeImpulseSolver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod
|
||||
float penetrationBias = std::max(contact.penetration - uf::physics::settings.baumgarteCorrectionSlop, 0.0f) * (uf::physics::settings.baumgarteCorrectionPercent / dt);
|
||||
penetrationBias = std::min(penetrationBias, uf::physics::settings.maxLinearCorrection / dt);
|
||||
|
||||
pod::Vector3f pseudoVa = a.pseudoVelocity + uf::vector::cross(a.pseudoAngularVelocity, rA);
|
||||
pod::Vector3f pseudoVb = b.pseudoVelocity + uf::vector::cross(b.pseudoAngularVelocity, rB);
|
||||
auto pseudoVa = a.pseudoVelocity + uf::vector::cross(a.pseudoAngularVelocity, rA);
|
||||
auto pseudoVb = b.pseudoVelocity + uf::vector::cross(b.pseudoAngularVelocity, rB);
|
||||
float pseudoVelAlongNormal = uf::vector::dot(pseudoVb - pseudoVa, contact.normal);
|
||||
|
||||
float jP = (penetrationBias - pseudoVelAlongNormal) / invMassN;
|
||||
@ -43,10 +42,10 @@ void impl::iterativeImpulseSolver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod
|
||||
}
|
||||
// tangent friction
|
||||
{
|
||||
pod::Vector3f vA = a.velocity + uf::vector::cross(a.angularVelocity, rA);
|
||||
pod::Vector3f vB = b.velocity + uf::vector::cross(b.angularVelocity, rB);
|
||||
pod::Vector3f rv = vB - vA;
|
||||
pod::Vector3f tangent = rv - contact.normal * uf::vector::dot(rv, contact.normal);
|
||||
auto vA = a.velocity + uf::vector::cross(a.angularVelocity, rA);
|
||||
auto vB = b.velocity + uf::vector::cross(b.angularVelocity, rB);
|
||||
auto rv = vB - vA;
|
||||
auto tangent = rv - contact.normal * uf::vector::dot(rv, contact.normal);
|
||||
float tMag2 = uf::vector::magnitude(tangent);
|
||||
if ( tMag2 > EPS2 ) {
|
||||
contact.tangent = tangent / std::sqrt( tMag2 );
|
||||
|
||||
@ -12,7 +12,7 @@ void impl::solvePositions( uf::stl::vector<pod::Manifold>& manifolds, float dt,
|
||||
auto tA = impl::getTransform( a );
|
||||
auto tB = impl::getTransform( b );
|
||||
|
||||
if ( a.isStatic && b.isStatic ) continue;
|
||||
if ( a.inverseMass == 0.0f && b.inverseMass == 0.0f ) continue;
|
||||
|
||||
for ( auto& c : manifold.points ) {
|
||||
auto ctxA = impl::solverBodyContext( a );
|
||||
|
||||
@ -28,18 +28,27 @@ namespace impl {
|
||||
}
|
||||
}
|
||||
|
||||
// cringe wrapper because i changed the api again
|
||||
namespace uf {
|
||||
namespace physics {
|
||||
template<typename T> pod::PhysicsBody& create( pod::World& world, uf::Object& object, const T& shape, float mass, const pod::Vector3f& center = {} ) {
|
||||
auto& body = uf::physics::create( world, object, mass, center );
|
||||
return uf::physics::initialize( body, shape );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// list of unit tests to "standardly" verify the system works, but honestly this is a mess
|
||||
// to-do: clean up all of this
|
||||
|
||||
TEST(SphereSphere_Collision, {
|
||||
pod::World world;
|
||||
uf::Object objA, objB;
|
||||
|
||||
auto& bodyA = uf::physics::create(world, objA, pod::Sphere{1.0f}, 1.0f);
|
||||
auto& bodyB = uf::physics::create(world, objB, pod::Sphere{1.0f}, 1.0f);
|
||||
|
||||
bodyA.transform->position = {0,0,0};
|
||||
bodyB.transform->position = {1.5f,0,0}; // closer than sum of radii (2.0)
|
||||
bodyA.transform->position = {};
|
||||
bodyB.transform->position.x = 1.5f;
|
||||
|
||||
bodyA.bounds = impl::computeAABB( bodyA );
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
@ -59,8 +68,8 @@ TEST(AabbAabb_Collision, {
|
||||
auto& bodyA = uf::physics::create(world, objA, box, 1.0f);
|
||||
auto& bodyB = uf::physics::create(world, objB, box, 1.0f);
|
||||
|
||||
bodyA.transform->position = {0,0,0};
|
||||
bodyB.transform->position = {1.5f,0,0}; // overlap in x-axis
|
||||
bodyA.transform->position = {};
|
||||
bodyB.transform->position.x = 1.5f;
|
||||
|
||||
bodyA.bounds = impl::computeAABB( bodyA );
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
@ -939,7 +948,7 @@ TEST(TriangleTriangle_Collision_SimpleOverlap, {
|
||||
};
|
||||
|
||||
auto& bodyA = uf::physics::create( world, objA, triA, 0.0f );
|
||||
auto& bodyB = uf::physics::create( world, objA, triB, 0.0f );
|
||||
auto& bodyB = uf::physics::create( world, objB, triB, 0.0f );
|
||||
|
||||
bodyA.bounds = impl::computeAABB( bodyA );
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
Loading…
Reference in New Issue
Block a user