refractor to try and minimize differences between reactphysics and internal physics engine (that i really need to optimize now), reverted some things with the graph system to get it to work again on scenes with more than one mesh (because for some reason instance IDs need to be global and i cant for the life of me figure out how to properly remap them)

This commit is contained in:
ecker 2025-09-01 23:16:43 -05:00
parent 3b5db2c32c
commit a66f56ad9f
38 changed files with 881 additions and 795 deletions

View File

@ -66,7 +66,7 @@ ifneq (,$(findstring win64,$(ARCH)))
REQ_DEPS += meshoptimizer toml xatlas curl ffx:fsr dc:texconv # vall_e cpptrace # openvr # ncurses draco discord bullet ultralight-ux
FLAGS += -march=native -g # -flto # -g
endif
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit simd ctti gltf imgui fmt freetype openal ogg wav # reactphysics
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit reactphysics simd ctti gltf imgui fmt freetype openal ogg wav
FLAGS += -DUF_ENV_WINDOWS -DUF_ENV_WIN64 -DWIN32_LEAN_AND_MEAN
DEPS += -lgdi32 -ldwmapi
LINKS += #-Wl,-subsystem,windows
@ -76,13 +76,13 @@ else ifneq (,$(findstring linux,$(ARCH)))
REQ_DEPS += toml xatlas curl dc:texconv # meshoptimizer ffx:fsr cpptrace vall_e # ncurses openvr draco discord bullet ultralight-ux
FLAGS += -march=native -g # -flto # -g
endif
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit simd ctti gltf imgui fmt freetype openal ogg wav # reactphysics
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit reactphysics simd ctti gltf imgui fmt freetype openal ogg wav
FLAGS += -DUF_ENV_LINUX -fPIC
DEPS += -pthread -ldl -lX11 -lXrandr
INCS := -I./dep/master/include $(INCS)
else ifneq (,$(findstring dreamcast,$(ARCH)))
FLAGS += -DUF_ENV_DREAMCAST # -DUF_LEAN_AND_MEAN # this apparently crashes
REQ_DEPS += opengl gldc json:nlohmann zlib lua simd ctti fmt freetype openal aldc ogg wav png # imgui # reactphysics
REQ_DEPS += opengl gldc json:nlohmann zlib lua reactphysics simd ctti fmt freetype openal aldc ogg wav png # imgui
INCS := -I./dep/dreamcast/include $(INCS)
endif

View File

