From 6deb8795c5cecec9d34871929c870f872a587dbf Mon Sep 17 00:00:00 2001 From: ecker Date: Fri, 22 May 2026 20:19:28 -0500 Subject: [PATCH] even more inane code cleanup, more lua bindings, multiple bodies for an entity (doesn't work?), ragdoll (doesn't work) --- bin/data/config.json | 2 +- bin/data/entities/ragdoll.json | 18 ++ bin/data/entities/scripts/craeture.lua | 2 +- bin/data/entities/scripts/door.lua | 2 +- bin/data/entities/scripts/player.lua | 25 +- bin/data/entities/scripts/ragdoll.lua | 73 ++++++ .../scenes/sourceengine/mds_mcdonalds.json | 2 +- .../inc/uf/utils/math/physics/constraints.h | 9 + .../math/physics/constraints/ballSocket.h | 5 +- .../math/physics/constraints/coneTwist.h | 5 +- .../utils/math/physics/constraints/distance.h | 8 +- .../uf/utils/math/physics/constraints/hinge.h | 5 +- .../uf/utils/math/physics/constraints/motor.h | 7 + .../utils/math/physics/constraints/slider.h | 10 +- .../utils/math/physics/constraints/spring.h | 10 +- .../uf/utils/math/physics/constraints/weld.h | 10 +- engine/inc/uf/utils/math/physics/impl.h | 8 - .../uf/utils/math/physics/narrowphase/aabb.h | 3 +- .../utils/math/physics/narrowphase/capsule.h | 3 +- .../uf/utils/math/physics/narrowphase/mesh.h | 3 +- .../uf/utils/math/physics/narrowphase/obb.h | 3 +- .../uf/utils/math/physics/narrowphase/plane.h | 3 +- .../utils/math/physics/narrowphase/sphere.h | 3 +- .../utils/math/physics/narrowphase/triangle.h | 3 +- engine/inc/uf/utils/math/physics/structs.h | 8 +- .../src/engine/ext/region/chunk/behavior.cpp | 2 +- engine/src/engine/graph/graph.cpp | 39 ++- engine/src/engine/object/behavior.cpp | 55 ++-- engine/src/ext/lua/lua.cpp | 10 + engine/src/ext/lua/usertypes/mesh.cpp | 15 ++ engine/src/ext/lua/usertypes/physics.cpp | 246 +++++++++++++++--- .../src/utils/math/physics/broadphase/bvh.cpp | 2 +- .../utils/math/physics/broadphase/island.cpp | 14 +- engine/src/utils/math/physics/common.cpp | 6 +- engine/src/utils/math/physics/constraints.cpp | 38 +++ .../math/physics/constraints/ballSocket.cpp | 27 +- .../math/physics/constraints/coneTwist.cpp | 65 ++--- .../math/physics/constraints/distance.cpp | 16 ++ .../utils/math/physics/constraints/hinge.cpp | 38 +-- .../utils/math/physics/constraints/motor.cpp | 15 +- .../utils/math/physics/constraints/slider.cpp | 35 ++- .../utils/math/physics/constraints/spring.cpp | 21 +- .../utils/math/physics/constraints/weld.cpp | 31 ++- engine/src/utils/math/physics/impl.cpp | 106 +++----- engine/src/utils/math/physics/integration.cpp | 14 +- .../utils/math/physics/narrowphase/aabb.cpp | 6 +- .../math/physics/narrowphase/capsule.cpp | 7 +- .../utils/math/physics/narrowphase/mesh.cpp | 6 +- .../utils/math/physics/narrowphase/obb.cpp | 7 +- .../utils/math/physics/narrowphase/plane.cpp | 7 +- .../utils/math/physics/narrowphase/sphere.cpp | 7 +- .../math/physics/narrowphase/triangle.cpp | 7 +- .../src/utils/math/physics/solvers/block.cpp | 19 +- .../math/physics/solvers/iterativeImpulse.cpp | 23 +- engine/src/utils/math/physics/solvers/ngs.cpp | 2 +- engine/src/utils/math/physics/tests.inl | 21 +- 56 files changed, 731 insertions(+), 406 deletions(-) create mode 100644 bin/data/entities/ragdoll.json create mode 100644 bin/data/entities/scripts/ragdoll.lua create mode 100644 engine/src/ext/lua/usertypes/mesh.cpp diff --git a/bin/data/config.json b/bin/data/config.json index 535df121..6e6e1ad6 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -350,7 +350,7 @@ "max": 0.01 // 0.2 }, "debug draw": { - "dynamic": false + "dynamic": true }, "fixed step": true, "substeps": 4 diff --git a/bin/data/entities/ragdoll.json b/bin/data/entities/ragdoll.json new file mode 100644 index 00000000..e39f9180 --- /dev/null +++ b/bin/data/entities/ragdoll.json @@ -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 + } +} \ No newline at end of file diff --git a/bin/data/entities/scripts/craeture.lua b/bin/data/entities/scripts/craeture.lua index c1a76bb5..91e8c971 100644 --- a/bin/data/entities/scripts/craeture.lua +++ b/bin/data/entities/scripts/craeture.lua @@ -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 ) diff --git a/bin/data/entities/scripts/door.lua b/bin/data/entities/scripts/door.lua index 5772db16..24f33109 100644 --- a/bin/data/entities/scripts/door.lua +++ b/bin/data/entities/scripts/door.lua @@ -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 ) diff --git a/bin/data/entities/scripts/player.lua b/bin/data/entities/scripts/player.lua index f4a36876..c2291466 100644 --- a/bin/data/entities/scripts/player.lua +++ b/bin/data/entities/scripts/player.lua @@ -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 diff --git a/bin/data/entities/scripts/ragdoll.lua b/bin/data/entities/scripts/ragdoll.lua new file mode 100644 index 00000000..f8181a6e --- /dev/null +++ b/bin/data/entities/scripts/ragdoll.lua @@ -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 \ No newline at end of file diff --git a/bin/data/scenes/sourceengine/mds_mcdonalds.json b/bin/data/scenes/sourceengine/mds_mcdonalds.json index 1508d37c..4fc8257b 100644 --- a/bin/data/scenes/sourceengine/mds_mcdonalds.json +++ b/bin/data/scenes/sourceengine/mds_mcdonalds.json @@ -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": { diff --git a/engine/inc/uf/utils/math/physics/constraints.h b/engine/inc/uf/utils/math/physics/constraints.h index d506a5c6..001ce896 100644 --- a/engine/inc/uf/utils/math/physics/constraints.h +++ b/engine/inc/uf/utils/math/physics/constraints.h @@ -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 ); + } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/constraints/ballSocket.h b/engine/inc/uf/utils/math/physics/constraints/ballSocket.h index a3e6e45d..8c710c95 100644 --- a/engine/inc/uf/utils/math/physics/constraints/ballSocket.h +++ b/engine/inc/uf/utils/math/physics/constraints/ballSocket.h @@ -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 ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/constraints/coneTwist.h b/engine/inc/uf/utils/math/physics/constraints/coneTwist.h index 7d4bd87d..3b6edb72 100644 --- a/engine/inc/uf/utils/math/physics/constraints/coneTwist.h +++ b/engine/inc/uf/utils/math/physics/constraints/coneTwist.h @@ -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 ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/constraints/distance.h b/engine/inc/uf/utils/math/physics/constraints/distance.h index 5f27b781..d6eaa8ae 100644 --- a/engine/inc/uf/utils/math/physics/constraints/distance.h +++ b/engine/inc/uf/utils/math/physics/constraints/distance.h @@ -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 ); } } -*/ \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/constraints/hinge.h b/engine/inc/uf/utils/math/physics/constraints/hinge.h index 911fc1d7..cce8088a 100644 --- a/engine/inc/uf/utils/math/physics/constraints/hinge.h +++ b/engine/inc/uf/utils/math/physics/constraints/hinge.h @@ -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 ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/constraints/motor.h b/engine/inc/uf/utils/math/physics/constraints/motor.h index 8c1bd2b0..3cbe8ed5 100644 --- a/engine/inc/uf/utils/math/physics/constraints/motor.h +++ b/engine/inc/uf/utils/math/physics/constraints/motor.h @@ -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 ); + } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/constraints/slider.h b/engine/inc/uf/utils/math/physics/constraints/slider.h index 21311cec..09ba9c1d 100644 --- a/engine/inc/uf/utils/math/physics/constraints/slider.h +++ b/engine/inc/uf/utils/math/physics/constraints/slider.h @@ -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 ); } -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/constraints/spring.h b/engine/inc/uf/utils/math/physics/constraints/spring.h index 9d2514cf..9ce61348 100644 --- a/engine/inc/uf/utils/math/physics/constraints/spring.h +++ b/engine/inc/uf/utils/math/physics/constraints/spring.h @@ -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 ); } -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/constraints/weld.h b/engine/inc/uf/utils/math/physics/constraints/weld.h index 730ec093..dbe86ad1 100644 --- a/engine/inc/uf/utils/math/physics/constraints/weld.h +++ b/engine/inc/uf/utils/math/physics/constraints/weld.h @@ -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 ); } -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/impl.h b/engine/inc/uf/utils/math/physics/impl.h index f27bb4fb..508ec5cc 100644 --- a/engine/inc/uf/utils/math/physics/impl.h +++ b/engine/inc/uf/utils/math/physics/impl.h @@ -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& ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/aabb.h b/engine/inc/uf/utils/math/physics/narrowphase/aabb.h index 783ccacb..074f27c7 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/aabb.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/aabb.h @@ -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 ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/capsule.h b/engine/inc/uf/utils/math/physics/narrowphase/capsule.h index 7d3aba68..e57ab584 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/capsule.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/capsule.h @@ -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 ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/mesh.h b/engine/inc/uf/utils/math/physics/narrowphase/mesh.h index d63b965e..bdf3569a 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/mesh.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/mesh.h @@ -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 ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/obb.h b/engine/inc/uf/utils/math/physics/narrowphase/obb.h index 744ae5a5..bff96e9d 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/obb.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/obb.h @@ -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 ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/plane.h b/engine/inc/uf/utils/math/physics/narrowphase/plane.h index aee36712..743b8af0 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/plane.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/plane.h @@ -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 ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/sphere.h b/engine/inc/uf/utils/math/physics/narrowphase/sphere.h index a4624b40..5c33b29a 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/sphere.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/sphere.h @@ -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 ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/triangle.h b/engine/inc/uf/utils/math/physics/narrowphase/triangle.h index 0a0e1b29..1a4de851 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/triangle.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/triangle.h @@ -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 ); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/structs.h b/engine/inc/uf/utils/math/physics/structs.h index d828394e..669ad66c 100644 --- a/engine/inc/uf/utils/math/physics/structs.h +++ b/engine/inc/uf/utils/math/physics/structs.h @@ -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; } } \ No newline at end of file diff --git a/engine/src/engine/ext/region/chunk/behavior.cpp b/engine/src/engine/ext/region/chunk/behavior.cpp index 374df66b..1d6c8f72 100644 --- a/engine/src/engine/ext/region/chunk/behavior.cpp +++ b/engine/src/engine/ext/region/chunk/behavior.cpp @@ -73,7 +73,7 @@ namespace { { auto& phyziks = metadataJson["physics"]; - collider.stats.mass = phyziks["mass"].as(collider.stats.mass); + if ( phyziks["mass"].as() != 0.0f ) collider.stats.inverseMass = 1.0f / phyziks["mass"].as(); 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 ); diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 6108e181..94de8e8b 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -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(); - 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(), 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(); - 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(), 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 ); } } } diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index 30bca59c..22c36b67 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -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(); - float mass = metadataJsonPhysics["mass"].as(); + float mass = metadataJsonPhysics["mass"].as(0.0f); bool recenter = metadataJsonPhysics["recenter"].as(); - 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(); + 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(); - 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(); - 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 halfHeight = metadataJsonPhysics["height"].as() * 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::physics::setColliderCategory( body, metadataJsonPhysics["category"].as() ); + } + if ( metadataJsonPhysics["mask"].is() ){ + uf::physics::setColliderMask( body, metadataJsonPhysics["mask"].as() ); + } + uf::physics::setGravity( body, gravity ); - if ( this->hasComponent() ) { - auto& physicsBody = this->getComponent(); - - auto gravity = uf::vector::decode( metadataJsonPhysics["gravity"], physicsBody.gravity ); - - if ( metadataJsonPhysics["category"].is() ){ - uf::physics::setColliderCategory( physicsBody, metadataJsonPhysics["category"].as() ); - } - if ( metadataJsonPhysics["mask"].is() ){ - uf::physics::setColliderMask( physicsBody, metadataJsonPhysics["mask"].as() ); - } - 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() && !metadataJsonPhysics["inertia"].as() ) { - 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() && !metadataJsonPhysics["inertia"].as() ) { + body.inverseInertiaTensor = { 0.0f, 0.0f, 0.0f }; } } diff --git a/engine/src/ext/lua/lua.cpp b/engine/src/ext/lua/lua.cpp index ecffd3c3..f46a7f5f 100644 --- a/engine/src/ext/lua/lua.cpp +++ b/engine/src/ext/lua/lua.cpp @@ -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(); + physics.set("create", UF_LUA_C_FUN(::binds::physics::create)); + } // `json` table { auto json = state["json"].get_or_create(); diff --git a/engine/src/ext/lua/usertypes/mesh.cpp b/engine/src/ext/lua/usertypes/mesh.cpp new file mode 100644 index 00000000..cddee4d5 --- /dev/null +++ b/engine/src/ext/lua/usertypes/mesh.cpp @@ -0,0 +1,15 @@ +#include +#if UF_USE_LUA +#include + +namespace binds { + void updateDescriptor( uf::Mesh& self ) { + self.updateDescriptor(); + } +} + +#include +UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(uf::Mesh, + UF_LUA_REGISTER_USERTYPE_DEFINE( updateDescriptor, UF_LUA_C_FUN( ::binds::updateDescriptor ) ) +) +#endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/physics.cpp b/engine/src/ext/lua/usertypes/physics.cpp index 81c975e2..a4197759 100644 --- a/engine/src/ext/lua/usertypes/physics.cpp +++ b/engine/src/ext/lua/usertypes/physics.cpp @@ -3,59 +3,229 @@ #include 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 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 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_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 \ No newline at end of file diff --git a/engine/src/utils/math/physics/broadphase/bvh.cpp b/engine/src/utils/math/physics/broadphase/bvh.cpp index 154c6a0f..73a607eb 100644 --- a/engine/src/utils/math/physics/broadphase/bvh.cpp +++ b/engine/src/utils/math/physics/broadphase/bvh.cpp @@ -189,7 +189,7 @@ void impl::buildBroadphaseBVH( pod::BVH& bvh, const uf::stl::vectorisStatic != filterType ) continue; + if ( filters && ( bodies[i]->inverseMass == 0.0f ) != filterType ) continue; bounds[i] = bodies[i]->bounds; bvh.indices.emplace_back(i); diff --git a/engine/src/utils/math/physics/broadphase/island.cpp b/engine/src/utils/math/physics/broadphase/island.cpp index 3e7a288f..dd50c561 100644 --- a/engine/src/utils/math/physics/broadphase/island.cpp +++ b/engine/src/utils/math/physics/broadphase/island.cpp @@ -48,7 +48,7 @@ void impl::buildIslands( const pod::BVH::pairs_t& pairs, const uf::stl::vector

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

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

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

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

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 ); } } } diff --git a/engine/src/utils/math/physics/common.cpp b/engine/src/utils/math/physics/common.cpp index a28344d3..6ac3a893 100644 --- a/engine/src/utils/math/physics/common.cpp +++ b/engine/src/utils/math/physics/common.cpp @@ -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); diff --git a/engine/src/utils/math/physics/constraints.cpp b/engine/src/utils/math/physics/constraints.cpp index 02865b3c..2ab9fcd5 100644 --- a/engine/src/utils/math/physics/constraints.cpp +++ b/engine/src/utils/math/physics/constraints.cpp @@ -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; + } + } } \ No newline at end of file diff --git a/engine/src/utils/math/physics/constraints/ballSocket.cpp b/engine/src/utils/math/physics/constraints/ballSocket.cpp index 3989a1e3..3f2d0544 100644 --- a/engine/src/utils/math/physics/constraints/ballSocket.cpp +++ b/engine/src/utils/math/physics/constraints/ballSocket.cpp @@ -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(), b.getComponent(), 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(), b.getComponent(), joint ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/constraints/coneTwist.cpp b/engine/src/utils/math/physics/constraints/coneTwist.cpp index fc6d4a9b..4d90bf49 100644 --- a/engine/src/utils/math/physics/constraints/coneTwist.cpp +++ b/engine/src/utils/math/physics/constraints/coneTwist.cpp @@ -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(), b.getComponent(), 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(), b.getComponent(), joint, axis, swingLimit, twistLimit ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/constraints/distance.cpp b/engine/src/utils/math/physics/constraints/distance.cpp index 430be4d6..871f0552 100644 --- a/engine/src/utils/math/physics/constraints/distance.cpp +++ b/engine/src/utils/math/physics/constraints/distance.cpp @@ -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; } \ No newline at end of file diff --git a/engine/src/utils/math/physics/constraints/hinge.cpp b/engine/src/utils/math/physics/constraints/hinge.cpp index 8da692ba..e4cc08a4 100644 --- a/engine/src/utils/math/physics/constraints/hinge.cpp +++ b/engine/src/utils/math/physics/constraints/hinge.cpp @@ -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(), b.getComponent(), 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(), b.getComponent(), joint, axis ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/constraints/motor.cpp b/engine/src/utils/math/physics/constraints/motor.cpp index 9ff44958..c9f2c142 100644 --- a/engine/src/utils/math/physics/constraints/motor.cpp +++ b/engine/src/utils/math/physics/constraints/motor.cpp @@ -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; } \ No newline at end of file diff --git a/engine/src/utils/math/physics/constraints/slider.cpp b/engine/src/utils/math/physics/constraints/slider.cpp index 49a137fd..bd1a1bcd 100644 --- a/engine/src/utils/math/physics/constraints/slider.cpp +++ b/engine/src/utils/math/physics/constraints/slider.cpp @@ -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; } \ No newline at end of file diff --git a/engine/src/utils/math/physics/constraints/spring.cpp b/engine/src/utils/math/physics/constraints/spring.cpp index e0f03d08..ef9e270a 100644 --- a/engine/src/utils/math/physics/constraints/spring.cpp +++ b/engine/src/utils/math/physics/constraints/spring.cpp @@ -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; } \ No newline at end of file diff --git a/engine/src/utils/math/physics/constraints/weld.cpp b/engine/src/utils/math/physics/constraints/weld.cpp index 2dfc0ae1..eef75535 100644 --- a/engine/src/utils/math/physics/constraints/weld.cpp +++ b/engine/src/utils/math/physics/constraints/weld.cpp @@ -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; } \ No newline at end of file diff --git a/engine/src/utils/math/physics/impl.cpp b/engine/src/utils/math/physics/impl.cpp index ad81ed01..57fb7a22 100644 --- a/engine/src/utils/math/physics/impl.cpp +++ b/engine/src/utils/math/physics/impl.cpp @@ -9,7 +9,7 @@ #include -#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(); + auto& root = object.getComponent(); + auto isRoot = !root.world; + auto& body = isRoot ? root : *(new pod::PhysicsBody); // initial initialization body.world = &world; body.object = &object; body.transform/*.reference*/ = &object.getComponent>(); 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(); return create( getWorld(), object, mass, offset ); - } void uf::physics::destroy( uf::Object& object ) { if ( !object.hasComponent() ) return; - return destroy( object.getComponent() ); + auto& root = object.getComponent(); + 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(), b.getComponent() ); -} -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(), b.getComponent() ); -} - -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() ); -} - #if UF_PHYSICS_TEST #include "tests.inl" #endif \ No newline at end of file diff --git a/engine/src/utils/math/physics/integration.cpp b/engine/src/utils/math/physics/integration.cpp index 1c8e837b..26efec08 100644 --- a/engine/src/utils/math/physics/integration.cpp +++ b/engine/src/utils/math/physics/integration.cpp @@ -4,7 +4,7 @@ #include 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; diff --git a/engine/src/utils/math/physics/narrowphase/aabb.cpp b/engine/src/utils/math/physics/narrowphase/aabb.cpp index f4c5e60f..818df28f 100644 --- a/engine/src/utils/math/physics/narrowphase/aabb.cpp +++ b/engine/src/utils/math/physics/narrowphase/aabb.cpp @@ -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 ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/capsule.cpp b/engine/src/utils/math/physics/narrowphase/capsule.cpp index 8f6ddeea..6f6ece15 100644 --- a/engine/src/utils/math/physics/narrowphase/capsule.cpp +++ b/engine/src/utils/math/physics/narrowphase/capsule.cpp @@ -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 ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/mesh.cpp b/engine/src/utils/math/physics/narrowphase/mesh.cpp index 10db7354..26528823 100644 --- a/engine/src/utils/math/physics/narrowphase/mesh.cpp +++ b/engine/src/utils/math/physics/narrowphase/mesh.cpp @@ -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 ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/obb.cpp b/engine/src/utils/math/physics/narrowphase/obb.cpp index 718b9346..d563ee48 100644 --- a/engine/src/utils/math/physics/narrowphase/obb.cpp +++ b/engine/src/utils/math/physics/narrowphase/obb.cpp @@ -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 ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/plane.cpp b/engine/src/utils/math/physics/narrowphase/plane.cpp index 24158772..868bb841 100644 --- a/engine/src/utils/math/physics/narrowphase/plane.cpp +++ b/engine/src/utils/math/physics/narrowphase/plane.cpp @@ -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 ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/sphere.cpp b/engine/src/utils/math/physics/narrowphase/sphere.cpp index 57d6e3e7..ff1624f1 100644 --- a/engine/src/utils/math/physics/narrowphase/sphere.cpp +++ b/engine/src/utils/math/physics/narrowphase/sphere.cpp @@ -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 ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/triangle.cpp b/engine/src/utils/math/physics/narrowphase/triangle.cpp index 95f191c7..834a1e27 100644 --- a/engine/src/utils/math/physics/narrowphase/triangle.cpp +++ b/engine/src/utils/math/physics/narrowphase/triangle.cpp @@ -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 ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/solvers/block.cpp b/engine/src/utils/math/physics/solvers/block.cpp index 7bcdaca9..2f4e3ee7 100644 --- a/engine/src/utils/math/physics/solvers/block.cpp +++ b/engine/src/utils/math/physics/solvers/block.cpp @@ -6,10 +6,8 @@ namespace impl { template bool blockNxNSolver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) { - pod::Matrix 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 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 { diff --git a/engine/src/utils/math/physics/solvers/iterativeImpulse.cpp b/engine/src/utils/math/physics/solvers/iterativeImpulse.cpp index db92259c..cb9912bd 100644 --- a/engine/src/utils/math/physics/solvers/iterativeImpulse.cpp +++ b/engine/src/utils/math/physics/solvers/iterativeImpulse.cpp @@ -4,17 +4,16 @@ #include 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 ); diff --git a/engine/src/utils/math/physics/solvers/ngs.cpp b/engine/src/utils/math/physics/solvers/ngs.cpp index 0fe615fe..e9187573 100644 --- a/engine/src/utils/math/physics/solvers/ngs.cpp +++ b/engine/src/utils/math/physics/solvers/ngs.cpp @@ -12,7 +12,7 @@ void impl::solvePositions( uf::stl::vector& 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 ); diff --git a/engine/src/utils/math/physics/tests.inl b/engine/src/utils/math/physics/tests.inl index 7cfc7b6f..b3eac673 100644 --- a/engine/src/utils/math/physics/tests.inl +++ b/engine/src/utils/math/physics/tests.inl @@ -28,18 +28,27 @@ namespace impl { } } +// cringe wrapper because i changed the api again +namespace uf { + namespace physics { + template 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 );