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:
parent
3b5db2c32c
commit
a66f56ad9f
6
Makefile
6
Makefile
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 )
|
||||
|
||||
|
||||
@ -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 ] } } }*/ },
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -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"
|
||||
}
|
||||
@ -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" }
|
||||
],
|
||||
|
||||
@ -1 +1 @@
|
||||
opengl
|
||||
vulkan
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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 ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@ -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>() ) {
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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());
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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{};
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@ -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 ) {
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user