242 lines
8.0 KiB
C++
242 lines
8.0 KiB
C++
#pragma once
|
|
|
|
#include <uf/utils/math/vector.h>
|
|
#include <uf/utils/math/quaternion.h>
|
|
#include <uf/utils/math/matrix.h>
|
|
#include <uf/utils/math/shapes.h>
|
|
#include <uf/utils/math/transform.h>
|
|
|
|
#include <uf/utils/memory/vector.h>
|
|
#include <uf/utils/memory/unordered_map.h>
|
|
|
|
#include <uf/engine/object/object.h>
|
|
#include <cfloat>
|
|
|
|
namespace uf {
|
|
class Mesh;
|
|
}
|
|
|
|
namespace pod {
|
|
enum class ShapeType {
|
|
AABB,
|
|
SPHERE,
|
|
PLANE,
|
|
CAPSULE,
|
|
TRIANGLE,
|
|
MESH,
|
|
};
|
|
|
|
struct SupportPoint {
|
|
pod::Vector3f p;
|
|
pod::Vector3f pA;
|
|
pod::Vector3f pB;
|
|
};
|
|
|
|
struct Simplex {
|
|
uf::stl::vector<pod::SupportPoint> pts;
|
|
};
|
|
|
|
struct Face {
|
|
pod::SupportPoint a, b, c;
|
|
pod::Vector3f normal;
|
|
float distance;
|
|
};
|
|
|
|
struct BVH {
|
|
typedef uf::stl::vector<std::pair<int,int>> pair_t;
|
|
struct Node {
|
|
pod::AABB bounds = {};
|
|
int left = -1;
|
|
int right = -1;
|
|
int start = 0;
|
|
int count = 0;
|
|
};
|
|
uf::stl::vector<size_t> indices;
|
|
uf::stl::vector<pod::BVH::Node> nodes;
|
|
};
|
|
|
|
struct MeshBVH {
|
|
pod::BVH* bvh;
|
|
const uf::Mesh* mesh;
|
|
};
|
|
|
|
typedef uint32_t CollisionMask;
|
|
|
|
|
|
struct Collider {
|
|
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
|
|
};
|
|
|
|
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 category = Collider::CATEGORY_ALL;
|
|
pod::CollisionMask mask = Collider::MASK_ALL;
|
|
|
|
union {
|
|
pod::Sphere sphere;
|
|
pod::AABB aabb;
|
|
pod::Plane plane;
|
|
pod::Capsule capsule;
|
|
pod::TriangleWithNormal triangle;
|
|
pod::MeshBVH mesh;
|
|
} u;
|
|
};
|
|
|
|
struct PhysicsMaterial {
|
|
float restitution = 0.2f;
|
|
float staticFriction = 0.5f;
|
|
float dynamicFriction = 0.3f;
|
|
};
|
|
|
|
struct World; // forward declare
|
|
|
|
struct RigidBody {
|
|
pod::World* world = NULL;
|
|
uf::Object* object = NULL;
|
|
// pod::Transform<> transform = {};
|
|
|
|
pod::Transform<>* transform = NULL;
|
|
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 = { 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;
|
|
};
|
|
|
|
struct Contact {
|
|
pod::Vector3f point;
|
|
pod::Vector3f normal;
|
|
float penetration;
|
|
|
|
// Warm-start cached values
|
|
int lifetime = 0;
|
|
pod::Vector3f tangent = {};
|
|
float accumulatedNormalImpulse = 0.0f;
|
|
float accumulatedTangentImpulse = 0.0f;
|
|
};
|
|
|
|
struct Manifold {
|
|
pod::RigidBody* a = NULL;
|
|
pod::RigidBody* b = NULL;
|
|
float dt = 0;
|
|
uf::stl::vector<pod::Contact> points;
|
|
};
|
|
|
|
struct RayQuery {
|
|
bool hit = false;
|
|
const pod::RigidBody* body;
|
|
pod::Contact contact = { pod::Vector3f{}, pod::Vector3f{}, FLT_MAX };
|
|
};
|
|
|
|
struct World {
|
|
uf::stl::vector<pod::RigidBody*> bodies;
|
|
|
|
pod::Vector3f gravity = { 0, -9.81f, 0 };
|
|
pod::BVH bvh;
|
|
};
|
|
}
|
|
|
|
namespace uf {
|
|
namespace physics {
|
|
namespace impl {
|
|
extern UF_API float timescale;
|
|
extern UF_API bool interpolate;
|
|
extern UF_API bool shared;
|
|
extern UF_API bool globalStorage;
|
|
|
|
extern UF_API pod::World world;
|
|
|
|
void UF_API initialize();
|
|
void UF_API initialize( uf::Object& );
|
|
void UF_API initialize( pod::World& );
|
|
|
|
void UF_API tick( float = 0 );
|
|
void UF_API tick( uf::Object&, float = 0 );
|
|
void UF_API tick( pod::World&, float = 0 );
|
|
|
|
void UF_API terminate();
|
|
void UF_API terminate( uf::Object& );
|
|
void UF_API terminate( pod::World& );
|
|
|
|
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 setColliderCategory( pod::RigidBody&, uint32_t category = pod::Collider::CATEGORY_ALL );
|
|
void UF_API setColliderCategory( pod::RigidBody&, const uf::stl::string& );
|
|
void UF_API setColliderMask( pod::RigidBody&, uint32_t mask = pod::Collider::MASK_ALL );
|
|
void UF_API setColliderMask( pod::RigidBody&, const uf::stl::string& );
|
|
void UF_API setGravity( pod::RigidBody&, const pod::Vector3f& = { NAN, NAN, NAN } );
|
|
pod::Vector3f UF_API getGravity( pod::RigidBody& );
|
|
|
|
void UF_API updateInertia( 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 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 );
|
|
|
|
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::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& = {} );
|
|
|
|
void UF_API destroy( uf::Object& );
|
|
void UF_API destroy( pod::RigidBody& );
|
|
|
|
pod::RayQuery UF_API rayCast( const pod::Ray&, const pod::RigidBody&, 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 );
|
|
}
|
|
}
|
|
} |