@ -117,7 +117,7 @@
"gui": true,
"vsync": false, // vsync on vulkan side rather than engine-side
"hdr": true,
"vxgi": true,
"vxgi": false, // true
"culling": true,
"bloom": true,
"rt": false,
@ -359,7 +359,7 @@
},
"threads": {
"workers" : "auto",
"frame limiter": "auto"
"frame limiter": 0 // "auto"
},
"debug": {
"framerate": {
@ -381,8 +381,8 @@
"auto validate": false
},
"loader": {
"assert": true,
"async": true
"assert": true
//"async": true
},
"hooks": {
"defer lazy calls": true

View File

@ -6,12 +6,7 @@
"metadata": {
"holdable": true,
"physics": {
// "gravity": [ 0, -9.81, 0 ],
// "inertia": [10, 10, 10],
// "mass": 10,
"type": "bounding box",
"recenter": false
"type": "bounding box"
}
}
}

View File

@ -2,7 +2,7 @@ local ent = ent
local scene = entities.currentScene()
local metadata = ent:getComponent("Metadata")
local transform = ent:getComponent("Transform")
local physicsState = ent:getComponent("PhysicsState")
local physicsBody = ent:getComponent("PhysicsBody")
local camera = ent:getComponent("Camera")
local cameraTransform = camera:getTransform()
@ -12,7 +12,6 @@ local timers = {
}
if not timers.lookat:running() then timers.lookat:start(); end
local collider = ent:getComponent("PhysicsState")
local target_transform = nil
local soundEmitter = ent
-- on tick
@ -27,8 +26,8 @@ ent:bind( "tick", function(self)
local angle = Vector3f.signedAngle( transform.forward, target, axis )
local rot = Quaternion.axisAngle( axis, angle * time.delta() * 4 )
if collider:hasBody() then
collider:applyRotation( rot )
if physicsBody:hasBody() then
physicsBody:applyRotation( rot )
else
transform:rotate( rot )
end

View File

@ -13,8 +13,8 @@ local targetAlpha = 1.57
local alpha = 0
local target = Vector3f(0,0,0)
local transform = ent:getComponent("Transform")
local physicsBody = ent:getComponent("PhysicsBody")
local metadata = ent:getComponent("Metadata")
local collider = ent:getComponent("PhysicsState")
local speed = metadata["speed"] or 1.0
local normal = Vector3f(0,0,-1)
@ -88,8 +88,8 @@ ent:bind( "tick", function(self)
end
if state > 0 and rot ~= nil then
if collider:hasBody() then
collider:applyRotation( rot )
if physicsBody:hasBody() then
physicsBody:applyRotation( rot )
else
transform:rotate( rot )
end

View File

@ -2,7 +2,7 @@ local ent = ent
local scene = entities.currentScene()
local metadataJson = ent:getComponent("Metadata")
local transform = ent:getComponent("Transform")
local physicsState = ent:getComponent("Physics")
local physicsBody = ent:getComponent("PhysicsBody")
local camera = ent:getComponent("Camera")
local cameraTransform = camera:getTransform()
@ -112,7 +112,7 @@ ent:bind( "tick", function(self)
local direction = flattenedTransform.forward * 8
local offset = 0.25
local _, depth = physicsState:rayCast( center, direction )
local _, depth = physicsBody:rayCast( center, direction )
if depth >= 0.5 then
depth = 0.5
elseif depth < 0 then
@ -142,7 +142,7 @@ ent:bind( "tick", function(self)
local center = flattenedTransform.position
local direction = flattenedTransform.forward * useDistance
local prop, depth = physicsState:rayCast( center, direction )
local prop, depth = physicsBody:rayCast( center, direction )
local payload = {
user = ent:uid(),
uid = prop and prop:uid() or 0,
@ -164,10 +164,10 @@ ent:bind( "tick", function(self)
]]
local center = flattenedTransform.position
local direction = flattenedTransform.forward * pullDistance
local prop, depth = physicsState:rayCast( center, direction )
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("Physics")
local heldObjectPhysicsState = prop:getComponent("PhysicsBody")
local strength = 500
local distanceSquared = (heldObjectTransform.position - flattenedTransform.position):magnitude()
@ -191,7 +191,7 @@ ent:bind( "tick", function(self)
local prop = entities.get( heldObject.uid )
local heldObjectTransform = prop:getComponent("Transform")
local heldObjectPhysicsState = prop:getComponent("Physics")
local heldObjectPhysicsState = prop:getComponent("PhysicsBody")
if mouse1 and timers.physcannon:elapsed() > 0.5 then
timers.physcannon:reset()
@ -243,14 +243,14 @@ ent:addHook( "entity:Use.%UID%", function( payload )
heldObject.uid = payload.uid
heldObject.distance = offset:norm()
prop:getComponent("Physics"):enableGravity(false)
prop:getComponent("PhysicsBody"):enableGravity(false)
else
validUse = not string.matched( prop:name(), "/^worldspawn/" )
end
elseif heldObject.uid ~= 0 then
validUse = true
local prop = entities.get( heldObject.uid )
local heldObjectPhysicsState = prop:getComponent("Physics")
local heldObjectPhysicsState = prop:getComponent("PhysicsBody")
heldObjectPhysicsState:enableGravity(true)
heldObjectPhysicsState:applyImpulse( heldObject.momentum )

View File

@ -10,7 +10,7 @@
"tags": {
// exact matches
"worldspawn": {
"physics": { "type": "mesh", "static": true },
"physics": { "type": "mesh", "static": true, "mass": 0 },
"grid": { "size": [8,1,8], "epsilon": 0.001, "cleanup": true, "print": true, "clip": true },
"optimize meshlets": { "simplify": 0.125, "print": false },
"unwrap mesh": true
@ -36,7 +36,7 @@
// "/^light_[^e]/": { "ignore": true },
// regexp matches
"/^worldspawn_/": { "physics": { "type": "mesh", "static": true } },
// "/^worldspawn_/": { "physics": { "type": "mesh", "static": true } },
"/^func_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^prop_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^prop_static/": { /*"action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } }*/ },

View File

@ -1,9 +1,9 @@
{
"import": "./base_sourceengine.json",
"assets": [
// { "filename": "./models/mds_mcdonalds.glb" },
{ "filename": "./models/mds_mcdonalds/graph.json" },
{ "filename": "/burger.json", "delay": 1 }
// { "filename": "./models/mds_mcdonalds.glb" }
{ "filename": "./models/mds_mcdonalds/graph.json" }
// { "filename": "/burger.json", "delay": 1 }
],
"metadata": {
"graph": {

View File

@ -1,9 +1,9 @@
{
// "import": "./rp_downtown_v2.json"
"import": "./ss2_medsci1.json"
// "import": "./ss2_medsci1.json"
// "import": "./test_grid.json"
// "import": "./sh2_mcdonalds.json"
// "import": "./animal_crossing.json"
// "import": "./mds_mcdonalds.json"
"import": "./mds_mcdonalds.json"
// "import": "./gm_construct.json"
}

View File

@ -2,9 +2,9 @@
"import": "./base_sourceengine.json",
"assets": [
// { "filename": "./models/ss2_medsci1.glb" }
// { "filename": "./models/ss2_medsci1/graph.json" }
{ "filename": "./models/ss2_medsci1/graph.json" }
// { "filename": "./models/ss2_medsci1_small.glb" }
{ "filename": "./models/ss2_medsci1_small/graph.json" }
// { "filename": "./models/ss2_medsci1_small/graph.json" }
// { "filename": "./models/ss2_medsci1_smallish.glb" }
// { "filename": "./models/ss2_medsci1_smallish/graph.json" }
],

View File

@ -1 +1 @@
opengl
vulkan

View File

@ -29,6 +29,8 @@ namespace pod {
// Render information
uf::stl::vector<uf::stl::string> primitives; //
uf::stl::vector<uf::stl::string> instances; // ugh
uf::stl::vector<uf::stl::string> drawCommands; // ugh
uf::stl::vector<uf::stl::string> meshes; //
uf::stl::vector<uf::stl::string> images; //
@ -79,8 +81,10 @@ namespace pod {
// Local storage, used for save/load
struct Storage {
uf::stl::KeyMap<pod::Instance> instances; // should be unused but is a counter for global instance IDs because I cannot for the life of me figure out a working way to remap otherwise
uf::stl::KeyMap<pod::Instance::Addresses> instanceAddresses;
uf::stl::KeyMap<uf::stl::vector<pod::Primitive>> primitives;
uf::stl::KeyMap<uf::stl::vector<pod::DrawCommand>> drawCommands; // unused
uf::stl::KeyMap<uf::Mesh> meshes;
uf::stl::KeyMap<uf::Image> images;

View File

@ -5,6 +5,7 @@
#include <uf/utils/math/transform.h>
#include <uf/utils/mesh/mesh.h>
#include <uf/engine/graph/graph.h>
#include <uf/utils/math/shapes.h>
#if UF_USE_REACTPHYSICS
#include <reactphysics3d/reactphysics3d.h>
@ -12,23 +13,49 @@
namespace rp3d = reactphysics3d;
namespace pod {
struct UF_API Physics {
size_t uid = 0;
uf::Object* object = NULL;
bool shared = false; // share control of the transform both in-engine and bullet, set to true if you're directly modifying the transform
typedef uint32_t CollisionMask;
struct PhysicsMaterial {
float restitution = 0.2f;
float staticFriction = 0.5f;
float dynamicFriction = 0.3f;
};
struct UF_API Collider {
pod::CollisionMask mask;
rp3d::RigidBody* body = NULL;
rp3d::CollisionShape* shape = NULL;
rp3d::Collider* colliders = NULL;
};
struct UF_API PhysicsBody {
rp3d::PhysicsWorld* world = NULL;
uf::Object* object = NULL;
pod::Transform<> transform = {};
pod::Vector3f velocity;
pod::Vector3f acceleration;
pod::Quaternion<> angularVelocity;
pod::Quaternion<> angularAcceleration;
pod::Vector3f offset = {};
bool isStatic = false;
float mass = 1.0f;
float inverseMass = 1.0f;
pod::Vector3f velocity = {};
pod::Vector3f forceAccumulator = {};
pod::Vector3f angularVelocity = {};
pod::Vector3f torqueAccumulator = {};
pod::Vector3f inertiaTensor = { 0, 0, 0 };
pod::Vector3f inverseInertiaTensor = { 0, 0, 0 };
pod::Vector3f gravity = { 0.0f, -9.81f, 0.0f }; // an invalid gravity will fallback to world gravity
pod::Collider collider;
pod::PhysicsMaterial material;
// to-do: do something about this
struct {
struct {
pod::Transform<> transform = {};
@ -38,19 +65,19 @@ namespace pod {
pod::Quaternion<> angularAcceleration;
} current, previous;
} internal;
struct {
uint32_t flags = 0;
float mass = 0.0f;
float friction = 0.8f;
float restitution = 0.0f;
pod::Vector3f inertia = {0, 0, 0};
pod::Vector3f gravity = {0, 0, 0};
} stats;
};
typedef Physics PhysicsState;
struct Contact {
pod::Vector3f contact = {};
pod::Vector3f normal = {};
float penetration = 0;
};
struct RayQuery {
bool hit = false;
const pod::PhysicsBody* body;
pod::Contact contact = { pod::Vector3f{}, pod::Vector3f{}, FLT_MAX };
};
}
namespace ext {
@ -88,53 +115,53 @@ namespace ext {
}
// base collider creation
pod::PhysicsState& UF_API create( uf::Object& );
pod::PhysicsBody& UF_API create( uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
void UF_API destroy( uf::Object& );
void UF_API destroy( pod::PhysicsState& );
void UF_API destroy( pod::PhysicsBody& );
void UF_API attach( pod::PhysicsState& );
void UF_API detach( pod::PhysicsState& );
void UF_API attach( pod::PhysicsBody& );
void UF_API detach( pod::PhysicsBody& );
// collider for mesh (static or dynamic)
pod::PhysicsState& UF_API create( uf::Object&, const uf::Mesh&, bool );
pod::PhysicsBody& UF_API create( uf::Object&, const uf::Mesh&, float mass = 0.0f, const pod::Vector3f& = {} );
// collider for boundingbox
pod::PhysicsState& UF_API create( uf::Object&, const pod::Vector3f& );
pod::PhysicsBody& UF_API create( uf::Object&, const pod::AABB&, float mass = 0.0f, const pod::Vector3f& = {} );
// collider for sphere
pod::PhysicsBody& UF_API create( uf::Object&, const pod::Sphere&, float mass = 0.0f, const pod::Vector3f& = {} );
// collider for plane
pod::PhysicsBody& UF_API create( uf::Object&, const pod::Plane&, float mass = 0.0f, const pod::Vector3f& = {} );
// collider for capsule
pod::PhysicsState& UF_API create( uf::Object&, float, float );
pod::PhysicsBody& UF_API create( uf::Object&, const pod::Capsule&, float mass = 0.0f, const pod::Vector3f& = {} );
// update mesh
void UF_API update( pod::PhysicsState&, const uf::Mesh&, bool );
void UF_API update( pod::PhysicsBody&, const uf::Mesh&, bool );
// synchronize engine transforms to bullet transforms
void UF_API syncTo( ext::reactphysics::WorldState& );
// synchronize bullet transforms to engine transforms
void UF_API syncFrom( ext::reactphysics::WorldState&, float = 1 );
// apply impulse
void UF_API setImpulse( pod::PhysicsState&, const pod::Vector3f& = {} );
void UF_API applyImpulse( pod::PhysicsState&, const pod::Vector3f& );
void UF_API setImpulse( pod::PhysicsBody&, const pod::Vector3f& = {} );
void UF_API applyImpulse( pod::PhysicsBody&, const pod::Vector3f& );
// directly move a transform
void UF_API applyMovement( pod::PhysicsState&, const pod::Vector3f& );
void UF_API applyMovement( pod::PhysicsBody&, const pod::Vector3f& );
// directly apply a velocity
void UF_API setVelocity( pod::PhysicsState&, const pod::Vector3f& );
void UF_API applyVelocity( pod::PhysicsState&, const pod::Vector3f& );
void UF_API setVelocity( pod::PhysicsBody&, const pod::Vector3f& );
void UF_API applyVelocity( pod::PhysicsBody&, const pod::Vector3f& );
// directly rotate a transform
void UF_API applyRotation( pod::PhysicsState&, const pod::Quaternion<>& );
void UF_API applyRotation( pod::PhysicsState&, const pod::Vector3f&, float );
void UF_API applyRotation( pod::PhysicsBody&, const pod::Quaternion<>& );
void UF_API applyRotation( pod::PhysicsBody&, const pod::Vector3f&, float );
// ray casting
uf::Object* UF_API rayCast( const pod::Vector3f&, const pod::Vector3f& );
uf::Object* UF_API rayCast( pod::PhysicsState&, const pod::Vector3f&, const pod::Vector3f& );
uf::Object* UF_API rayCast( pod::PhysicsState&, const pod::Vector3f&, const pod::Vector3f&, float& );
uf::Object* UF_API rayCast( const pod::Vector3f&, const pod::Vector3f&, uf::Object*, float& );
// float UF_API rayCast( const pod::Vector3f&, const pod::Vector3f&, uf::Object*, uf::Object*& );
pod::RayQuery UF_API rayCast( const pod::Ray& ray, const pod::PhysicsBody& body, float max );
// allows noclip
void UF_API activateCollision( pod::PhysicsState&, bool = true );
void UF_API activateCollision( pod::PhysicsBody&, bool = true );
//
float UF_API getMass( pod::PhysicsState& );
void UF_API setMass( pod::PhysicsState&, float );
float UF_API getMass( pod::PhysicsBody& );
void UF_API setMass( pod::PhysicsBody&, float );
}
}
namespace uf {

View File

@ -62,9 +62,37 @@ namespace pod {
typedef uint32_t CollisionMask;
struct Collider {
// what it is
enum CategoryMask : uint32_t {
CATEGORY_NONE = 0,
CATEGORY_STATIC = 1 << 0,
CATEGORY_DYNAMIC = 1 << 1,
CATEGORY_PLAYER = 1 << 2,
CATEGORY_NPC = 1 << 3,
CATEGORY_TRIGGER = 1 << 4,
CATEGORY_PROJECTILE = 1 << 5,
CATEGORY_CHARACTER = CATEGORY_PLAYER | CATEGORY_NPC,
CATEGORY_ALL = 0xFFFFFFFF
};
// what it collides with
enum CollisionMask : uint32_t {
MASK_NONE = 0,
MASK_STATIC = CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC | CATEGORY_PROJECTILE,
MASK_DYNAMIC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC,
MASK_PLAYER = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_NPC | CATEGORY_PROJECTILE,
MASK_NPC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_PROJECTILE,
MASK_TRIGGER = CATEGORY_PLAYER | CATEGORY_NPC,
MASK_PROJECTILE = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC,
MASK_CHARACTER = MASK_PLAYER | MASK_NPC,
MASK_ALL = 0xFFFFFFFF
};
pod::ShapeType type;
pod::CollisionMask mask = 0xFFFFFFFF;
pod::CollisionMask category = Collider::CATEGORY_ALL;
pod::CollisionMask mask = Collider::MASK_ALL;
union {
pod::Sphere sphere;
pod::AABB aabb;
@ -83,7 +111,7 @@ namespace pod {
struct World; // forward declare
struct RigidBody {
struct PhysicsBody {
pod::World* world = NULL;
uf::Object* object = NULL;
// pod::Transform<> transform = {};
@ -105,6 +133,8 @@ namespace pod {
pod::Vector3f inertiaTensor = { 1, 1, 1 };
pod::Vector3f inverseInertiaTensor = { 1, 1, 1 };
pod::Vector3f gravity = { NAN, NAN, NAN }; // an invalid gravity will fallback to world gravity
pod::AABB bounds;
pod::Collider collider;
pod::PhysicsMaterial material;
@ -123,20 +153,20 @@ namespace pod {
};
struct Manifold {
pod::RigidBody* a = NULL;
pod::RigidBody* b = NULL;
pod::PhysicsBody* a = NULL;
pod::PhysicsBody* b = NULL;
float dt = 0;
uf::stl::vector<pod::Contact> points;
};
struct RayQuery {
bool hit = false;
const pod::RigidBody* body;
const pod::PhysicsBody* body;
pod::Contact contact = { pod::Vector3f{}, pod::Vector3f{}, FLT_MAX };
};
struct World {
uf::stl::vector<pod::RigidBody*> bodies;
uf::stl::vector<pod::PhysicsBody*> bodies;
pod::Vector3f gravity = { 0, -9.81f, 0 };
pod::BVH bvh;
@ -168,38 +198,46 @@ namespace uf {
void UF_API step( pod::World&, float dt );
void UF_API substep( pod::World&, float dt, int substeps );
void UF_API setMass( pod::RigidBody& body, float mass = 0.0f );
void UF_API setInertia( pod::RigidBody& body );
void UF_API applyForce( pod::RigidBody& body, const pod::Vector3f& force );
void UF_API applyForceAtPoint( pod::RigidBody body, const pod::Vector3f& force, const pod::Vector3f& point );
void UF_API applyImpulse( pod::RigidBody& body, const pod::Vector3f& impulse );
void UF_API applyTorque( pod::RigidBody& body, const pod::Vector3f& torque );
void UF_API setMass( pod::PhysicsBody& body, float mass = 0.0f );
void UF_API setColliderCategory( pod::PhysicsBody&, uint32_t category = pod::Collider::CATEGORY_ALL );
void UF_API setColliderCategory( pod::PhysicsBody&, const uf::stl::string& );
void UF_API setColliderMask( pod::PhysicsBody&, uint32_t mask = pod::Collider::MASK_ALL );
void UF_API setColliderMask( pod::PhysicsBody&, const uf::stl::string& );
void UF_API setGravity( pod::PhysicsBody&, const pod::Vector3f& = { NAN, NAN, NAN } );
pod::Vector3f UF_API getGravity( pod::PhysicsBody& );
void UF_API setVelocity( pod::RigidBody& body, const pod::Vector3f& velocity );
void UF_API applyRotation( pod::RigidBody& body, const pod::Quaternion<>& q );
void UF_API applyRotation( pod::RigidBody& body, const pod::Vector3f& axis, float angle );
void UF_API updateInertia( pod::PhysicsBody& body );
void UF_API applyForce( pod::PhysicsBody& body, const pod::Vector3f& force );
void UF_API applyForceAtPoint( pod::PhysicsBody body, const pod::Vector3f& force, const pod::Vector3f& point );
void UF_API applyImpulse( pod::PhysicsBody& body, const pod::Vector3f& impulse );
void UF_API applyTorque( pod::PhysicsBody& body, const pod::Vector3f& torque );
void UF_API setVelocity( pod::PhysicsBody& body, const pod::Vector3f& velocity );
void UF_API applyRotation( pod::PhysicsBody& body, const pod::Quaternion<>& q );
void UF_API applyRotation( pod::PhysicsBody& body, const pod::Vector3f& axis, float angle );
pod::RigidBody& UF_API create( uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( uf::Object& object, const pod::AABB& aabb, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( uf::Object& object, const pod::Sphere& sphere, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( uf::Object& object, const pod::Plane& plane, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( uf::Object& object, const pod::Capsule& capsule, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( uf::Object&, const uf::Mesh& mesh, float mass = 0.0f, const pod::Vector3f& = {} );
pod::PhysicsBody& UF_API create( uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
pod::PhysicsBody& UF_API create( uf::Object& object, const pod::AABB& aabb, 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 create( uf::Object& object, const pod::Plane& plane, float mass = 0.0f, const pod::Vector3f& = {} );
pod::PhysicsBody& UF_API create( uf::Object& object, const pod::Capsule& capsule, float mass = 0.0f, const pod::Vector3f& = {} );
pod::PhysicsBody& UF_API create( uf::Object&, const uf::Mesh& mesh, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( pod::World&, uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( pod::World&, uf::Object& object, const pod::AABB& aabb, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( pod::World&, uf::Object& object, const pod::Sphere& sphere, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( pod::World&, uf::Object& object, const pod::Plane& plane, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( pod::World&, uf::Object& object, const pod::Capsule& capsule, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( pod::World&, uf::Object& object, const pod::TriangleWithNormal& tri, float mass = 0.0f, const pod::Vector3f& = {} );
pod::RigidBody& UF_API create( pod::World&, uf::Object&, const uf::Mesh& mesh, float mass = 0.0f, const pod::Vector3f& = {} );
pod::PhysicsBody& UF_API create( pod::World&, uf::Object&, 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 create( pod::World&, uf::Object& object, const pod::Sphere& sphere, 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 create( pod::World&, 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::TriangleWithNormal& tri, float mass = 0.0f, const pod::Vector3f& = {} );
pod::PhysicsBody& UF_API create( pod::World&, uf::Object&, const uf::Mesh& mesh, float mass = 0.0f, const pod::Vector3f& = {} );
void UF_API destroy( uf::Object& );
void UF_API destroy( pod::RigidBody& );
void UF_API destroy( pod::PhysicsBody& );
pod::RayQuery UF_API rayCast( const pod::Ray&, const pod::RigidBody&, float = FLT_MAX );
pod::RayQuery UF_API rayCast( const pod::Ray&, const pod::PhysicsBody&, float = FLT_MAX );
pod::RayQuery UF_API rayCast( const pod::Ray&, const pod::World&, float = FLT_MAX );
pod::RayQuery UF_API rayCast( const pod::Ray&, const pod::World&, const pod::RigidBody*, float = FLT_MAX );
pod::RayQuery UF_API rayCast( const pod::Ray&, const pod::World&, const pod::PhysicsBody*, float = FLT_MAX );
}
}
}

View File

@ -25,10 +25,6 @@ UF_BEHAVIOR_TRAITS_CPP(ext::PlayerBehavior, ticks = true, renders = false, multi
void ext::PlayerBehavior::initialize( uf::Object& self ) {
auto& transform = this->getComponent<pod::Transform<>>();
#if UF_USE_REACTPHYSICS
auto& collider = this->getComponent<pod::PhysicsState>();
#endif
auto& metadata = this->getComponent<ext::PlayerBehavior::Metadata>();
auto& metadataJson = this->getComponent<uf::Serializer>();
@ -133,16 +129,12 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
auto& transform = this->getComponent<pod::Transform<>>();
auto& scene = uf::scene::getCurrentScene();
#if UF_USE_REACTPHYSICS
auto& physics = this->getComponent<pod::Physics>();
auto& collider = this->getComponent<pod::PhysicsState>();
#else
auto& physics = this->getComponent<pod::RigidBody>();
#endif
auto& metadata = this->getComponent<ext::PlayerBehavior::Metadata>();
auto& metadataJson = this->getComponent<uf::Serializer>();
auto& physicsBody = this->getComponent<pod::PhysicsBody>();
#if UF_ENTITY_METADATA_USE_JSON
metadata.deserialize(self, metadataJson);
#endif
@ -281,23 +273,24 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
stats.floored = stats.noclipped;
if ( !stats.floored ) {
#if UF_USE_REACTPHYSICS
float t = -1;
uf::Object* hit = NULL;
pod::Vector3f center = transform.position + metadata.movement.floored.feet;
pod::Vector3f origin = transform.position + metadata.movement.floored.feet;
pod::Vector3f direction = metadata.movement.floored.floor;
if ( !stats.floored && collider.body && (hit = uf::physics::impl::rayCast( collider, center, direction, t )) ) {
if ( metadata.movement.floored.print ) UF_MSG_DEBUG("Floored: {} | {}", hit->getName(), t);
pod::RayQuery query = uf::physics::impl::rayCast( pod::Ray{origin, direction}, physicsBody, 1.0f );
if ( query.hit ) {
if ( metadata.movement.floored.print ) UF_MSG_DEBUG("{}: {} | {}", query.contact.penetration, uf::string::toString(*query.body->object), uf::vector::toString(physicsBody.velocity));
stats.floored = true;
//if ( physicsBody.velocity.y < 0.0f ) physicsBody.velocity.y = 0.0f;
}
#else
pod::Vector3f origin = transform.position + metadata.movement.floored.feet;
pod::Vector3f direction = metadata.movement.floored.floor;
pod::RayQuery query = uf::physics::impl::rayCast( pod::Ray{origin, direction}, physics, 1.0f );
pod::RayQuery query = uf::physics::impl::rayCast( pod::Ray{origin, direction}, physicsBody, 1.0f );
if ( query.hit ) {
if ( metadata.movement.floored.print ) UF_MSG_DEBUG("{}: {} | {}", query.contact.penetration, uf::string::toString(*query.body->object), uf::vector::toString(physics.velocity));
if ( metadata.movement.floored.print ) UF_MSG_DEBUG("{}: {} | {}", query.contact.penetration, uf::string::toString(*query.body->object), uf::vector::toString(physicsBody.velocity));
stats.floored = true;
if ( physics.velocity.y < 0.0f ) physics.velocity.y = 0.0f;
//if ( physicsBody.velocity.y < 0.0f ) physicsBody.velocity.y = 0.0f;
}
#endif
}
@ -346,9 +339,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
}
#endif
#if UF_USE_REACTPHYSICS
if ( collider.stats.gravity == pod::Vector3f{0,0,0} ) stats.noclipped = true;
#endif
if ( physicsBody.gravity == pod::Vector3f{0,0,0} ) stats.noclipped = true;
{
speed.rotate = metadata.movement.rotate * uf::physics::time::delta;
@ -363,7 +354,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
speed.run *= 1.5;
}
if ( !stats.floored || stats.noclipped ) speed.friction = 1;
if ( stats.noclipped ) physics.velocity = {};
if ( stats.noclipped ) physicsBody.velocity = {};
}
if ( keys.running ) speed.move = speed.run;
else if ( keys.walk ) speed.move = speed.walk;
@ -424,12 +415,10 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
translator.forward.y = 0;
translator.forward = uf::vector::normalize( translator.forward );
}
#if UF_USE_REACTPHYSICS
else if ( stats.noclipped || collider.stats.gravity == pod::Vector3f{0,0,0} ){
else if ( stats.noclipped || physicsBody.gravity == pod::Vector3f{0,0,0} ){
translator.forward.y += cameraTransform.forward.y;
translator.forward = uf::vector::normalize( translator.forward );
}
#endif
if ( metadata.system.control ) {
// noclip handler
@ -437,9 +426,19 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
bool state = !stats.noclipped;
metadata.system.noclipped = state;
#if UF_USE_REACTPHYSICS
if ( collider.body ) {
collider.body->enableGravity(!state);
uf::physics::impl::activateCollision(collider, !state);
if ( physicsBody.object ) {
physicsBody.collider.body->enableGravity(!state);
uf::physics::impl::activateCollision(physicsBody, !state);
}
#else
if ( !state ) {
uf::physics::impl::setGravity( physicsBody );
uf::physics::impl::setColliderCategory( physicsBody, "ALL");
uf::physics::impl::setColliderMask( physicsBody, "ALL");
} else {
uf::physics::impl::setGravity( physicsBody, pod::Vector3f{0,0,0});
uf::physics::impl::setColliderCategory( physicsBody, "NONE");
uf::physics::impl::setColliderMask( physicsBody, "NONE");
}
#endif
@ -453,16 +452,16 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
if ( keys.left ^ keys.right ) target += translator.right * (keys.right ? 1 : -1);
target = uf::vector::normalize( target );
physics.velocity *= { speed.friction, 1, speed.friction };
physicsBody.velocity *= { speed.friction, 1, speed.friction };
stats.walking = (keys.forward ^ keys.backwards) || (keys.left ^ keys.right);
if ( stats.walking ) {
float factor = stats.floored ? 1.0f : speed.air;
if ( stats.noclipped ) {
physics.velocity += target * speed.move;
physicsBody.velocity += target * speed.move;
} else {
physics.velocity += target * std::clamp( speed.move * factor - uf::vector::dot( physics.velocity, target ), 0.0f, speed.move * 10 * uf::physics::time::delta );
physicsBody.velocity += target * std::clamp( speed.move * factor - uf::vector::dot( physicsBody.velocity, target ), 0.0f, speed.move * 10 * uf::physics::time::delta );
}
auto dot = uf::vector::dot( transform.forward, target );
@ -472,18 +471,14 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
auto axis = transform.up;
float angle = uf::vector::signedAngle( transform.forward, target, axis ) * uf::physics::time::delta * 4; // speed.rotate;
#if UF_USE_REACTPHYSICS
if ( collider.body ) uf::physics::impl::applyRotation( collider, axis, angle ); else
#else
if ( physics.object ) uf::physics::impl::applyRotation( physics, axis, angle ); else
#endif
if ( physicsBody.object ) uf::physics::impl::applyRotation( physicsBody, axis, angle ); else
uf::transform::rotate( transform, axis, angle );
}
}
if ( !stats.floored ) stats.walking = false;
}
TIMER(0.0625, stats.floored && keys.jump && !stats.noclipped ) {
physics.velocity += translator.up * metadata.movement.jump;
physicsBody.velocity += translator.up * metadata.movement.jump;
}
if ( stats.floored && keys.jump && stats.noclipped ) transform.position += translator.up * metadata.movement.jump * uf::physics::time::delta * 4.0f;
if ( keys.crouch ) {
@ -527,11 +522,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
if ( metadata.camera.invert.x ) lookDelta.x *= -1;
metadata.camera.limit.current.x += lookDelta.x;
if ( metadata.camera.limit.current.x != metadata.camera.limit.current.x || ( metadata.camera.limit.current.x < metadata.camera.limit.max.x && metadata.camera.limit.current.x > metadata.camera.limit.min.x ) ) {
#if UF_USE_REACTPHYSICS
if ( collider.body ) uf::physics::impl::applyRotation( collider, transform.up, lookDelta.x ); else
#else
if ( physics.object ) uf::physics::impl::applyRotation( physics, transform.up, lookDelta.x ); else
#endif
if ( physicsBody.object ) uf::physics::impl::applyRotation( physicsBody, transform.up, lookDelta.x ); else
uf::transform::rotate( transform, transform.up, lookDelta.x );
} else metadata.camera.limit.current.x -= lookDelta.x;
}
@ -539,19 +530,13 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
if ( metadata.camera.invert.y ) lookDelta.y *= -1;
metadata.camera.limit.current.y += lookDelta.y;
if ( metadata.camera.limit.current.y != metadata.camera.limit.current.y || ( metadata.camera.limit.current.y < metadata.camera.limit.max.y && metadata.camera.limit.current.y > metadata.camera.limit.min.y ) ) {
#if UF_USE_REACTPHYSICS
// if ( collider.body && !collider.shared ) uf::physics::impl::applyRotation( collider, cameraTransform.right, lookDelta.y ); else
#endif
// if ( physicsBody.object && !physicsBody.shared ) uf::physics::impl::applyRotation( physicsBody, cameraTransform.right, lookDelta.y ); else
uf::transform::rotate( cameraTransform, cameraTransform.right, lookDelta.y );
} else metadata.camera.limit.current.y -= lookDelta.y;
}
} else if ( metadata.system.control ) {
if ( keys.lookRight ^ keys.lookLeft ) {
#if UF_USE_REACTPHYSICS
if ( collider.body ) uf::physics::impl::applyRotation( collider, transform.up, speed.rotate * (keys.lookRight ? 1 : -1) ); else
#else
if ( physics.object ) uf::physics::impl::applyRotation( physics, transform.up, speed.rotate * (keys.lookRight ? 1 : -1) ); else
#endif
if ( physicsBody.object ) uf::physics::impl::applyRotation( physicsBody, transform.up, speed.rotate * (keys.lookRight ? 1 : -1) ); else
uf::transform::rotate( transform, transform.up, speed.rotate * (keys.lookRight ? 1 : -1) );
}
if ( keys.lookUp ^ keys.lookDown ) {
@ -566,22 +551,16 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
// cameraTransform.position = uf::quaternion::rotate( rotation, cameraTransform.position - transform.position );
}
if ( keys.lookUp ^ keys.lookDown ) {
#if 0
// if ( collider.body && !collider.shared ) uf::physics::impl::applyRotation( collider, cameraTransform.right, lookDelta.y ); else
#endif
// if ( physicsBody.object && !physicsBody.shared ) uf::physics::impl::applyRotation( physicsBody, cameraTransform.right, lookDelta.y ); else
float direction = keys.lookUp ? 1 : -1;
if ( metadata.camera.invert.y ) direction *= -1;
uf::transform::rotate( cameraTransform, cameraTransform.right, speed.rotate * direction );
}
}
{
#if UF_USE_REACTPHYSICS
if ( collider.body ) uf::physics::impl::setVelocity( collider, physics.velocity ); else
#else
if ( physics.object ) uf::physics::impl::setVelocity( physics, physics.velocity ); else
#endif
transform.position += physics.velocity * uf::physics::time::delta;
// if ( uf::vector::magnitude( physics.velocity ) > 1.0e-6 ) UF_MSG_DEBUG("Velocity: {}", uf::vector::toString( physics.velocity ));
if ( physicsBody.object ) uf::physics::impl::setVelocity( physicsBody, physicsBody.velocity ); else
transform.position += physicsBody.velocity * uf::physics::time::delta;
// if ( uf::vector::magnitude( physicsBody.velocity ) > 1.0e-6 ) UF_MSG_DEBUG("Velocity: {}", uf::vector::toString( physicsBody.velocity ));
}

View File

@ -8,6 +8,7 @@
#include <uf/utils/math/physics.h>
#include <uf/utils/camera/camera.h>
#include <uf/ext/xatlas/xatlas.h>
#include <uf/utils/io/fmt.h>
// it's too unstable right now to do multithreaded loading, perhaps there's a better way
#if UF_USE_OPENGL
@ -414,6 +415,17 @@ void uf::graph::load( pod::Graph& graph, const uf::stl::string& filename, const
graph.settings.stream.hash = graph.metadata["stream"]["hash"].as(graph.settings.stream.hash);
graph.settings.stream.lastUpdate = graph.metadata["stream"]["lastUpdate"].as(graph.settings.stream.lastUpdate);
}
// store offsets
{
size_t instances = 0;
for ( auto& key : storage.primitives.keys ) {
instances += storage.primitives.map[key].size();
}
graph.metadata["offsets"]["instances"] = instances;
graph.metadata["offsets"]["materials"] = storage.materials.keys.size();
graph.metadata["offsets"]["joints"] = storage.joints.keys.size();
}
uf::stl::string key = graph.metadata["key"].as<uf::stl::string>("");
if ( key != "" ) {
@ -429,6 +441,12 @@ void uf::graph::load( pod::Graph& graph, const uf::stl::string& filename, const
// UF_MSG_DEBUG("{}", name);
storage.primitives[name] = decodePrimitives( value, graph );
graph.primitives.emplace_back(name);
uf::stl::vector<pod::DrawCommand> drawCommands;
for ( auto& primitive : storage.primitives[name] ) {
drawCommands.emplace_back( primitive.drawCommand );
}
storage.drawCommands[name] = std::move(drawCommands);
});
UF_DEBUG_TIMER_MULTITRACE("Read primitives.");
#if UF_ENV_DREAMCAST

View File

@ -790,6 +790,12 @@ void uf::graph::process( pod::Graph& graph ) {
uf::stl::unordered_map<size_t, size_t> lightmapIDs;
uint32_t lightmapCount = 0;
for ( auto& name : graph.instances ) {
auto& instance = storage.instances[name];
filenames[instance.auxID] = uf::string::replace(UF_GRAPH_DEFAULT_LIGHTMAP, "%i", std::to_string(instance.auxID));
lightmapCount = std::max( lightmapCount, instance.auxID + 1 );
}
for ( auto& name : graph.primitives ) {
auto& primitives = storage.primitives[name];
for ( auto& primitive : primitives ) {
@ -863,6 +869,11 @@ void uf::graph::process( pod::Graph& graph ) {
}
}
for ( auto& name : graph.instances ) {
auto& instance = storage.instances[name];
if ( lightmapIDs.count( instance.auxID ) == 0 ) continue;
instance.lightmapID = lightmapIDs[instance.auxID];
}
for ( auto& name : graph.primitives ) {
auto& primitives = storage.primitives[name];
for ( auto& primitive : primitives ) {
@ -933,9 +944,10 @@ void uf::graph::process( pod::Graph& graph ) {
// process nodes
UF_DEBUG_TIMER_MULTITRACE("Processing nodes");
for ( auto index : graph.root.children ) {
UF_DEBUG_TIMER_MULTITRACE("Processing node: {}", graph.nodes[index].name);
process( graph, index, *graph.root.entity );
UF_DEBUG_TIMER_MULTITRACE("Processed node: {}", graph.nodes[index].name);
auto& node = graph.nodes[index];
if ( node.entity ) UF_DEBUG_TIMER_MULTITRACE("Processed node: {}", node.name);
}
// patch materials/textures
@ -1036,61 +1048,81 @@ void uf::graph::process( pod::Graph& graph ) {
}
}
// remap instance variables
UF_DEBUG_TIMER_MULTITRACE("Remapping primitive");
for ( auto& name : graph.primitives ) {
auto& primitives = storage.primitives[name];
for ( auto& primitive : primitives ) {
auto& drawCommand = primitive.drawCommand;
auto& instance = primitive.instance;
UF_DEBUG_TIMER_MULTITRACE("Remapping instances");
for ( auto& name : graph.instances ) {
auto& instance = storage.instances[name];
if ( 0 <= instance.materialID && instance.materialID < graph.materials.size() ) {
auto& keys = storage.materials.keys;
auto& indices = storage.materials.indices;
if ( !(0 <= instance.materialID && instance.materialID < graph.materials.size()) ) continue;
// remap instance ID
if ( 0 <= drawCommand.instanceID && drawCommand.instanceID < graph.primitives.size() ) {
for ( auto key : storage.primitives.keys ) {
if ( key == name ) break;
drawCommand.instanceID += storage.primitives[key].size();
}
}
auto& needle = graph.materials[instance.materialID];
instance.materialID = indices[needle];
}
if ( 0 <= instance.lightmapID && instance.lightmapID < graph.textures.size() ) {
auto& keys = storage.textures.keys;
auto& indices = storage.textures.indices;
if ( 0 <= instance.materialID && instance.materialID < graph.materials.size() ) {
auto& keys = storage.materials.keys;
auto& indices = storage.materials.indices;
if ( !(0 <= instance.materialID && instance.materialID < graph.materials.size()) ) continue;
if ( !(0 <= instance.lightmapID && instance.lightmapID < graph.textures.size()) ) continue;
auto& needle = graph.materials[instance.materialID];
instance.materialID = indices[needle];
}
if ( 0 <= instance.lightmapID && instance.lightmapID < graph.textures.size() ) {
auto& keys = storage.textures.keys;
auto& indices = storage.textures.indices;
auto& needle = graph.textures[instance.lightmapID];
instance.lightmapID = indices[needle];
}
#if 0
// i genuinely dont remember what this is used for
if ( !(0 <= instance.lightmapID && instance.lightmapID < graph.textures.size()) ) continue;
auto& needle = graph.textures[instance.lightmapID];
instance.lightmapID = indices[needle];
}
#if 0
// i genuinely dont remember what this is used for
if ( 0 <= instance.imageID && instance.imageID < graph.images.size() ) {
auto& keys = storage.images.keys;
auto it = std::find( keys.begin(), keys.end(), graph.images[instance.imageID] );
UF_ASSERT( it != keys.end() );
instance.imageID = it - keys.begin();
}
#endif
// remap a skinID as an actual jointID
if ( 0 <= instance.jointID && instance.jointID < graph.skins.size() ) {
auto& name = graph.skins[instance.jointID];
instance.jointID = 0;
for ( auto key : storage.joints.keys ) {
if ( key == name ) break;
instance.jointID += storage.joints[key].size();
}
if ( 0 <= instance.imageID && instance.imageID < graph.images.size() ) {
auto& keys = storage.images.keys;
auto it = std::find( keys.begin(), keys.end(), graph.images[instance.imageID] );
UF_ASSERT( it != keys.end() );
instance.imageID = it - keys.begin();
}
#endif
// remap a skinID as an actual jointID
if ( 0 <= instance.jointID && instance.jointID < graph.skins.size() ) {
auto& name = graph.skins[instance.jointID];
instance.jointID = 0;
for ( auto key : storage.joints.keys ) {
if ( key == name ) break;
auto& joints = storage.joints[key];
instance.jointID += joints.size();
}
}
}
// remap draw commands
#if 0
UF_DEBUG_TIMER_MULTITRACE("Remapping drawCommands");
for ( auto& name : graph.drawCommands ) {
auto& drawCommands = storage.drawCommands[name];
for ( auto& drawCommand : drawCommands ) {
if ( 0 <= drawCommand.instanceID && drawCommand.instanceID < graph.instances.size() ) {
auto& keys = storage.instances.keys;
auto& indices = storage.instances.indices;
if ( !(0 <= drawCommand.instanceID && drawCommand.instanceID < graph.instances.size()) ) continue;
auto& needle = graph.instances[drawCommand.instanceID];
#if 1
drawCommand.instanceID = indices[needle];
#elif 1
for ( size_t i = 0; i < keys.size(); ++i ) {
if ( keys[i] != needle ) continue;
drawCommand.instanceID = i;
break;
}
#else
auto it = std::find( keys.begin(), keys.end(), needle );
UF_ASSERT( it != keys.end() );
drawCommand.instanceID = it - keys.begin();
#endif
}
}
}
#endif
if ( graphMetadataJson["debug"]["print"]["lights"].as<bool>() ) {
UF_MSG_DEBUG("Lights: {}", graph.lights.size());
for ( auto& pair : graph.lights ) {
@ -1104,21 +1136,16 @@ void uf::graph::process( pod::Graph& graph ) {
}
}
#if 0
if ( graphMetadataJson["debug"]["print"]["primitives"].as<bool>() ) {
UF_MSG_DEBUG("Instances: {}", graph.primitives.size());
for ( auto& name : graph.primitives ) {
auto& primitive = storage.primitives[name];
for ( auto& primitive : primitives ) {
auto& instance = primitive.instance;
UF_MSG_DEBUG("\tInstance: {} | {} | {}", name,
instance.materialID,
instance.lightmapID
);
}
if ( graphMetadataJson["debug"]["print"]["instances"].as<bool>() ) {
UF_MSG_DEBUG("Instances: {}", graph.instances.size());
for ( auto& name : graph.instances ) {
auto& instance = storage.instances[name];
UF_MSG_DEBUG("\tInstance: {} | {} | {}", name,
instance.materialID,
instance.lightmapID
);
}
}
#endif
if ( graphMetadataJson["debug"]["print"]["materials"].as<bool>() ) {
UF_MSG_DEBUG("Materials: {}", graph.materials.size());
for ( auto& name : graph.materials ) {
@ -1146,6 +1173,7 @@ void uf::graph::process( pod::Graph& graph ) {
#endif
uf::graph::reload();
storage.instanceAddresses.keys = storage.instances.keys;
UF_DEBUG_TIMER_MULTITRACE_END("Processed graph.");
}
void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) {
@ -1289,34 +1317,32 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
}
}
}
// what a mess
node.object = storage.entities.keys.size();
auto objectKeyName = ::objectKey( node );
storage.entities[objectKeyName] = &entity;
auto& objectData = storage.objects[objectKeyName];
auto model = uf::transform::model( transform );
objectData.model = model;
objectData.previous = model;
//
if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) {
auto model = uf::transform::model( transform );
auto& mesh = storage.meshes.map[graph.meshes[node.mesh]];
auto& primitives = storage.primitives.map[graph.primitives[node.mesh]];
node.object = storage.entities.keys.size();
auto objectKeyName = ::objectKey( node );
storage.entities[objectKeyName] = &entity;
auto& objectData = storage.objects[objectKeyName];
auto model = uf::transform::model( transform );
objectData.model = model;
objectData.previous = model;
pod::Instance::Bounds bounds;
pod::DrawCommand* drawCommands = NULL;
if ( mesh.indirect.count && mesh.indirect.count <= primitives.size() ) {
auto& attribute = mesh.indirect.attributes.front();
auto& buffer = mesh.buffers[mesh.isInterleaved(mesh.indirect.interleaved) ? mesh.indirect.interleaved : attribute.buffer];
drawCommands = (pod::DrawCommand*) buffer.data();
}
// setup instances
for ( auto primitiveID = 0; primitiveID < primitives.size(); ++primitiveID ) {
auto& primitive = primitives[primitiveID];
auto& instance = primitive.instance;
auto& drawCommand = primitive.drawCommand;
auto instanceID = primitiveID;
for ( auto i = 0; i < primitives.size(); ++i ) {
auto& primitive = primitives[i];
size_t instanceID = storage.instances.keys.size();
auto instanceKeyName = graph.instances.emplace_back(std::to_string(instanceID));
auto& instance = storage.instances[instanceKeyName];
instance = primitive.instance;
instance.objectID = node.object;
instance.jointID = graphMetadataJson["renderer"]["skinned"].as<bool>() ? 0 : -1;
@ -1324,8 +1350,13 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
bounds.min = uf::vector::min( bounds.min, instance.bounds.min );
bounds.max = uf::vector::max( bounds.max, instance.bounds.max );
drawCommand.instanceID = instanceID;
if ( drawCommands ) drawCommands[primitiveID].instanceID = instanceID;
if ( mesh.indirect.count && mesh.indirect.count <= primitives.size() ) {
auto& attribute = mesh.indirect.attributes.front();
auto& buffer = mesh.buffers[mesh.isInterleaved(mesh.indirect.interleaved) ? mesh.indirect.interleaved : attribute.buffer];
pod::DrawCommand* drawCommands = (pod::DrawCommand*) buffer.data();
auto& drawCommand = drawCommands[i];
drawCommand.instanceID = instanceID;
}
}
#if !UF_GRAPH_EXTENDED
if ( graphMetadataJson["renderer"]["render"].as<bool>() ) {
@ -1348,33 +1379,22 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
pod::Vector3f center = (max + min) * 0.5f;
pod::Vector3f corner = uf::vector::abs(max - min) * 0.5f;
UF_MSG_DEBUG("{}: Center: {} | Corner: {}", node.name, uf::vector::toString( center ), uf::vector::toString( corner ));
UF_MSG_DEBUG("{}: Min: {} | Max: {}", node.name, uf::vector::toString( min ), uf::vector::toString( max ));
if ( ext::json::isNull( metadataJson["physics"]["center"] ) ) metadataJson["physics"]["center"] = uf::vector::encode( center );
if ( ext::json::isNull( metadataJson["physics"]["corner"] ) ) metadataJson["physics"]["corner"] = uf::vector::encode( corner );
if ( ext::json::isNull( metadataJson["physics"]["min"] ) ) metadataJson["physics"]["min"] = uf::vector::encode( min );
if ( ext::json::isNull( metadataJson["physics"]["max"] ) ) metadataJson["physics"]["max"] = uf::vector::encode( max );
}
#if !UF_GRAPH_EXTENDED
#if UF_USE_REACTPHYSICS
if ( type == "mesh" ) {
auto& collider = entity.getComponent<pod::PhysicsState>();
collider.stats.mass = phyziks["mass"].as(collider.stats.mass);
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 );
collider.stats.gravity = uf::vector::decode( phyziks["gravity"], collider.stats.gravity );
auto& physicsBody = entity.getComponent<pod::PhysicsBody>();
float mass = phyziks["mass"].as(physicsBody.mass);
physicsBody.material.staticFriction = phyziks["friction"].as(physicsBody.material.staticFriction);
physicsBody.material.restitution = phyziks["restitution"].as(physicsBody.material.restitution);
physicsBody.inertiaTensor = uf::vector::decode( phyziks["inertia"], physicsBody.inertiaTensor );
physicsBody.gravity = uf::vector::decode( phyziks["gravity"], physicsBody.gravity );
uf::physics::impl::create( entity.as<uf::Object>(), mesh, !phyziks["static"].as<bool>(true) );
}
#else
if ( type == "mesh" ) {
auto phyziks["mass"].as(collider.stats.mass);
uf::physics::impl::create( entity.as<uf::Object>(), mesh, mass );
}
#endif
#endif
}
}
}
@ -1430,23 +1450,17 @@ void uf::graph::tick( uf::Object& object ) {
}
bool uf::graph::tick( pod::Graph::Storage& storage ) {
bool rebuild = false;
uf::stl::vector<pod::Instance> instances; instances.reserve(storage.primitives.map.size());
uf::stl::vector<pod::Instance> instances = storage.instances.flatten();
uf::stl::vector<pod::Instance::Addresses> instanceAddresses = storage.instanceAddresses.flatten();
uf::stl::vector<pod::Matrix4f> joints; joints.reserve(storage.joints.map.size());
uf::stl::vector<pod::Instance::Object> objects = storage.objects.flatten();
for ( auto& key : storage.primitives.keys ) {
for ( auto& primitive : storage.primitives.map[key] ) {
instances.emplace_back( primitive.instance );
}
}
for ( auto& key : storage.joints.keys ) {
auto& matrices = storage.joints.map[key];
joints.reserve( joints.size() + matrices.size() );
for ( auto& mat : matrices ) joints.emplace_back( mat );
}
rebuild = storage.buffers.instance.update( (const void*) instances.data(), instances.size() * sizeof(pod::Instance) ) || rebuild;
rebuild = storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) ) || rebuild;
rebuild = storage.buffers.joint.update( (const void*) joints.data(), joints.size() * sizeof(pod::Matrix4f) ) || rebuild;
@ -1455,13 +1469,9 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) {
if ( ::newGraphAdded ) {
uf::stl::vector<pod::Material> materials = storage.materials.flatten();
uf::stl::vector<pod::Texture> textures = storage.textures.flatten();
uf::stl::vector<pod::DrawCommand> drawCommands; drawCommands.reserve(storage.primitives.map.size());
uf::stl::vector<pod::DrawCommand> drawCommands; drawCommands.reserve(storage.drawCommands.map.size());
for ( auto& key : storage.primitives.keys ) {
for ( auto& primitive : storage.primitives.map[key] ) {
drawCommands.emplace_back( primitive.drawCommand );
}
}
for ( auto& key : storage.drawCommands.keys ) drawCommands.insert( drawCommands.end(), storage.drawCommands.map[key].begin(), storage.drawCommands.map[key].end() );
rebuild = storage.buffers.drawCommands.update( (const void*) drawCommands.data(), drawCommands.size() * sizeof(pod::DrawCommand) ) || rebuild;
rebuild = storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) ) || rebuild;
@ -1521,7 +1531,7 @@ void uf::graph::render( pod::Graph::Storage& storage ) {
storage.buffers.camera.update( (const void*) &viewport, sizeof(pod::Camera::Viewports) );
#if UF_USE_VULKAN
if ( !renderMode || !renderMode->hasBuffer("camera") || renderMode->getType() == "Swapchain" ) return; // for some reason causes clang ASAN to cry
if ( !renderMode || !renderMode->hasBuffer("camera") || renderMode->getType() == "Swapchain" ) return;
auto& buffer = renderMode->getBuffer("camera");
buffer.update( (const void*) &viewport, sizeof(pod::Camera::Viewports) );
#endif
@ -1929,7 +1939,6 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
// bind mesh to physics state
// to-do: figure out why the mesh just suddenly breaks when re-streamed in dreamcast (could just be the version of reactphysics)
{
#if UF_USE_REACTPHYSICS
auto phyziks = tag["physics"];
if ( !ext::json::isObject( phyziks ) ) phyziks = metadataJson["physics"];
else metadataJson["physics"] = phyziks;
@ -1937,39 +1946,22 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
if ( ext::json::isObject( phyziks ) ) {
uf::stl::string type = phyziks["type"].as<uf::stl::string>();
if ( type == "mesh" ) {
bool exists = entity.hasComponent<pod::PhysicsState>();
bool exists = entity.hasComponent<pod::PhysicsBody>();
if ( exists ) {
uf::physics::impl::destroy( entity );
}
auto& collider = entity.getComponent<pod::PhysicsState>();
collider.stats.mass = phyziks["mass"].as(collider.stats.mass);
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 );
collider.stats.gravity = uf::vector::decode( phyziks["gravity"], collider.stats.gravity );
auto& physicsBody = entity.getComponent<pod::PhysicsBody>();
float mass = phyziks["mass"].as(physicsBody.mass);
physicsBody.material.staticFriction = phyziks["friction"].as(physicsBody.material.staticFriction);
physicsBody.material.restitution = phyziks["restitution"].as(physicsBody.material.restitution);
physicsBody.inertiaTensor = uf::vector::decode( phyziks["inertia"], physicsBody.inertiaTensor );
physicsBody.gravity = uf::vector::decode( phyziks["gravity"], physicsBody.gravity );
uf::physics::impl::create( entity, mesh, !phyziks["static"].as<bool>(true) );
uf::physics::impl::create( entity.as<uf::Object>(), mesh, mass );
}
}
#else
auto phyziks = tag["physics"];
if ( !ext::json::isObject( phyziks ) ) phyziks = metadataJson["physics"];
else metadataJson["physics"] = phyziks;
if ( ext::json::isObject( phyziks ) ) {
uf::stl::string type = phyziks["type"].as<uf::stl::string>();
if ( type == "mesh" ) {
bool exists = entity.hasComponent<pod::RigidBody>();
if ( exists ) {
uf::physics::impl::destroy( entity );
}
auto mass = phyziks["mass"].as(0.0f);
uf::physics::impl::create( entity, mesh, mass );
}
}
#endif
}
}
void uf::graph::reload( pod::Graph& graph ) {
@ -2061,4 +2053,4 @@ void uf::graph::update( pod::Graph& graph, float delta ) {
#endif
uf::graph::updateAnimation( graph, delta );
}
}

View File

@ -131,29 +131,6 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
if ( ext::json::isObject(metadataJson["physics"]) ) {
auto& metadataJsonPhysics = metadataJson["physics"];
#if UF_USE_REACTPHYSICS
auto& collider = this->getComponent<pod::PhysicsState>();
collider.stats.flags = metadataJsonPhysics["flags"].as(collider.stats.flags);
collider.stats.mass = metadataJsonPhysics["mass"].as(collider.stats.mass);
collider.stats.restitution = metadataJsonPhysics["restitution"].as(collider.stats.restitution);
collider.stats.friction = metadataJsonPhysics["friction"].as(collider.stats.friction);
collider.stats.inertia = uf::vector::decode( metadataJsonPhysics["inertia"], collider.stats.inertia );
collider.stats.gravity = uf::vector::decode( metadataJsonPhysics["gravity"], collider.stats.gravity );
if ( metadataJsonPhysics["type"].as<uf::stl::string>() == "bounding box" ) {
pod::Vector3f center = uf::vector::decode( metadataJsonPhysics["center"], pod::Vector3f{} );
pod::Vector3f corner = uf::vector::decode( metadataJsonPhysics["corner"], pod::Vector3f{0.5, 0.5, 0.5} );
if ( metadataJsonPhysics["recenter"].as<bool>(true) ) collider.transform.position = (center - transform.position);
uf::physics::impl::create( *this, corner );
} else if ( metadataJsonPhysics["type"].as<uf::stl::string>() == "capsule" ) {
float radius = metadataJsonPhysics["radius"].as<float>();
float height = metadataJsonPhysics["height"].as<float>();
uf::physics::impl::create( *this, radius, height );
}
#else
auto type = metadataJsonPhysics["type"].as<uf::stl::string>();
float mass = metadataJsonPhysics["mass"].as<float>();
@ -162,6 +139,10 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
if ( type == "bounding box" || 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} );
#if UF_USE_REACTPHYSICS
auto center = ( max + min ) * 0.5f;
if ( metadataJsonPhysics["recenter"].as<bool>(true) ) offset = (center - transform.position);
#endif
uf::physics::impl::create( self, pod::AABB{ .min = min, .max = max }, mass, offset );
} else if ( type == "plane" ) {
@ -175,20 +156,39 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
uf::physics::impl::create( self, pod::Sphere{ radius }, mass, offset );
} else if ( type == "capsule" ) {
float radius = metadataJsonPhysics["radius"].as<float>();
float height = metadataJsonPhysics["height"].as<float>();
float halfHeight = metadataJsonPhysics["height"].as<float>() * 0.5f;
uf::physics::impl::create( self, pod::Capsule{ radius, height * 0.5f }, mass, offset );
uf::physics::impl::create( self, pod::Capsule{ radius, halfHeight }, mass, offset );
}
if ( this->hasComponent<pod::RigidBody>() ) {
auto& body = this->getComponent<pod::RigidBody>();
if ( this->hasComponent<pod::PhysicsBody>() ) {
auto& physicsBody = this->getComponent<pod::PhysicsBody>();
auto gravity = uf::vector::decode( metadataJsonPhysics["gravity"], physicsBody.gravity );
auto category = metadataJsonPhysics["category"].as<uf::stl::string>("ALL");
auto mask = metadataJsonPhysics["mask"].as<uf::stl::string>("ALL");
#if UF_USE_REACTPHYSICS
physicsBody.mass = mass;
physicsBody.gravity = gravity;
physicsBody.material.restitution = metadataJsonPhysics["restitution"].as(physicsBody.material.restitution);
physicsBody.material.staticFriction = metadataJsonPhysics["friction"].as(physicsBody.material.staticFriction);
physicsBody.inertiaTensor = uf::vector::decode( metadataJsonPhysics["inertia"], physicsBody.inertiaTensor );
#else
uf::physics::impl::setColliderCategory( physicsBody, category );
uf::physics::impl::setColliderMask( physicsBody, mask );
uf::physics::impl::setGravity( physicsBody, gravity );
#endif
physicsBody.velocity = uf::vector::decode( metadataJsonPhysics["velocity"], physicsBody.velocity );
physicsBody.angularVelocity = uf::vector::decode( metadataJsonPhysics["angularVelocity"], physicsBody.angularVelocity );
if ( this->getName() == "Player" ) {
body.inertiaTensor = { FLT_MAX, FLT_MAX, FLT_MAX };
body.inverseInertiaTensor = { 0.0f, 0.0f, 0.0f };
physicsBody.inertiaTensor = { FLT_MAX, FLT_MAX, FLT_MAX };
physicsBody.inverseInertiaTensor = { 0.0f, 0.0f, 0.0f };
}
}
#endif
}
UF_BEHAVIOR_METADATA_BIND_SERIALIZER_HOOKS(metadata, metadataJson);
@ -232,10 +232,10 @@ void uf::ObjectBehavior::destroy( uf::Object& self ) {
// this->deleteComponent<uf::Atlas>();
}
#if UF_USE_REACTPHYSICS
if ( this->hasComponent<pod::PhysicsState>() ) {
auto& collider = this->getComponent<pod::PhysicsState>();
uf::physics::impl::detach( collider );
// this->deleteComponent<pod::PhysicsState>();
if ( this->hasComponent<pod::PhysicsBody>() ) {
auto& physicsBody = this->getComponent<pod::PhysicsBody>();
uf::physics::impl::detach( physicsBody );
// this->deleteComponent<pod::PhysicsBody>();
}
#endif
if ( this->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {

View File

@ -345,16 +345,6 @@ bool uf::Object::load( const uf::Serializer& _json ) {
}
}
}
// Set movement
#if UF_USE_REACTPHYSICS
if ( ext::json::isObject( json["physics"] ) && !this->hasComponent<pod::Physics>() ) {
auto& physics = this->getComponent<pod::Physics>();
physics.velocity = uf::vector::decode( json["physics"]["linear"]["velocity"], physics.velocity );
physics.acceleration = uf::vector::decode( json["physics"]["linear"]["acceleration"], physics.acceleration );
physics.angularVelocity = uf::vector::decode( json["physics"]["rotational"]["velocity"], physics.angularVelocity );
physics.angularAcceleration = uf::vector::decode( json["physics"]["rotational"]["acceleration"], physics.angularAcceleration );
}
#endif
// Load assets
this->loadAssets( json );

View File

@ -253,7 +253,8 @@ void ext::gltf::load( pod::Graph& graph, const uf::stl::string& filename, const
}
// load meshes
{
size_t masterAuxID = 0;
size_t masterInstanceID = 0;
graph.meshes.reserve(model.meshes.size());
storage.meshes.reserve(model.meshes.size());

View File

@ -383,18 +383,15 @@ if ( meshopt.should ) {
primitives.reserve( meshlets.size() );
for ( auto& meshlet : meshlets ) {
// to-do: check against the meshlet's actual primitive information
auto& drawCommand = drawCommands.emplace_back(pod::DrawCommand{
.indices = meshlet.indices.size(),
.instances = 1,
.indexID = indexID,
.vertexID = vertexID,
.instanceID = meshlet.primitive.drawCommand.instanceID,
.auxID = meshlet.primitive.drawCommand.auxID,
.materialID = meshlet.primitive.drawCommand.materialID,
.vertices = meshlet.vertices.size(),
});
meshlet.primitive.drawCommand.instances = 1;
meshlet.primitive.drawCommand.instanceID = ++masterInstanceID; // this doesn't matter......
meshlet.primitive.drawCommand.indexID = indexID;
meshlet.primitive.drawCommand.indices = meshlet.indices.size();
meshlet.primitive.drawCommand.vertexID = vertexID;
meshlet.primitive.drawCommand.vertices = meshlet.vertices.size();
drawCommands.emplace_back(meshlet.primitive.drawCommand);
primitives.emplace_back( meshlet.primitive );
indexID += meshlet.indices.size();

View File

@ -1,54 +1,56 @@
#include <uf/ext/lua/lua.h>
#if UF_USE_LUA && UF_USE_REACTPHYSICS
#if UF_USE_LUA
#include <uf/utils/math/physics.h>
namespace binds {
bool hasBody( pod::Physics& self ) { return self.body; }
pod::Vector3f& linearVelocity( pod::Physics& self ) { return self.velocity; }
pod::Quaternion<>& rotationalVelocity( pod::Physics& self ) { return self.angularVelocity; }
bool hasBody( pod::PhysicsBody& self ) { return !!self.object; }
pod::Vector3f& velocity( pod::PhysicsBody& self ) { return self.velocity; }
void setVelocity( pod::PhysicsBody& self, const pod::Vector3f& v ) { self.velocity = v; }
void applyVelocity( pod::PhysicsBody& self, const pod::Vector3f& v ) { self.velocity += v; }
void setLinearVelocity( pod::Physics& self, const pod::Vector3f& v ) { self.velocity = v; }
void setRotationalVelocity( pod::Physics& self, const pod::Quaternion<>& v ) { self.angularVelocity = v; }
void enableGravity( pod::PhysicsState& state, bool s ) {
if ( !state.body ) return;
state.body->enableGravity(s);
void enableGravity( pod::PhysicsBody& state, bool s ) {
if ( !state.object ) return;
#if UF_USE_REACTPHYSICS
state.collider.body->enableGravity(s);
#else
if ( s ) {
uf::physics::impl::setGravity( state, pod::Vector3f{ 0, -9.81f, 0 } );
} else {
uf::physics::impl::setGravity( state );
}
#endif
}
void applyRotation( pod::PhysicsState& state, const pod::Quaternion<>& q ) {
void applyRotation( pod::PhysicsBody& state, const pod::Quaternion<>& q ) {
return uf::physics::impl::applyRotation( state, q );
}
std::tuple<uf::Object*, float> rayCast( pod::Physics& self, const pod::Vector3f& center, const pod::Vector3f& direction ) {
float depth = -1;
uf::Object* object = uf::physics::impl::rayCast(self, center, direction, depth);
std::tuple<uf::Object*, float> rayCast( pod::PhysicsBody& self, const pod::Vector3f& center, const pod::Vector3f& direction ) {
pod::RayQuery query = uf::physics::impl::rayCast( pod::Ray{center, 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 );
}
}
#include <uf/ext/lua/component.h>
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Physics,
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( linearVelocity, UF_LUA_C_FUN(::binds::linearVelocity) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( rotationalVelocity, UF_LUA_C_FUN(::binds::rotationalVelocity) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( velocity, UF_LUA_C_FUN(::binds::velocity) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( setLinearVelocity, UF_LUA_C_FUN(::binds::setLinearVelocity) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( setRotationalVelocity, UF_LUA_C_FUN(::binds::setRotationalVelocity) ),
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(uf::physics::impl::setVelocity) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( setImpulse, UF_LUA_C_FUN(uf::physics::impl::setImpulse) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( applyImpulse, UF_LUA_C_FUN(uf::physics::impl::applyImpulse) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( applyMovement, UF_LUA_C_FUN(uf::physics::impl::applyMovement) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( applyVelocity, UF_LUA_C_FUN(uf::physics::impl::applyVelocity) ),
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( activateCollision, UF_LUA_C_FUN(uf::physics::impl::activateCollision) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( rayCast, UF_LUA_C_FUN(::binds::rayCast) )
// UF_LUA_REGISTER_USERTYPE_DEFINE( setImpulse, UF_LUA_C_FUN(uf::physics::impl::setImpulse) ),
// UF_LUA_REGISTER_USERTYPE_DEFINE( activateCollision, UF_LUA_C_FUN(uf::physics::impl::activateCollision) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( rayCast, UF_LUA_C_FUN(::binds::rayCast) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( getMass, UF_LUA_C_FUN(uf::physics::impl::getMass) ),
UF_LUA_REGISTER_USERTYPE_DEFINE( setMass, UF_LUA_C_FUN(uf::physics::impl::setMass) )
// UF_LUA_REGISTER_USERTYPE_DEFINE( getMass, UF_LUA_C_FUN(uf::physics::impl::getMass) ),
// UF_LUA_REGISTER_USERTYPE_DEFINE( setMass, UF_LUA_C_FUN(uf::physics::impl::setMass) ),
)
#endif

View File

@ -212,7 +212,7 @@ namespace {
// allows showing collision models
void debugDraw( uf::Object& object ) {
auto& scene = uf::scene::getCurrentScene();
auto& world = ext::reactphysics::globalStorage ? ::world : scene.getComponent<ext::reactphysics::WorldState>();
auto& world = /*ext::reactphysics::globalStorage ? ::world :*/ scene.getComponent<ext::reactphysics::WorldState>();
static size_t oldCount = 0;
uf::Mesh mesh;
@ -322,7 +322,7 @@ void ext::reactphysics::initialize( uf::Object& scene ) {
// logger->addFileDestination("./data/logs/rp3d_log_.html", logLevel, rp3d::DefaultLogger::Format::HTML);
// ::common.setLogger(::logger);
auto& world = ext::reactphysics::globalStorage ? ::world : scene.getComponent<ext::reactphysics::WorldState>();
auto& world = /*ext::reactphysics::globalStorage ? ::world :*/ scene.getComponent<ext::reactphysics::WorldState>();
world = ::common.createPhysicsWorld(settings);
// world->setEventListener(&::listener);
@ -340,7 +340,7 @@ void ext::reactphysics::tick( float delta ) {
return ext::reactphysics::tick( uf::scene::getCurrentScene(), delta );
}
void ext::reactphysics::tick( uf::Object& scene, float delta ) {
auto& world = ext::reactphysics::globalStorage ? ::world : scene.getComponent<ext::reactphysics::WorldState>();
auto& world = /*ext::reactphysics::globalStorage ? ::world :*/ scene.getComponent<ext::reactphysics::WorldState>();
ext::reactphysics::syncTo( world );
static float accumulator = 0;
@ -360,15 +360,15 @@ void ext::reactphysics::terminate() {
return ext::reactphysics::terminate( uf::scene::getCurrentScene() );
}
void ext::reactphysics::terminate( uf::Object& scene ) {
auto& world = ext::reactphysics::globalStorage ? ::world : scene.getComponent<ext::reactphysics::WorldState>();
auto& world = /*ext::reactphysics::globalStorage ? ::world :*/ scene.getComponent<ext::reactphysics::WorldState>();
if ( !world ) return;
size_t count = world->getNbRigidBodies();
for ( size_t i = 0; i < count; ++i ) {
auto* body = world->getRigidBody(i); if ( !body ) continue;
uf::Object* object = (uf::Object*) body->getUserData(); if ( !object || !object->isValid() ) continue;
auto& state = object->getComponent<pod::PhysicsState>(); // if ( !state.shared ) continue;
state.body = NULL;
auto& state = object->getComponent<pod::PhysicsBody>();
state.collider.body = NULL;
}
::common.destroyPhysicsWorld(world);
@ -376,22 +376,22 @@ void ext::reactphysics::terminate( uf::Object& scene ) {
}
// base collider creation
pod::PhysicsState& ext::reactphysics::create( uf::Object& object ) {
auto& state = object.getComponent<pod::PhysicsState>();
pod::PhysicsBody& ext::reactphysics::create( uf::Object& object, float mass, const pod::Vector3f& offset ) {
auto& state = object.getComponent<pod::PhysicsBody>();
state.world = ext::reactphysics::globalStorage ? ::world : uf::scene::getCurrentScene().getComponent<ext::reactphysics::WorldState>();
state.uid = object.getUid();
state.object = &object;
state.transform.position = offset;
state.transform.reference = &object.getComponent<pod::Transform<>>();
state.shared = ext::reactphysics::shared;
UF_MSG_DEBUG("Created physics state: {}", uf::string::toString( object ));
state.mass = mass;
state.isStatic = mass != 0.0f;
state.inverseMass = mass == 0.0f ? 0.0f : 1.0f / mass;
return state;
}
void ext::reactphysics::destroy( uf::Object& object ) {
auto& state = object.getComponent<pod::PhysicsState>();
auto& state = object.getComponent<pod::PhysicsBody>();
ext::reactphysics::destroy( state );
auto uid = object.getUid();
@ -403,14 +403,14 @@ void ext::reactphysics::destroy( uf::Object& object ) {
::triangleParts.erase( uid );
}
}
void ext::reactphysics::destroy( pod::PhysicsState& state ) {
void ext::reactphysics::destroy( pod::PhysicsBody& state ) {
ext::reactphysics::detach( state );
}
void ext::reactphysics::attach( pod::PhysicsState& state ) {
if ( !state.shape || !state.world ) return;
void ext::reactphysics::attach( pod::PhysicsBody& state ) {
if ( !state.collider.shape || !state.world ) return;
// auto& scene = uf::scene::getCurrentScene();
// auto& world = ext::reactphysics::globalStorage ? ::world : scene.getComponent<ext::reactphysics::WorldState>();
// auto& world = /*ext::reactphysics::globalStorage ? ::world :*/ scene.getComponent<ext::reactphysics::WorldState>();
rp3d::Transform colliderTransform = rp3d::Transform::identity();
colliderTransform.setPosition( ::convert( state.transform.position ) );
@ -419,77 +419,88 @@ void ext::reactphysics::attach( pod::PhysicsState& state ) {
state.transform.position = {};
state.transform.orientation = {};
state.body = state.world->createRigidBody( ::convert( *state.transform.reference ) );
state.collider.body = state.world->createRigidBody( ::convert( *state.transform.reference ) );
auto* collider = state.body->addCollider(state.shape, colliderTransform);
auto* collider = state.collider.body->addCollider(state.collider.shape, colliderTransform);
collider->setCollisionCategoryBits(0xFF);
collider->setCollideWithMaskBits(0xFF);
state.body->setUserData(state.object);
state.body->setMass(state.stats.mass);
state.collider.body->setUserData(state.object);
state.collider.body->setMass(state.mass);
if ( state.stats.mass != 0.0f ) {
state.body->setType(rp3d::BodyType::DYNAMIC);
state.body->updateLocalCenterOfMassFromColliders();
state.body->updateMassPropertiesFromColliders();
if ( state.mass != 0.0f ) {
state.collider.body->setType(rp3d::BodyType::DYNAMIC);
state.collider.body->updateLocalCenterOfMassFromColliders();
state.collider.body->updateMassPropertiesFromColliders();
} else {
state.body->setType(rp3d::BodyType::STATIC);
state.collider.body->setType(rp3d::BodyType::STATIC);
}
state.body->enableGravity(state.stats.gravity != pod::Vector3f{0,0,0});
state.collider.body->enableGravity(state.gravity != pod::Vector3f{0,0,0});
// affects air speed, bad
// state.body->setLinearDamping(state.stats.friction);
// state.collider.body->setLinearDamping(state.material.staticFriction);
auto& material = collider->getMaterial();
material.setBounciness(0);
state.body->setLocalInertiaTensor( ::convert( state.stats.inertia ) );
state.collider.body->setLocalInertiaTensor( ::convert( state.inertiaTensor ) );
}
void ext::reactphysics::detach( pod::PhysicsState& state ) {
if ( !state.body || !state.world ) return;
void ext::reactphysics::detach( pod::PhysicsBody& state ) {
if ( !state.collider.body || !state.world ) return;
// auto& scene = uf::scene::getCurrentScene();
// auto& world = ext::reactphysics::globalStorage ? ::world : scene.getComponent<ext::reactphysics::WorldState>();
// auto& world = /*ext::reactphysics::globalStorage ? ::world :*/ scene.getComponent<ext::reactphysics::WorldState>();
state.world->destroyRigidBody(state.body);
state.body = NULL;
state.world->destroyRigidBody(state.collider.body);
state.collider.body = NULL;
state = {}; // necessary if it gets reused
}
// collider for mesh (static or dynamic)
pod::PhysicsState& ext::reactphysics::create( uf::Object& object, const uf::Mesh& mesh, bool dynamic ) {
pod::PhysicsBody& ext::reactphysics::create( uf::Object& object, const uf::Mesh& mesh, float mass, const pod::Vector3f& offset ) {
UF_ASSERT( mesh.index.count );
auto* rMesh = ::createTriangleMesh( mesh, object );
auto& state = ext::reactphysics::create( object );
state.shape = ::common.createConcaveMeshShape( rMesh );
state.stats.mass = 0;
auto& state = ext::reactphysics::create( object, mass, offset );
state.collider.shape = ::common.createConcaveMeshShape( rMesh );
state.mass = 0;
ext::reactphysics::attach( state );
UF_MSG_DEBUG("Created physics state (mesh): {}", uf::string::toString( object ));
return state;
}
// collider for boundingbox
pod::PhysicsState& ext::reactphysics::create( uf::Object& object, const pod::Vector3f& extent ) {
auto& state = ext::reactphysics::create( object );
state.shape = ::common.createBoxShape( rp3d::Vector3( abs(extent.x), abs(extent.y), abs(extent.z) ) );
pod::PhysicsBody& ext::reactphysics::create( uf::Object& object, const pod::AABB& aabb, float mass, const pod::Vector3f& offset ) {
pod::Vector3f extent = ( aabb.max - aabb.min ) * 0.5f;
auto& state = ext::reactphysics::create( object, mass, offset );
state.collider.shape = ::common.createBoxShape( rp3d::Vector3( abs(extent.x), abs(extent.y), abs(extent.z) ) );
ext::reactphysics::attach( state );
return state;
}
//
pod::PhysicsBody& ext::reactphysics::create( uf::Object& object, const pod::Sphere& aabb, float mass, const pod::Vector3f& offset ) {
auto& state = ext::reactphysics::create( object, mass, offset );
//state.collider.shape = ::common.createSphereShape( rp3d::Vector3( abs(extent.x), abs(extent.y), abs(extent.z) ) );
ext::reactphysics::attach( state );
return state;
}
//
pod::PhysicsBody& ext::reactphysics::create( uf::Object& object, const pod::Plane& aabb, float mass, const pod::Vector3f& offset ) {
auto& state = ext::reactphysics::create( object, mass, offset );
//state.collider.shape = ::common.createPlaneShape( rp3d::Vector3( abs(extent.x), abs(extent.y), abs(extent.z) ) );
ext::reactphysics::attach( state );
UF_MSG_DEBUG("Created physics state (box): {}", uf::string::toString( object ));
return state;
}
// collider for capsule
pod::PhysicsState& ext::reactphysics::create( uf::Object& object, float radius, float height ) {
auto& state = ext::reactphysics::create( object );
state.shape = ::common.createCapsuleShape( radius, height );
pod::PhysicsBody& ext::reactphysics::create( uf::Object& object, const pod::Capsule& capsule, float mass, const pod::Vector3f& offset ) {
auto& state = ext::reactphysics::create( object, mass, offset );
state.collider.shape = ::common.createCapsuleShape( capsule.radius, capsule.halfHeight * 2.0f );
ext::reactphysics::attach( state );
UF_MSG_DEBUG("Created physics state (capsule): {} | {}, {}", uf::string::toString( object ), radius, height);
return state;
}
@ -512,9 +523,9 @@ void ext::reactphysics::syncTo( ext::reactphysics::WorldState& world ) {
for ( size_t i = 0; i < count; ++i ) {
auto* body = world->getRigidBody(i); if ( !body ) continue;
uf::Object* object = (uf::Object*) body->getUserData(); if ( !object || !object->isValid() ) continue;
auto& state = object->getComponent<pod::PhysicsState>(); // if ( !state.shared ) continue;
auto& state = object->getComponent<pod::PhysicsBody>();
if ( state.shared ) {
if ( true /*state\.shared*/ ) {
if ( !ext::reactphysics::interpolate ) body->setTransform(::convert(state.transform));
body->setLinearVelocity( ::convert(state.velocity) );
body->setAngularVelocity( ::convertQ(state.angularVelocity) );
@ -524,9 +535,9 @@ void ext::reactphysics::syncTo( ext::reactphysics::WorldState& world ) {
switch ( ext::reactphysics::gravity::mode ) {
case ext::reactphysics::gravity::Mode::PER_OBJECT: if ( body->isGravityEnabled() ) {
#if RP3D_OLD
body->applyForceToCenterOfMass( ::convert(state.stats.gravity * mass) );
body->applyForceToCenterOfMass( ::convert(state.gravity * mass) );
#else
body->applyLocalForceAtCenterOfMass( ::convert(state.stats.gravity * mass) );
body->applyLocalForceAtCenterOfMass( ::convert(state.gravity * mass) );
#endif
} break;
case ext::reactphysics::gravity::Mode::UNIVERSAL: if ( mass > 0 ) {
@ -575,170 +586,131 @@ void ext::reactphysics::syncFrom( ext::reactphysics::WorldState& world, float in
auto* body = world->getRigidBody(i); if ( !body ) continue;
uf::Object* object = (uf::Object*) body->getUserData(); if ( !object || !object->isValid() ) continue;
auto& state = object->getComponent<pod::PhysicsState>();
if ( !state.object ) {
state.object = object;
//continue;
}
auto& state = object->getComponent<pod::PhysicsBody>();
if ( !state.object ) state.object = object;
auto& transform = state.object->getComponent<pod::Transform<>>();
auto& physics = state.object->getComponent<pod::Physics>();
/*
transform.position = ::convert( body->getTransform().getPosition() );
transform.orientation = ::convert( body->getTransform().getOrientation() );
// state transform is an offset, un-offset
if ( state.transform.reference ) transform.position -= state.transform.position;
// transform = uf::transform::reorient( transform );
*/
state.internal.current.transform = ::convert( body->getTransform() );
state.internal.current.velocity = ::convert( body->getLinearVelocity() );
state.internal.current.angularVelocity = ::convertQ( body->getAngularVelocity() );
physics.velocity = state.internal.current.velocity;
physics.angularVelocity = state.internal.current.angularVelocity;
state.velocity = state.internal.current.velocity;
state.angularVelocity = state.internal.current.angularVelocity;
if ( !ext::reactphysics::interpolate ) {
transform.position = state.internal.current.transform.position;
transform.orientation = state.internal.current.transform.orientation;
// state transform is an offset, un-offset
if ( state.transform.reference ) transform.position -= state.transform.position;
// transform = uf::transform::reorient( transform );
} else {
// transform = uf::transform::interpolate( state.internal.previous.transform, state.internal.current.transform, interp );
transform.position = state.internal.previous.transform.position * ( 1.0f - interp ) + state.internal.current.transform.position * interp;
transform.orientation = uf::quaternion::slerp( state.internal.previous.transform.orientation, state.internal.current.transform.orientation, interp);
// state transform is an offset, un-offset
if ( state.transform.reference ) transform.position -= state.transform.position;
// physics.velocity = uf::vector::lerp( state.internal.previous.velocity, state.internal.current.velocity, interp );
// physics.angularVelocity = uf::quaternion::slerp( state.internal.previous.angularVelocity, state.internal.current.angularVelocity, interp );
}
}
}
// apply impulse
void ext::reactphysics::setImpulse( pod::PhysicsState& state, const pod::Vector3f& v ) {
if ( !state.body ) return;
void ext::reactphysics::setImpulse( pod::PhysicsBody& state, const pod::Vector3f& v ) {
if ( !state.collider.body ) return;
#if !RP3D_OLD
state.body->resetForce();
state.body->resetTorque();
state.collider.body->resetForce();
state.collider.body->resetTorque();
#endif
state.body->setLinearVelocity( ::convert(pod::Vector3f{}) );
state.body->setAngularVelocity( ::convert(pod::Vector3f{}) );
state.collider.body->setLinearVelocity( ::convert(pod::Vector3f{}) );
state.collider.body->setAngularVelocity( ::convert(pod::Vector3f{}) );
// ext::reactphysics::applyImpulse( state, v );
}
void ext::reactphysics::applyImpulse( pod::PhysicsState& state, const pod::Vector3f& v ) {
if ( !state.body ) return;
void ext::reactphysics::applyImpulse( pod::PhysicsBody& state, const pod::Vector3f& v ) {
if ( !state.collider.body ) return;
#if RP3D_OLD
state.body->applyForceToCenterOfMass( ::convert(v) );
state.collider.body->applyForceToCenterOfMass( ::convert(v) );
#else
state.body->applyLocalForceAtCenterOfMass( ::convert(v) );
state.collider.body->applyLocalForceAtCenterOfMass( ::convert(v) );
#endif
}
// directly move a transform
void ext::reactphysics::applyMovement( pod::PhysicsState& state, const pod::Vector3f& v ) {
if ( !state.body ) return;
void ext::reactphysics::applyMovement( pod::PhysicsBody& state, const pod::Vector3f& v ) {
if ( !state.collider.body ) return;
rp3d::Transform transform = state.body->getTransform();
rp3d::Transform transform = state.collider.body->getTransform();
transform.setPosition( transform.getPosition() + ::convert(v) * uf::physics::time::delta );
state.body->setTransform(transform);
state.collider.body->setTransform(transform);
}
// directly apply a velocity
void ext::reactphysics::setVelocity( pod::PhysicsState& state, const pod::Vector3f& v ) {
if ( !state.body ) return;
if ( state.shared ) {
auto& physics = state.object->getComponent<pod::Physics>();
physics.velocity = v;
// return;
}
state.body->setLinearVelocity( ::convert(v) );
void ext::reactphysics::setVelocity( pod::PhysicsBody& state, const pod::Vector3f& v ) {
if ( !state.collider.body ) return;
state.velocity = v;
state.collider.body->setLinearVelocity( ::convert(v) );
}
void ext::reactphysics::applyVelocity( pod::PhysicsState& state, const pod::Vector3f& v ) {
if ( !state.body ) return;
void ext::reactphysics::applyVelocity( pod::PhysicsBody& state, const pod::Vector3f& v ) {
if ( !state.collider.body ) return;
if ( state.shared ) {
auto& physics = state.object->getComponent<pod::Physics>();
physics.velocity += v;
// return;
}
state.body->setLinearVelocity( state.body->getLinearVelocity() + ::convert(v) );
state.velocity += v;
state.collider.body->setLinearVelocity( state.collider.body->getLinearVelocity() + ::convert(v) );
}
// directly rotate a transform
void ext::reactphysics::applyRotation( pod::PhysicsState& state, const pod::Quaternion<>& q ) {
if ( !state.body ) return;
void ext::reactphysics::applyRotation( pod::PhysicsBody& state, const pod::Quaternion<>& q ) {
if ( !state.collider.body ) return;
if ( state.shared ) {
auto& transform = state.object->getComponent<pod::Transform<>>();
uf::transform::rotate( transform, q );
// return;
}
auto transform = state.body->getTransform();
uf::transform::rotate( state.object->getComponent<pod::Transform<>>(), q );
auto transform = state.collider.body->getTransform();
transform.setOrientation( transform.getOrientation() * ::convert( q ) );
state.body->setTransform(transform);
state.collider.body->setTransform(transform);
}
void ext::reactphysics::applyRotation( pod::PhysicsState& state, const pod::Vector3f& axis, float delta ) {
void ext::reactphysics::applyRotation( pod::PhysicsBody& state, const pod::Vector3f& axis, float delta ) {
ext::reactphysics::applyRotation( state, uf::quaternion::axisAngle( axis, delta ) );
}
// ray casting
uf::Object* ext::reactphysics::rayCast( const pod::Vector3f& center, const pod::Vector3f& direction ) {
float depth = -1;
return rayCast( center, direction, NULL, depth );
}
uf::Object* ext::reactphysics::rayCast( pod::PhysicsState& state, const pod::Vector3f& center, const pod::Vector3f& direction ) {
float depth = -1;
return rayCast( center, direction, state.object, depth );
}
uf::Object* ext::reactphysics::rayCast( pod::PhysicsState& state, const pod::Vector3f& center, const pod::Vector3f& direction, float& depth ) {
return rayCast( center, direction, state.object, depth );
}
uf::Object* ext::reactphysics::rayCast( const pod::Vector3f& center, const pod::Vector3f& direction, uf::Object* source, float& depth ) {
pod::RayQuery ext::reactphysics::rayCast( const pod::Ray& ray, const pod::PhysicsBody& body, float maxDistance ) {
auto& scene = uf::scene::getCurrentScene();
auto& world = ext::reactphysics::globalStorage ? ::world : scene.getComponent<ext::reactphysics::WorldState>();
depth = -1;
auto& world = /*ext::reactphysics::globalStorage ? ::world :*/ scene.getComponent<ext::reactphysics::WorldState>();
if ( !world ) return NULL;
pod::RayQuery query;
query.contact.penetration = maxDistance;
if ( !world ) return query;
::RaycastCallback callback;
callback.source = source;
world->raycast( rp3d::Ray( ::convert( center ), ::convert( center + direction ) ), &callback );
if ( !callback.isHit ) return NULL;
depth = callback.raycastInfo.hitFraction;
callback.source = body.object;
world->raycast( rp3d::Ray( ::convert( ray.origin ), ::convert( ray.origin + ray.direction ) ), &callback );
if ( !callback.isHit ) return query;
uf::Object* object = (uf::Object*) callback.raycastInfo.body->getUserData();
return (uf::Object*) callback.raycastInfo.body->getUserData();
query.hit = callback.isHit;
query.body = &object->getComponent<pod::PhysicsBody>();
query.contact.contact = ray.origin + ray.direction * callback.raycastInfo.hitFraction;
query.contact.normal = ray.direction;
query.contact.penetration = callback.raycastInfo.hitFraction;
return query;
}
// allows noclip
void ext::reactphysics::activateCollision( pod::PhysicsState& state, bool s ) {
if ( !state.body ) return;
// state.body->setIsActive(s);
auto colliders = state.body->getNbColliders();
void ext::reactphysics::activateCollision( pod::PhysicsBody& state, bool s ) {
if ( !state.collider.body ) return;
// state.collider.body->setIsActive(s);
auto colliders = state.collider.body->getNbColliders();
for ( auto i = 0; i < colliders; ++i ) {
auto* collider = state.body->getCollider(i);
auto* collider = state.collider.body->getCollider(i);
collider->setCollisionCategoryBits(s ? 0xFF : 0x00);
collider->setCollideWithMaskBits(s ? 0xFF : 0x00);
}
}
float ext::reactphysics::getMass( pod::PhysicsState& state ) {
if ( !state.body ) return state.stats.mass;
float ext::reactphysics::getMass( pod::PhysicsBody& state ) {
if ( !state.collider.body ) return state.mass;
return (state.stats.mass = state.body->getMass());
return (state.mass = state.collider.body->getMass());
}
void ext::reactphysics::setMass( pod::PhysicsState& state, float mass ) {
state.stats.mass = mass;
state.body->setMass(mass);
void ext::reactphysics::setMass( pod::PhysicsBody& state, float mass ) {
state.mass = mass;
state.collider.body->setMass(mass);
}
#endif

View File

@ -62,53 +62,79 @@ size_t ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
source = mesh;
source.updateDescriptor();
for (auto& view : source.makeViews({"position", "uv", "st", "index"})) {
auto pos = view["position"];
auto uv = view["uv"];
auto st = view["st"];
auto idx = view["index"];
uf::Mesh::Input vertexInput = mesh.vertex;
// Must have positions + indices
if (!pos.valid() || !idx.valid()) continue;
if (view.vertex.count == 0 || view.index.count == 0) continue;
uf::Mesh::Attribute positionAttribute;
uf::Mesh::Attribute uvAttribute;
uf::Mesh::Attribute stAttribute;
for ( auto& attribute : mesh.vertex.attributes ) {
if ( attribute.descriptor.name == "position" ) positionAttribute = attribute;
else if ( attribute.descriptor.name == "uv" ) uvAttribute = attribute;
else if ( attribute.descriptor.name == "st" ) stAttribute = attribute;
}
UF_ASSERT( positionAttribute.descriptor.name == "position" && uvAttribute.descriptor.name == "uv" && stAttribute.descriptor.name == "st" );
if ( mesh.index.count ) {
uf::Mesh::Input indexInput = mesh.index;
uf::Mesh::Attribute indexAttribute = mesh.index.attributes.front();
// Choose xatlas index format
::xatlas::IndexFormat indexType = ::xatlas::IndexFormat::UInt32;
switch (idx.attribute.descriptor.size) {
switch ( mesh.index.size ) {
case sizeof(uint16_t): indexType = ::xatlas::IndexFormat::UInt16; break;
case sizeof(uint32_t): indexType = ::xatlas::IndexFormat::UInt32; break;
default: UF_EXCEPTION("unsupported index type"); break;
}
// Get atlas target from indirect auxID or default 0
size_t atlasID = 0;
if ( 0 <= view.indirectIndex ) {
auto* drawCommand = (pod::DrawCommand*) mesh.getBuffer(mesh.indirect).data();
atlasID = drawCommand[view.indirectIndex].auxID;
if ( mesh.indirect.count ) {
auto& primitives = /*graph.storage*/storage.primitives[name];
pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer(mesh.indirect).data();
for ( auto i = 0; i < mesh.indirect.count; ++i ) {
size_t atlasID = drawCommands[i].auxID;
vertexInput = mesh.remapVertexInput( i );
indexInput = mesh.remapIndexInput( i );
auto& atlas = atlases[atlasID];
auto& entry = atlas.entries.emplace_back();
entry.index = index;
entry.commandID = i;
auto& decl = entry.decl;
decl.vertexPositionData = static_cast<uint8_t*>(positionAttribute.pointer) + positionAttribute.stride * vertexInput.first;
decl.vertexPositionStride = positionAttribute.stride;
decl.vertexUvData = static_cast<uint8_t*>(uvAttribute.pointer) + uvAttribute.stride * vertexInput.first;
decl.vertexUvStride = uvAttribute.stride;
decl.vertexCount = vertexInput.count;
decl.indexCount = indexInput.count;
decl.indexData = static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first;
decl.indexFormat = indexType;
}
} else {
size_t atlasID = 0;
auto& atlas = atlases[atlasID];
auto& entry = atlas.entries.emplace_back();
entry.index = index;
auto& decl = entry.decl;
decl.vertexPositionData = static_cast<uint8_t*>(positionAttribute.pointer) + positionAttribute.stride * vertexInput.first;
decl.vertexPositionStride = positionAttribute.stride;
decl.vertexUvData = static_cast<uint8_t*>(uvAttribute.pointer) + uvAttribute.stride * vertexInput.first;
decl.vertexUvStride = uvAttribute.stride;
decl.vertexCount = vertexInput.count;
decl.indexCount = indexInput.count;
decl.indexData = static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first;
decl.indexFormat = indexType;
}
auto& atlas = atlases[atlasID];
auto& entry = atlas.entries.emplace_back();
entry.index = index;
auto& decl = entry.decl;
decl.vertexPositionData = pos.data(view.vertex.first);
decl.vertexPositionStride = pos.stride();
if ( uv.valid() ) {
decl.vertexUvData = uv.data(view.vertex.first);
decl.vertexUvStride = uv.stride();
} else if ( st.valid() ) {
decl.vertexUvData = st.data(view.vertex.first);
decl.vertexUvStride = st.stride();
}
decl.vertexCount = view.vertex.count;
decl.indexCount = view.index.count;
decl.indexData = idx.data(view.index.first);
decl.indexFormat = indexType;
}
} else UF_EXCEPTION("to-do: not require indices for meshes");
}
::xatlas::ChartOptions chartOptions{};

View File

@ -27,7 +27,7 @@ namespace {
};
}
std::pair<pod::Vector3f, pod::Vector3f> getCapsuleSegment( const pod::RigidBody& body ) {
std::pair<pod::Vector3f, pod::Vector3f> getCapsuleSegment( const pod::PhysicsBody& body ) {
const auto transform = ::getTransform( body );
const auto& capsule = body.collider.u.capsule;
const pod::Vector3f up = uf::quaternion::rotate( transform.orientation, pod::Vector3f{0,1,0} );
@ -38,7 +38,7 @@ namespace {
return { p1, p2 };
}
pod::AABB computeAABB( const pod::RigidBody& body ) {
pod::AABB computeAABB( const pod::PhysicsBody& body ) {
const auto transform = ::getTransform( body );
switch ( body.collider.type ) {
case pod::ShapeType::AABB: {
@ -197,7 +197,7 @@ namespace {
return ( aabb.max - aabb.min ) * 0.5f;
}
bool aabbAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool aabbAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES(AABB, AABB);
const auto& A = a.bounds;
@ -257,19 +257,19 @@ namespace {
return true;
}
bool aabbSphere( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool aabbSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( AABB, SPHERE );
return ::sphereAabb( b, a, manifold, eps );
}
bool aabbPlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool aabbPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( AABB, PLANE );
return ::planeAabb( b, a, manifold, eps );
}
bool aabbCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool aabbCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( AABB, CAPSULE );
return ::capsuleAabb( b, a, manifold, eps );
}
bool aabbMesh( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool aabbMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( AABB, MESH );
return ::meshAabb( b, a, manifold, eps );
}

View File

@ -1,50 +1,54 @@
// BVH
namespace {
// collects a list of nodes that are overlapping with each other
void traverseNodePair( const pod::BVH& bvh, int leftID, int rightID, pod::BVH::pair_t& pairs ) {
const auto& left = bvh.nodes[leftID];
const auto& right = bvh.nodes[rightID];
void traverseNodePair( const pod::BVH& bvh, int indexA, int indexB, pod::BVH::pair_t& pairs ) {
const auto& nodeA = bvh.nodes[indexA];
const auto& nodeB = bvh.nodes[indexB];
if ( !::aabbOverlap( left.bounds, right.bounds ) ) return;
if ( !::aabbOverlap( nodeA.bounds, nodeB.bounds ) ) return;
if ( left.count > 0 && right.count > 0 ) {
for ( auto i = 0; i < left.count; ++i )
for ( auto j = 0; j < right.count; ++j ) {
int a = bvh.indices[left.start + i];
int b = bvh.indices[right.start + j];
pairs.emplace_back(std::pair{a, b});
if ( nodeA.count > 0 && nodeB.count > 0 ) {
for ( auto i = 0; i < nodeA.count; ++i )
for ( auto j = 0; j < nodeB.count; ++j ) {
int indexA = bvh.indices[nodeA.start + i];
int indexB = bvh.indices[nodeB.start + j];
pairs.emplace_back(std::pair{indexA, indexB});
}
return;
}
if ( left.count == 0 ) {
::traverseNodePair( bvh, left.left, rightID, pairs );
::traverseNodePair( bvh, left.right, rightID, pairs );
} else if ( right.count == 0 ) {
::traverseNodePair( bvh, leftID, right.left, pairs );
::traverseNodePair( bvh, leftID, right.right, pairs );
if ( nodeA.count == 0 ) {
::traverseNodePair( bvh, nodeA.left, indexB, pairs );
::traverseNodePair( bvh, nodeA.right, indexB, pairs );
} else if ( nodeB.count == 0 ) {
::traverseNodePair( bvh, indexA, nodeB.left, pairs );
::traverseNodePair( bvh, indexA, nodeB.right, pairs );
}
}
// collects a list of nodes from each BVH that are overlapping with each other (for mesh v mesh)
void traverseNodePair( const pod::BVH& a, int nodeA, const pod::BVH& b, int nodeB, pod::BVH::pair_t& pairs ) {
const auto& nA = a.nodes[nodeA];
const auto& nB = b.nodes[nodeB];
void traverseNodePair( const pod::BVH& bvhA, int indexA, const pod::BVH& bvhB, int indexB, pod::BVH::pair_t& pairs ) {
const auto& nodeA = bvhA.nodes[indexA];
const auto& nodeB = bvhB.nodes[indexB];
if ( !::aabbOverlap( nA.bounds, nB.bounds ) ) return;
if ( !::aabbOverlap( nodeA.bounds, nodeB.bounds ) ) return;
if ( nA.count > 0 && nB.count > 0 ) {
for ( auto i = 0; i < nA.count; i++ )
for ( auto j = 0; j < nB.count; j++ )
pairs.emplace_back(a.indices[nA.start+i], b.indices[nB.start+j]);
if ( nodeA.count > 0 && nodeB.count > 0 ) {
for ( auto i = 0; i < nodeA.count; i++ ) {
for ( auto j = 0; j < nodeB.count; j++ ) {
auto indexA = bvhA.indices[nodeA.start+i];
auto indexB = bvhB.indices[nodeB.start+j];
pairs.emplace_back(std::pair{indexA, indexB});
}
}
return;
}
if ( nA.count == 0 ) {
::traverseNodePair( a, nA.left, b , nodeB, pairs );
::traverseNodePair( a, nA.right, b , nodeB, pairs );
} else {
::traverseNodePair( a, nodeA, b, nB.left, pairs );
::traverseNodePair( a, nodeA, b, nB.right, pairs );
if ( nodeA.count == 0 ) {
::traverseNodePair( bvhA, nodeA.left, bvhB , indexB, pairs );
::traverseNodePair( bvhA, nodeA.right, bvhB , indexB, pairs );
} else if ( nodeB.count == 0 ) {
::traverseNodePair( bvhA, indexA, bvhB, nodeB.left, pairs );
::traverseNodePair( bvhA, indexA, bvhB, nodeB.right, pairs );
}
}
@ -54,9 +58,14 @@ namespace {
if ( node.count > 0 ) {
for ( auto i = 0; i < node.count; ++i ) {
for ( auto j = i + 1; j < node.count; ++j ) {
int a = bvh.indices[node.start + i];
int b = bvh.indices[node.start + j];
pairs.emplace_back(std::pair{a, b});
int indexA = bvh.indices[node.start + i];
int indexB = bvh.indices[node.start + j];
if ( !::aabbOverlap( bvh.nodes[indexA].bounds, bvh.nodes[indexB].bounds ) ) {
continue;
}
pairs.emplace_back(std::pair{indexA, indexB});
}
}
return;
@ -113,7 +122,7 @@ namespace {
return index;
}
void buildBroadphaseBVH( pod::BVH& bvh, const uf::stl::vector<pod::RigidBody*>& bodies, int capacity = 2 ) {
void buildBroadphaseBVH( pod::BVH& bvh, const uf::stl::vector<pod::PhysicsBody*>& bodies, int capacity = 2 ) {
bvh.indices.clear();
bvh.nodes.clear();
bvh.indices.reserve(bodies.size());
@ -188,7 +197,7 @@ namespace {
}
}
}
void queryBVH( const pod::BVH& bvh, const pod::RigidBody& body, uf::stl::vector<int>& indices ) {
void queryBVH( const pod::BVH& bvh, const pod::PhysicsBody& body, uf::stl::vector<int>& indices ) {
return ::queryBVH( bvh, body.bounds, indices );
}

View File

@ -1,5 +1,5 @@
namespace {
bool capsuleCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool capsuleCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( CAPSULE, CAPSULE );
auto [ A1, A2 ] = ::getCapsuleSegment( a );
@ -20,7 +20,7 @@ namespace {
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
return true;
}
bool capsuleAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool capsuleAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( CAPSULE, AABB );
const auto& capsule = a;
const auto& box = b;
@ -43,7 +43,7 @@ namespace {
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
return true;
}
bool capsulePlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool capsulePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( CAPSULE, PLANE );
const auto& capsule = a;
const auto& plane = b;
@ -77,7 +77,7 @@ namespace {
#endif
return true;
}
bool capsuleSphere( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool capsuleSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( CAPSULE, SPHERE );
const auto& capsule = a;
const auto& sphere = b;
@ -102,7 +102,7 @@ namespace {
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
return true;
}
bool capsuleMesh( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool capsuleMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( CAPSULE, MESH );
return meshCapsule( b, a, manifold, eps );
}

View File

@ -77,7 +77,7 @@ namespace {
}
}
pod::Contact epa( const pod::RigidBody& a, const pod::RigidBody& b, const pod::Simplex& simplex, int maxIterations = 64, float eps = EPS(1.0e-4f) ) {
pod::Contact epa( const pod::PhysicsBody& a, const pod::PhysicsBody& b, const pod::Simplex& simplex, int maxIterations = 64, float eps = EPS(1.0e-4f) ) {
UF_ASSERT( ::isValidSimplex(simplex) );
auto faces = ::initialPolytope(simplex);

View File

@ -1,5 +1,5 @@
namespace {
pod::Vector3f support( const pod::RigidBody& body, const pod::Vector3f& dir ) {
pod::Vector3f support( const pod::PhysicsBody& body, const pod::Vector3f& dir ) {
const auto transform = ::getTransform( body );
switch ( body.collider.type ) {
case pod::ShapeType::SPHERE: {
@ -36,11 +36,11 @@ namespace {
return {};
}
pod::Vector3f supportMinkowski( const pod::RigidBody& A, const pod::RigidBody& B, const pod::Vector3f& dir ) {
pod::Vector3f supportMinkowski( const pod::PhysicsBody& A, const pod::PhysicsBody& B, const pod::Vector3f& dir ) {
return ::support( A, dir ) - ::support( B, -dir );
}
pod::SupportPoint supportMinkowskiDetailed( const pod::RigidBody& A, const pod::RigidBody& B, const pod::Vector3f& dir ) {
pod::SupportPoint supportMinkowskiDetailed( const pod::PhysicsBody& A, const pod::PhysicsBody& B, const pod::Vector3f& dir ) {
auto pA = ::support( A, dir );
auto pB = ::support( B, -dir );
return { pA - pB, pA, pB };
@ -149,7 +149,7 @@ namespace {
return false;
}
bool gjk( const pod::RigidBody& a, const pod::RigidBody& b, pod::Simplex& simplex, int maxIterations = 20, float eps = EPS(1e-6f) ) {
bool gjk( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Simplex& simplex, int maxIterations = 20, float eps = EPS(1e-6f) ) {
auto dir = ::getPosition( b ) - ::getPosition( a );
if ( uf::vector::magnitude(dir) < eps ) dir = {1,0,0}; // fallback direction

View File

@ -1,40 +1,40 @@
// forward declare
namespace {
bool aabbAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool aabbSphere( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool aabbPlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool aabbCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool aabbMesh( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool aabbAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool aabbSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool aabbPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool aabbCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool aabbMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool sphereSphere( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool sphereAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool spherePlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool sphereCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool sphereMesh( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool sphereSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool sphereAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool spherePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool sphereCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool sphereMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool planeAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool planeSphere( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool planePlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool planeCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool planeMesh( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool planeAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool planeSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool planePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool planeCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool planeMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool capsuleCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool capsuleAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool capsulePlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool capsuleSphere( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool capsuleMesh( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool capsuleCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool capsuleAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool capsulePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool capsuleSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool capsuleMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool meshAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool meshSphere( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool meshPlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool meshCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool meshMesh( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool meshAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool meshSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool meshPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool meshCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool meshMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool triangleTriangle( const pod::TriangleWithNormal& a, const pod::TriangleWithNormal& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool triangleAabb( const pod::TriangleWithNormal& tri, const pod::RigidBody& body, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool triangleSphere( const pod::TriangleWithNormal& tri, const pod::RigidBody& body, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool trianglePlane( const pod::TriangleWithNormal& tri, const pod::RigidBody& body, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool triangleCapsule( const pod::TriangleWithNormal& tri, const pod::RigidBody& body, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool triangleAabb( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool triangleSphere( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool trianglePlane( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
bool triangleCapsule( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
pod::Vector3f aabbCenter( const pod::AABB& aabb );
bool aabbOverlap( const pod::AABB& a, const pod::AABB& b, float eps = EPS(1.0e-6f) );
@ -53,7 +53,7 @@ namespace {
namespace {
// create ID from pointers
uint64_t makePairKey( const pod::RigidBody& a, const pod::RigidBody& b ) {
uint64_t makePairKey( const pod::PhysicsBody& a, const pod::PhysicsBody& b ) {
auto idA = reinterpret_cast<uint64_t>(&a);
auto idB = reinterpret_cast<uint64_t>(&b);
if ( idA > idB ) std::swap(idA, idB); // ensure consistent order
@ -62,18 +62,25 @@ namespace {
// returns an absolute transform while also allowing offsetting the collision body
// to-do: find a succint way to explain this madness
pod::Transform<> getTransform( const pod::RigidBody& body ) {
pod::Transform<> getTransform( const pod::PhysicsBody& body ) {
pod::Transform<> t;
t.position = body.offset;
t.reference = body.transform;
return uf::transform::flatten( t );
}
pod::Vector3f getPosition( const pod::RigidBody& body, bool useTransform = false ) {
pod::Vector3f getPosition( const pod::PhysicsBody& body, bool useTransform = false ) {
if ( !useTransform ) return ::aabbCenter( body.bounds );
return ::getTransform( body ).position;
}
bool shouldCollide( const pod::Collider& a, const pod::Collider& b ) {
return ( a.category & b.mask ) && ( b.category & a.mask );
}
bool shouldCollide( const pod::PhysicsBody& a, const pod::PhysicsBody& b ) {
return ::shouldCollide( a.collider, b.collider );
}
// normalizes the delta between two bodies / contacts by the distance (as it was already computed) if non-zero
// a lot of collider v colliders use this semantic
pod::Vector3f normalizeDelta( const pod::Vector3f& delta, float dist, float eps = EPS(1.0e-6), const pod::Vector3f& fallback = pod::Vector3f{0,1,0} ) {
@ -284,7 +291,7 @@ namespace {
return ::closestPointOnTriangle( p, tri.points[0], tri.points[1], tri.points[2] );
}
pod::Vector3f orientNormalToAB( const pod::RigidBody& a, const pod::RigidBody& b, pod::Vector3f n ) {
pod::Vector3f orientNormalToAB( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Vector3f n ) {
return uf::vector::normalize( uf::vector::dot( n, ::getPosition( b ) - ::getPosition( a ) ) < 0.0f ? -n : n );
}

View File

@ -6,14 +6,18 @@
namespace {
bool warmupSolver = true;
bool blockContactSolver = false;
bool psgContactSolver = true;
bool useGjk = false;
bool blockContactSolver = false; // blockNxN solver is flawed
bool psgContactSolver = true; // iterative solver is flawed
bool useGjk = false; // currently don't have a way to broadphase mesh => narrowphase tri via GJK
bool fixedStep = true;
int substeps = 0;
int substeps = 4;
int solverIterations = 10;
float baumgarteCorrectionPercent = 0.005f;
// increasing these make things lag
int broadphaseBvhCapacity = 1;
int meshBvhCapacity = 1;
int solverIterations = 5;
float baumgarteCorrectionPercent = 0.005f; // needs to be very small or the correction is too large
float baumgarteCorrectionSlop = 0.001f;
uf::stl::unordered_map<size_t, pod::Manifold> manifoldsCache;
}
@ -106,7 +110,7 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
uf::stl::vector<std::pair<int,int>> pairs;
// create BVH
::buildBroadphaseBVH(bvh, bodies);
::buildBroadphaseBVH( bvh, bodies, ::broadphaseBvhCapacity );
// query for overlaps
::queryOverlaps( bvh, pairs );
// iterate overlaps
@ -114,6 +118,9 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
auto& a = *bodies[ia];
auto& b = *bodies[ib];
// could be also pruned in the broadphase, but traversal needs to be agnostic between a BVH for bodies or a BVH for triangles
if ( !::shouldCollide( a, b ) ) continue;
pod::Manifold manifold;
if ( ::generateContacts( a, b, manifold, dt ) ) {
// bodies with meshes already reorient the normal to the triangle's center
@ -137,8 +144,6 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
}
}
// for ( auto& m : manifolds ) for ( auto& c : m.points ) UF_MSG_DEBUG("contact={}, normal={}, depth={}", uf::vector::toString( c.point ), uf::vector::toString( c.normal ), c.penetration );
// pass manifolds to solver
::solveContacts( manifolds, dt );
@ -166,12 +171,50 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
}
}
void uf::physics::impl::setMass( pod::RigidBody& body, float mass ) {
void uf::physics::impl::setMass( pod::PhysicsBody& body, float mass ) {
body.mass = mass;
body.inverseMass = 1.0f / mass;
uf::physics::impl::setInertia( body );
uf::physics::impl::updateInertia( body );
}
void uf::physics::impl::setInertia( pod::RigidBody& body ) {
void uf::physics::impl::setColliderCategory( pod::PhysicsBody& body, uint32_t category ) {
body.collider.category = category;
}
void uf::physics::impl::setColliderCategory( pod::PhysicsBody& body, const uf::stl::string& category ) {
auto c = uf::string::uppercase( category );
if ( c == "NONE" ) return uf::physics::impl::setColliderCategory( body, pod::Collider::CATEGORY_NONE );
if ( c == "STATIC" ) return uf::physics::impl::setColliderCategory( body, pod::Collider::CATEGORY_STATIC );
if ( c == "DYNAMIC" ) return uf::physics::impl::setColliderCategory( body, pod::Collider::CATEGORY_DYNAMIC );
if ( c == "PLAYER" ) return uf::physics::impl::setColliderCategory( body, pod::Collider::CATEGORY_PLAYER );
if ( c == "NPC" ) return uf::physics::impl::setColliderCategory( body, pod::Collider::CATEGORY_NPC );
if ( c == "TRIGGER" ) return uf::physics::impl::setColliderCategory( body, pod::Collider::CATEGORY_TRIGGER );
if ( c == "PROJECTILE" ) return uf::physics::impl::setColliderCategory( body, pod::Collider::CATEGORY_PROJECTILE );
if ( c == "CHARACTER" ) return uf::physics::impl::setColliderCategory( body, pod::Collider::CATEGORY_CHARACTER );
if ( c == "ALL" ) return uf::physics::impl::setColliderCategory( body, pod::Collider::CATEGORY_ALL );
}
void uf::physics::impl::setColliderMask( pod::PhysicsBody& body, uint32_t mask ) {
body.collider.mask = mask;
}
void uf::physics::impl::setColliderMask( pod::PhysicsBody& body, const uf::stl::string& mask ) {
auto m = uf::string::uppercase( mask );
if ( m == "NONE" ) return uf::physics::impl::setColliderMask( body, pod::Collider::MASK_NONE );
if ( m == "STATIC" ) return uf::physics::impl::setColliderMask( body, pod::Collider::MASK_STATIC );
if ( m == "DYNAMIC" ) return uf::physics::impl::setColliderMask( body, pod::Collider::MASK_DYNAMIC );
if ( m == "PLAYER" ) return uf::physics::impl::setColliderMask( body, pod::Collider::MASK_PLAYER );
if ( m == "NPC" ) return uf::physics::impl::setColliderMask( body, pod::Collider::MASK_NPC );
if ( m == "TRIGGER" ) return uf::physics::impl::setColliderMask( body, pod::Collider::MASK_TRIGGER );
if ( m == "PROJECTILE" ) return uf::physics::impl::setColliderMask( body, pod::Collider::MASK_PROJECTILE );
if ( m == "CHARACTER" ) return uf::physics::impl::setColliderCategory( body, pod::Collider::MASK_CHARACTER );
if ( m == "ALL" ) return uf::physics::impl::setColliderMask( body, pod::Collider::MASK_ALL );
}
void uf::physics::impl::setGravity( pod::PhysicsBody& body, const pod::Vector3f& gravity ) {
body.gravity = gravity;
}
pod::Vector3f uf::physics::impl::getGravity( pod::PhysicsBody& body ) {
return uf::vector::isValid( body.gravity ) ? body.gravity : body.world->gravity;
}
void uf::physics::impl::updateInertia( pod::PhysicsBody& body ) {
if ( body.isStatic || body.mass <= 0 ) {
body.inverseInertiaTensor = {};
return;
@ -211,11 +254,11 @@ void uf::physics::impl::setInertia( pod::RigidBody& body ) {
} break;
}
}
void uf::physics::impl::applyForce( pod::RigidBody& body, const pod::Vector3f& force ) {
void uf::physics::impl::applyForce( pod::PhysicsBody& body, const pod::Vector3f& force ) {
if ( body.isStatic ) return;
body.forceAccumulator += force;
}
void uf::physics::impl::applyForceAtPoint( pod::RigidBody body, const pod::Vector3f& force, const pod::Vector3f& point ) {
void uf::physics::impl::applyForceAtPoint( pod::PhysicsBody body, const pod::Vector3f& force, const pod::Vector3f& point ) {
if ( body.isStatic ) return;
// linear force
body.forceAccumulator += force;
@ -223,28 +266,28 @@ void uf::physics::impl::applyForceAtPoint( pod::RigidBody body, const pod::Vecto
pod::Vector3f r = point - ::getPosition( body );
body.torqueAccumulator += uf::vector::cross( r, force );
}
void uf::physics::impl::applyImpulse( pod::RigidBody& body, const pod::Vector3f& impulse ) {
void uf::physics::impl::applyImpulse( pod::PhysicsBody& body, const pod::Vector3f& impulse ) {
if ( body.isStatic ) return;
body.velocity += impulse * body.inverseMass;
}
void uf::physics::impl::applyTorque( pod::RigidBody& body, const pod::Vector3f& torque ) {
void uf::physics::impl::applyTorque( pod::PhysicsBody& body, const pod::Vector3f& torque ) {
if ( body.isStatic ) return;
body.torqueAccumulator += torque;
}
void uf::physics::impl::setVelocity( pod::RigidBody& body, const pod::Vector3f& v ) {
void uf::physics::impl::setVelocity( pod::PhysicsBody& body, const pod::Vector3f& v ) {
body.velocity = v;
}
void uf::physics::impl::applyRotation( pod::RigidBody& body, const pod::Quaternion<>& q ) {
void uf::physics::impl::applyRotation( pod::PhysicsBody& body, const pod::Quaternion<>& q ) {
uf::transform::rotate( *body.transform/*.reference*/, q );
}
void uf::physics::impl::applyRotation( pod::RigidBody& body, const pod::Vector3f& axis, float angle ) {
void uf::physics::impl::applyRotation( pod::PhysicsBody& body, const pod::Vector3f& axis, float angle ) {
applyRotation( body, uf::quaternion::axisAngle( axis, angle ) );
}
// body creation
pod::RigidBody& uf::physics::impl::create( pod::World& world, uf::Object& object, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( pod::World& world, uf::Object& object, float mass, const pod::Vector3f& offset ) {
// bind to component
pod::RigidBody& body = object.getComponent<pod::RigidBody>();
pod::PhysicsBody& body = object.getComponent<pod::PhysicsBody>();
// initial initialization
body.world = &world;
body.object = &object;
@ -254,71 +297,70 @@ pod::RigidBody& uf::physics::impl::create( pod::World& world, uf::Object& object
body.inverseMass = mass == 0.0f ? 0.0f : 1.0f / mass;
body.isStatic = mass == 0.0f;
if ( body.isStatic ) {
uf::physics::impl::setColliderCategory(body, "STATIC");
uf::physics::impl::setColliderMask(body, "STATIC");
}
// insert into world
world.bodies.emplace_back(&body);
return body;
}
pod::RigidBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const pod::AABB& aabb, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const pod::AABB& aabb, float mass, const pod::Vector3f& offset ) {
auto& body = uf::physics::impl::create( world, object, mass, offset );
body.collider.type = pod::ShapeType::AABB;
body.collider.u.aabb = aabb;
body.bounds = ::computeAABB( body );
uf::physics::impl::setInertia( body );
UF_MSG_DEBUG("Creating body of type: {}, mass={}, min={}, max={}", "AABB", mass, uf::vector::toString(aabb.min), uf::vector::toString(aabb.max) );
uf::physics::impl::updateInertia( body );
return body;
}
pod::RigidBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const pod::Sphere& sphere, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const pod::Sphere& sphere, float mass, const pod::Vector3f& offset ) {
auto& body = uf::physics::impl::create( world, object, mass, offset );
body.collider.type = pod::ShapeType::SPHERE;
body.collider.u.sphere = sphere;
body.bounds = ::computeAABB( body );
uf::physics::impl::setInertia( body );
UF_MSG_DEBUG("Creating body of type={}, mass={}, radius={}", "SPHERE", mass, sphere.radius );
uf::physics::impl::updateInertia( body );
return body;
}
pod::RigidBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const pod::Plane& plane, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const pod::Plane& plane, float mass, const pod::Vector3f& offset ) {
auto& body = uf::physics::impl::create( world, object, mass, offset );
body.collider.type = pod::ShapeType::PLANE;
body.collider.u.plane = plane;
body.bounds = ::computeAABB( body );
uf::physics::impl::setInertia( body );
UF_MSG_DEBUG("Creating body of type={}, mass={}, normal={}, offset={}", "PLANE", mass, uf::vector::toString( plane.normal ), plane.offset );
uf::physics::impl::updateInertia( body );
return body;
}
pod::RigidBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const pod::Capsule& capsule, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const pod::Capsule& capsule, float mass, const pod::Vector3f& offset ) {
auto& body = uf::physics::impl::create( world, object, mass, offset );
body.collider.type = pod::ShapeType::CAPSULE;
body.collider.u.capsule = capsule;
body.bounds = ::computeAABB( body );
uf::physics::impl::setInertia( body );
UF_MSG_DEBUG("Creating body of type={}, mass={}, radius={}, height={}", "CAPSULE", mass, capsule.radius, capsule.halfHeight * 2.0f );
uf::physics::impl::updateInertia( body );
return body;
}
pod::RigidBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const pod::TriangleWithNormal& tri, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const pod::TriangleWithNormal& tri, float mass, const pod::Vector3f& offset ) {
auto& body = uf::physics::impl::create( world, object, mass, offset );
body.collider.type = pod::ShapeType::TRIANGLE;
body.collider.u.triangle = tri;
body.bounds = ::computeAABB( body );
uf::physics::impl::setInertia( body );
UF_MSG_DEBUG("Creating body of type={}, mass={}, point[0]={}, point[1]={}, point[2]={}", "TRIANGLE", mass, uf::vector::toString( tri.points[0] ), uf::vector::toString( tri.points[1] ), uf::vector::toString( tri.points[2] ) );
uf::physics::impl::updateInertia( body );
return body;
}
pod::RigidBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const uf::Mesh& mesh, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( pod::World& world, uf::Object& object, const uf::Mesh& mesh, float mass, const pod::Vector3f& offset ) {
auto& body = uf::physics::impl::create( world, object, mass, offset );
body.collider.type = pod::ShapeType::MESH;
body.collider.u.mesh.mesh = &mesh;
body.collider.u.mesh.bvh = new pod::BVH;
::buildMeshBVH( *body.collider.u.mesh.bvh, mesh );
::buildMeshBVH( *body.collider.u.mesh.bvh, mesh, ::meshBvhCapacity );
body.bounds = ::computeAABB( body );
uf::physics::impl::setInertia( body );
UF_MSG_DEBUG("Creating body of type={}, mass={}, nodes={} indices={} ", "MESH", mass, body.collider.u.mesh.bvh->nodes.size(), body.collider.u.mesh.bvh->indices.size());
uf::physics::impl::updateInertia( body );
return body;
}
pod::RigidBody& uf::physics::impl::create( uf::Object& object, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( uf::Object& object, float mass, const pod::Vector3f& offset ) {
// bind to scene
// auto& root = object.getRootParent<>(); // in the event a scene is being initialized that is not the root scene, use the root parent instead
// auto& world = root.getComponent<pod::World>();
@ -327,38 +369,38 @@ pod::RigidBody& uf::physics::impl::create( uf::Object& object, float mass, const
return create( world, object, mass, offset );
}
pod::RigidBody& uf::physics::impl::create( uf::Object& object, const pod::AABB& aabb, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( uf::Object& object, const pod::AABB& aabb, float mass, const pod::Vector3f& offset ) {
auto& scene = uf::scene::getCurrentScene();
auto& world = scene.getComponent<pod::World>();
return create( world, object, aabb, mass, offset );
}
pod::RigidBody& uf::physics::impl::create( uf::Object& object, const pod::Sphere& sphere, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( uf::Object& object, const pod::Sphere& sphere, float mass, const pod::Vector3f& offset ) {
auto& scene = uf::scene::getCurrentScene();
auto& world = scene.getComponent<pod::World>();
return create( world, object, sphere, mass, offset );
}
pod::RigidBody& uf::physics::impl::create( uf::Object& object, const pod::Plane& plane, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( uf::Object& object, const pod::Plane& plane, float mass, const pod::Vector3f& offset ) {
auto& scene = uf::scene::getCurrentScene();
auto& world = scene.getComponent<pod::World>();
return create( world, object, plane, mass, offset );
}
pod::RigidBody& uf::physics::impl::create( uf::Object& object, const pod::Capsule& capsule, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( uf::Object& object, const pod::Capsule& capsule, float mass, const pod::Vector3f& offset ) {
auto& scene = uf::scene::getCurrentScene();
auto& world = scene.getComponent<pod::World>();
return create( world, object, capsule, mass, offset );
}
pod::RigidBody& uf::physics::impl::create( uf::Object& object, const uf::Mesh& mesh, float mass, const pod::Vector3f& offset ) {
pod::PhysicsBody& uf::physics::impl::create( uf::Object& object, const uf::Mesh& mesh, float mass, const pod::Vector3f& offset ) {
auto& scene = uf::scene::getCurrentScene();
auto& world = scene.getComponent<pod::World>();
return create( world, object, mesh, mass, offset );
}
void uf::physics::impl::destroy( uf::Object& object ) {
if ( !object.hasComponent<pod::RigidBody>() ) return;
if ( !object.hasComponent<pod::PhysicsBody>() ) return;
return destroy( object.getComponent<pod::RigidBody>() );
return destroy( object.getComponent<pod::PhysicsBody>() );
}
void uf::physics::impl::destroy( pod::RigidBody& body ) {
void uf::physics::impl::destroy( pod::PhysicsBody& body ) {
auto& world = *body.world;
// remove from world
for ( auto it = world.bodies.begin(); it != world.bodies.end(); ++it ) {
@ -373,27 +415,23 @@ void uf::physics::impl::destroy( pod::RigidBody& body ) {
}
}
pod::RayQuery uf::physics::impl::rayCast( const pod::Ray& ray, const pod::RigidBody& body, float maxDistance ) {
pod::RayQuery uf::physics::impl::rayCast( const pod::Ray& ray, const pod::PhysicsBody& body, float maxDistance ) {
return rayCast( ray, *body.world, &body, maxDistance );
}
pod::RayQuery uf::physics::impl::rayCast( const pod::Ray& ray, const pod::World& world, float maxDistance ) {
return rayCast( ray, world, NULL, maxDistance );
}
pod::RayQuery uf::physics::impl::rayCast( const pod::Ray& ray, const pod::World& world, const pod::RigidBody* body, float maxDistance ) {
pod::RayQuery uf::physics::impl::rayCast( const pod::Ray& ray, const pod::World& world, const pod::PhysicsBody* body, float maxDistance ) {
pod::RayQuery rayHit;
rayHit.contact.penetration = maxDistance;
auto& bvh = world.bvh;
auto& bodies = world.bodies;
#if 1
uf::stl::vector<int> candidates;
::queryBVH( bvh, ray, candidates );
for ( auto i : candidates ) {
#else
for ( auto i = 0; i < bodies.size(); ++i ) {
#endif
auto* b = bodies[i];
if ( body == b ) continue;
switch ( b->collider.type ) {

View File

@ -1,5 +1,5 @@
namespace {
float computeEffectiveMass( pod::RigidBody& a, pod::RigidBody& b, const pod::Vector3f& rA, const pod::Vector3f& rB, const pod::Vector3f& n ) {
float computeEffectiveMass( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& rA, const pod::Vector3f& rB, const pod::Vector3f& n ) {
float inverseMass = 0.0f;
if ( !a.isStatic ) inverseMass += a.inverseMass;
if ( !b.isStatic ) inverseMass += b.inverseMass;
@ -21,7 +21,7 @@ namespace {
return result;
}
void applyImpulseTo( pod::RigidBody& a, pod::RigidBody& b, const pod::Vector3f& rA, const pod::Vector3f& rB, const pod::Vector3f& impulse ) {
void applyImpulseTo( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& rA, const pod::Vector3f& rB, const pod::Vector3f& impulse ) {
if ( !a.isStatic ) {
a.velocity -= impulse * a.inverseMass;
a.angularVelocity -= (uf::vector::cross(rA, impulse)) * a.inverseInertiaTensor;
@ -34,7 +34,7 @@ namespace {
}
}
void applyRollingResistance( pod::RigidBody& body, float dt ) {
void applyRollingResistance( pod::PhysicsBody& body, float dt ) {
if ( body.isStatic ) return;
float rollingFriction = 0.02f; // to-do: derive from material
@ -45,14 +45,14 @@ namespace {
// body.angularVelocity *= -rollingFriction * dt;
}
void bindManifold( pod::RigidBody& a, pod::RigidBody& b, pod::Manifold& manifold, float dt = 0 ) {
void bindManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt = 0 ) {
manifold.a = &a;
manifold.b = &b;
manifold.dt = dt;
manifold.points.clear();
}
bool generateContactsGjk( pod::RigidBody& a, pod::RigidBody& b, pod::Manifold& manifold, float dt ) {
bool generateContactsGjk( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
::bindManifold( a, b, manifold, dt );
pod::Simplex simplex;
@ -66,7 +66,7 @@ namespace {
return true;
}
bool generateContacts( pod::RigidBody& a, pod::RigidBody& b, pod::Manifold& manifold, float dt ) {
bool generateContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
if ( ::useGjk ) return generateContactsGjk( a, b, manifold, dt );
::bindManifold( a, b, manifold, dt );
@ -172,7 +172,7 @@ namespace {
}
}
void warmupContacts( pod::RigidBody& a, pod::RigidBody& b, const pod::Contact& c, float dt ) {
void warmupContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Contact& c, float dt ) {
if ( !c.lifetime ) return; // too new
// build relative offsets
@ -189,14 +189,14 @@ namespace {
// UF_MSG_DEBUG("Warming, Pn={}, Pt={}, lifetime={}", uf::vector::toString(Pn), uf::vector::toString(Pt), c.lifetime );
}
void warmupManifold( pod::RigidBody& a, pod::RigidBody& b, const pod::Manifold& manifold, float dt ) {
void warmupManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Manifold& manifold, float dt ) {
for ( auto& contact : manifold.points ) {
::warmupContacts( a, b, contact, dt );
}
}
// baumgarte position correction
void positionCorrection( pod::RigidBody& a, pod::RigidBody& b, const pod::Contact& contact ) {
void positionCorrection( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Contact& contact ) {
if ( ::baumgarteCorrectionPercent <= 0 ) return;
float correctionMagnitude = std::max(contact.penetration - ::baumgarteCorrectionSlop, 0.0f) / (a.inverseMass + b.inverseMass) * ::baumgarteCorrectionPercent;
@ -206,7 +206,7 @@ namespace {
if ( !b.isStatic ) b.transform/*.reference*/->position += correction * b.inverseMass;
}
void integrate( pod::RigidBody& body, float dt ) {
void integrate( pod::PhysicsBody& body, float dt ) {
// only integrate dynamic bodies
if ( body.isStatic || body.mass == 0 ) return;
@ -214,7 +214,7 @@ namespace {
// linear integration
pod::Vector3f acceleration = body.forceAccumulator * body.inverseMass;
acceleration += world.gravity; // apply gravity
acceleration += uf::physics::impl::getGravity( body ); // apply gravity
body.velocity += acceleration * dt;
body.transform/*.reference*/->position += body.velocity * dt;

View File

@ -13,7 +13,7 @@ normal = uf::quaternion::rotate( mesh.transform.orientation, normal );
//
namespace {
bool meshAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool meshAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( MESH, AABB );
const auto& mesh = a;
@ -36,7 +36,7 @@ namespace {
}
return hit;
}
bool meshSphere( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool meshSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( MESH, SPHERE );
const auto& mesh = a;
@ -61,7 +61,7 @@ namespace {
return hit;
}
// to-do
bool meshPlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool meshPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( MESH, PLANE );
const auto& mesh = a;
@ -85,7 +85,7 @@ namespace {
return hit;
}
bool meshCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool meshCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( MESH, CAPSULE );
const auto& mesh = a;
@ -110,7 +110,7 @@ namespace {
return hit;
}
// to-do
bool meshMesh( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool meshMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( MESH, MESH );
const auto& bvhA = *a.collider.u.mesh.bvh;
@ -123,16 +123,12 @@ namespace {
pod::BVH::pair_t pairs;
::traverseNodePair(bvhA, 0, bvhB, 0, pairs);
UF_MSG_DEBUG("candidates={}", pairs.size());
bool hit = false;
// do collision per triangle
for (auto [ idA, idB] : pairs ) {
auto tA = ::fetchTriangle( meshA, idA, a ); // transform triangles to world space
auto tB = ::fetchTriangle( meshB, idB, b );
UF_MSG_DEBUG("triA={}, triB={}", idA, idB );
if ( !::triangleTriangle( tA, tB, manifold, eps ) ) continue;
hit = true;
}

View File

@ -1,5 +1,5 @@
namespace {
bool planeAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool planeAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( PLANE, AABB );
const auto& plane = a;
@ -21,7 +21,7 @@ namespace {
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
return true;
}
bool planeSphere(const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps) {
bool planeSphere(const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps) {
ASSERT_COLLIDER_TYPES(PLANE, SPHERE);
const auto& plane = a;
@ -42,15 +42,15 @@ namespace {
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
return true;
}
bool planePlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool planePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( PLANE, PLANE );
return false;
}
bool planeCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool planeCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( PLANE, CAPSULE );
return capsulePlane( b, a, manifold, eps );
}
bool planeMesh( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool planeMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( PLANE, MESH );
return meshPlane( b, a, manifold, eps );
}

View File

@ -48,7 +48,7 @@ namespace {
return true;
}
bool rayAabb( const pod::Ray& ray, const pod::RigidBody& body, pod::RayQuery& rayHit ) {
bool rayAabb( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit ) {
float tMin = 0.0f;
float tMax = FLT_MAX;
@ -74,7 +74,7 @@ namespace {
}
return true;
}
bool raySphere( const pod::Ray& ray, const pod::RigidBody& body, pod::RayQuery& rayHit ) {
bool raySphere( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit ) {
auto center = ::getPosition(body);
float r = body.collider.u.sphere.radius;
@ -87,8 +87,6 @@ namespace {
float disc = b*b - 4*a*c;
UF_MSG_DEBUG( "center={}, r={}, oc={}, a, b, c, disc", uf::vector::toString( center ), r, uf::vector::toString( oc ), a, b, c, disc );
if ( disc < 0 ) return false;
float sqrtDisc = std::sqrt(disc);
@ -97,8 +95,6 @@ namespace {
float t = ( t0 >= 0 ) ? t0 : t1;
UF_MSG_DEBUG( "sqrtDisc={}, t0={}, t1={}, t={}, rayHit.contact.penetration={}", sqrtDisc, t0, t1, t, rayHit.contact.penetration );
if ( t < 0 ) return false; // both behind ray
// compare against current best hit
@ -112,7 +108,7 @@ namespace {
rayHit.contact.penetration = t;
return true;
}
bool rayPlane( const pod::Ray& ray, const pod::RigidBody& body, pod::RayQuery& rayHit, float eps = EPS(1e-6f) ) {
bool rayPlane( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit, float eps = EPS(1e-6f) ) {
auto& normal = body.collider.u.plane.normal;
float offset = body.collider.u.plane.offset;
@ -131,7 +127,7 @@ namespace {
rayHit.contact.penetration = t;
return true;
}
bool rayCapsule( const pod::Ray& ray, const pod::RigidBody& body, pod::RayQuery& rayHit ) {
bool rayCapsule( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit ) {
auto [ p1, p2 ] = ::getCapsuleSegment( body );
float r = body.collider.u.capsule.radius;
@ -196,7 +192,7 @@ namespace {
return true;
}
bool rayMesh( const pod::Ray& r, const pod::RigidBody& body, pod::RayQuery& rayHit ) {
bool rayMesh( const pod::Ray& r, const pod::PhysicsBody& body, pod::RayQuery& rayHit ) {
const uf::Mesh& meshData = *body.collider.u.mesh.mesh;
const pod::BVH& bvh = *body.collider.u.mesh.bvh;

View File

@ -1,5 +1,5 @@
namespace {
void iterativeImpulseSolver( pod::RigidBody& a, pod::RigidBody& b, pod::Contact& contact, float dt ) {
void iterativeImpulseSolver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Contact& contact, float dt ) {
// relative positions from centers to contact point
pod::Vector3f rA = contact.point - ::getPosition( a, true );
pod::Vector3f rB = contact.point - ::getPosition( b, true );
@ -74,7 +74,7 @@ namespace {
}
template<size_t N, typename T = float>
void blockNxNSolver( pod::RigidBody& a, pod::RigidBody& b, pod::Manifold& manifold, float dt ) {
void blockNxNSolver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
pod::Matrix<T,N> K = {};
pod::Vector<T,N> rhs = {};
pod::Vector<T,N> lambda = {};
@ -167,17 +167,17 @@ namespace {
}
}
void block2x2Solver( pod::RigidBody& a, pod::RigidBody& b, pod::Manifold& manifold, float dt ) {
void block2x2Solver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
return ::blockNxNSolver<2>( a, b, manifold, dt );
}
void block3x3Solver( pod::RigidBody& a, pod::RigidBody& b, pod::Manifold& manifold, float dt ) {
void block3x3Solver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
return ::blockNxNSolver<3>( a, b, manifold, dt );
}
void block4x4Solver( pod::RigidBody& a, pod::RigidBody& b, pod::Manifold& manifold, float dt ) {
void block4x4Solver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
return ::blockNxNSolver<4>( a, b, manifold, dt );
}
void blockPGSSolver( pod::RigidBody& a, pod::RigidBody& b, pod::Manifold& manifold, float dt ) {
void blockPGSSolver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
const int count = std::min( (int) manifold.points.size(), 4 );
// precompute inv mass
float invMassA = ( a.isStatic ? 0.0f : a.inverseMass );
@ -260,7 +260,7 @@ namespace {
}
}
void resolveManifold( pod::RigidBody& a, pod::RigidBody& b, pod::Manifold& manifold, float dt ) {
void resolveManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
if ( ::blockContactSolver ) {
if ( manifold.points.size() == 2 ) return ::block2x2Solver( a, b, manifold, dt );
if ( manifold.points.size() == 3 ) return ::block3x3Solver( a, b, manifold, dt );

View File

@ -1,5 +1,5 @@
namespace {
bool sphereSphere( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool sphereSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( SPHERE, SPHERE );
auto delta = ::getPosition( b ) - ::getPosition( a );
@ -16,7 +16,7 @@ namespace {
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
return true;
}
bool sphereAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool sphereAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( SPHERE, AABB );
const auto& sphere = a;
@ -51,15 +51,15 @@ namespace {
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
return true;
}
bool spherePlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool spherePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( SPHERE, PLANE );
return planeSphere( b, a, manifold, eps );
}
bool sphereCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool sphereCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( SPHERE, CAPSULE );
return capsuleSphere( b, a, manifold, eps );
}
bool sphereMesh( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool sphereMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( SPHERE, MESH );
return meshSphere( b, a, manifold, eps );
}

View File

@ -104,7 +104,7 @@ namespace {
}
// if body is a mesh, apply its transform to the triangles, else reorient the normal with respect to the body
pod::TriangleWithNormal fetchTriangle( const uf::Mesh& mesh, size_t triID, const pod::RigidBody& body ) {
pod::TriangleWithNormal fetchTriangle( const uf::Mesh& mesh, size_t triID, const pod::PhysicsBody& body ) {
auto tri = ::fetchTriangle( mesh, triID );
auto transform = ::getTransform( body );
@ -259,7 +259,7 @@ namespace {
return true;
}
bool triangleAabb( const pod::TriangleWithNormal& tri, const pod::RigidBody& body, pod::Manifold& manifold, float eps ) {
bool triangleAabb( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold, float eps ) {
const auto& aabb = body;
auto closest = ::closestPointOnTriangle( ::getPosition( aabb ), tri );
@ -286,7 +286,7 @@ namespace {
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
return true;
}
bool triangleSphere( const pod::TriangleWithNormal& tri, const pod::RigidBody& body, pod::Manifold& manifold, float eps ) {
bool triangleSphere( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold, float eps ) {
const auto& sphere = body;
float r = sphere.collider.u.sphere.radius;
@ -313,7 +313,7 @@ namespace {
return true;
}
// to-do: implement
bool trianglePlane( const pod::TriangleWithNormal& tri, const pod::RigidBody& body, pod::Manifold& manifold, float eps ) {
bool trianglePlane( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold, float eps ) {
const auto& plane = body;
auto normal = plane.collider.u.plane.normal;
float d = plane.collider.u.plane.offset;
@ -357,7 +357,7 @@ namespace {
}
return hit;
}
bool triangleCapsule( const pod::TriangleWithNormal& tri, const pod::RigidBody& body, pod::Manifold& manifold, float eps ) {
bool triangleCapsule( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold, float eps ) {
const auto& capsule = body;
float r = capsule.collider.u.capsule.radius;
@ -386,23 +386,23 @@ namespace {
return true;
}
bool triangleTriangle( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool triangleTriangle( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( TRIANGLE, TRIANGLE );
return ::triangleTriangle( a.collider.u.triangle, b.collider.u.triangle, manifold, eps );
}
bool triangleAabb( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool triangleAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( TRIANGLE, AABB );
return ::triangleAabb( a.collider.u.triangle, b, manifold, eps );
}
bool triangleSphere( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool triangleSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( TRIANGLE, SPHERE );
return ::triangleSphere( a.collider.u.triangle, b, manifold, eps );
}
bool trianglePlane( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool trianglePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( TRIANGLE, PLANE );
return ::trianglePlane( a.collider.u.triangle, b, manifold, eps );
}
bool triangleCapsule( const pod::RigidBody& a, const pod::RigidBody& b, pod::Manifold& manifold, float eps ) {
bool triangleCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( TRIANGLE, CAPSULE );
return ::triangleCapsule( a.collider.u.triangle, b, manifold, eps );
}