added OBB colliders, painfully trying to resolve issues with rotating bodies
This commit is contained in:
parent
142f584684
commit
6b07173804
@ -335,6 +335,15 @@
|
||||
"ultralight": { "enabled": true, "scale": 1.5 },
|
||||
"discord": { "enabled": false }
|
||||
},
|
||||
"physics": {
|
||||
"warmup solver": true,
|
||||
"block solver": true,
|
||||
"psg solver": true,
|
||||
"gjk": true,
|
||||
"fixed step": true,
|
||||
"substeps": 4,
|
||||
"solver iterations": 10
|
||||
},
|
||||
"audio": {
|
||||
"mute": false,
|
||||
"async update": false,
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
{
|
||||
"assets": [],
|
||||
"behaviors": [
|
||||
"SoundEmitterBehavior"
|
||||
],
|
||||
@ -7,10 +6,10 @@
|
||||
"holdable": true,
|
||||
"physics": {
|
||||
"mass": 100,
|
||||
"inertia": false,
|
||||
// "type": "bounding box"
|
||||
// "inertia": false,
|
||||
"type": "bounding box"
|
||||
// "type": "mesh"
|
||||
"type": "hull"
|
||||
// "type": "hull"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -23,8 +23,6 @@ if metadata["normal"] ~= nil then
|
||||
if metadata["angle"] < 0 then sign = 1 end
|
||||
normal = Vector3f( metadata["normal"][1] * sign, metadata["normal"][2] * sign, metadata["normal"][3] * sign ):normalize()
|
||||
end
|
||||
local starting = Quaternion(transform.orientation)
|
||||
local ending = transform.orientation:multiply(Quaternion.axisAngle( Vector3f(0,1,0), metadata["angle"] ))
|
||||
|
||||
-- local soundEmitter = ent:loadChild("/sound.json",true)
|
||||
local soundEmitter = ent
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
"func_door_rotating_5568": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [1,0,0] } } },
|
||||
"func_door_rotating_5584": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [1,0,0] } } },
|
||||
|
||||
// "prop_physics_override_5813": { "action": "load", "payload": { "import": "/physics_prop.json" } },
|
||||
"prop_physics_override_5813": { "action": "load", "payload": { "import": "/physics_prop.json" } },
|
||||
|
||||
// regex matches
|
||||
"/^prop_physics_[^o]/": { "action": "load", "payload": { "import": "/prop.json" } },
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
namespace pod {
|
||||
enum class ShapeType {
|
||||
AABB,
|
||||
OBB,
|
||||
SPHERE,
|
||||
PLANE,
|
||||
CAPSULE,
|
||||
@ -125,16 +126,9 @@ namespace pod {
|
||||
pod::BVH* bvh;
|
||||
const uf::Mesh* mesh;
|
||||
};
|
||||
|
||||
// MIGHT contain additional data, so far mirrors the above
|
||||
struct ConvexHullBVH {
|
||||
pod::BVH* bvh;
|
||||
const uf::Mesh* mesh;
|
||||
};
|
||||
typedef MeshBVH ConvexHullBVH;
|
||||
|
||||
typedef uint32_t CollisionMask;
|
||||
|
||||
|
||||
struct Collider {
|
||||
// what it is
|
||||
enum CategoryMask : uint32_t {
|
||||
@ -166,8 +160,9 @@ namespace pod {
|
||||
pod::CollisionMask mask = Collider::MASK_ALL;
|
||||
|
||||
union {
|
||||
pod::Sphere sphere;
|
||||
pod::AABB aabb;
|
||||
pod::OBB obb;
|
||||
pod::Sphere sphere;
|
||||
pod::Plane plane;
|
||||
pod::Capsule capsule;
|
||||
pod::TriangleWithNormal triangle;
|
||||
@ -259,8 +254,8 @@ namespace pod {
|
||||
};
|
||||
|
||||
struct PhysicsSettings {
|
||||
bool warmupSolver = true; // cache manifold data to warm up the solver
|
||||
bool blockContactSolver = true; // use BlockNxN solvers (where N = number of contacts for a manifold)
|
||||
bool warmupSolver = false; // cache manifold data to warm up the solver
|
||||
bool blockContactSolver = false; // use BlockNxN solvers (where N = number of contacts for a manifold)
|
||||
bool psgContactSolver = true; // use PSG contact solver
|
||||
bool useGjk = false; // currently don't have a way to broadphase mesh => narrowphase tri via GJK
|
||||
bool fixedStep = true; // run physics simulation with a fixed delta time (with accumulation), rather than rely on actual engine deltatime
|
||||
@ -362,6 +357,13 @@ namespace uf {
|
||||
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 applyVelocity( pod::PhysicsBody& body, const pod::Vector3f& velocity );
|
||||
|
||||
void UF_API setAngularVelocity( pod::PhysicsBody& body, const pod::Vector3f& velocity );
|
||||
void UF_API setAngularVelocity( pod::PhysicsBody& body, const pod::Quaternion<>& q, float dt = 0 );
|
||||
void UF_API applyAngularVelocity( pod::PhysicsBody& body, const pod::Vector3f& velocity );
|
||||
void UF_API applyAngularVelocity( pod::PhysicsBody& body, const pod::Quaternion<>& q, float dt = 0 );
|
||||
|
||||
void UF_API applyRotation( pod::PhysicsBody& body, const pod::Quaternion<>& q );
|
||||
void UF_API applyRotation( pod::PhysicsBody& body, const pod::Vector3f& axis, float angle );
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "impl.h"
|
||||
|
||||
#include "narrowphase/aabb.h"
|
||||
#include "narrowphase/obb.h"
|
||||
#include "narrowphase/sphere.h"
|
||||
#include "narrowphase/plane.h"
|
||||
#include "narrowphase/capsule.h"
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
bool aabbAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool aabbObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool aabbSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool aabbPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool aabbCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
@ -3,10 +3,11 @@
|
||||
#include "../impl.h"
|
||||
|
||||
namespace impl {
|
||||
bool capsuleCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool capsuleAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool capsulePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool capsuleObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool capsuleSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool capsulePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool capsuleCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool capsuleMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool capsuleHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
}
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
bool hullAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool hullObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool hullSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool hullPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool hullCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
bool meshAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool meshObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool meshSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool meshPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool meshCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
13
engine/inc/uf/utils/math/physics/narrowphase/obb.h
Normal file
13
engine/inc/uf/utils/math/physics/narrowphase/obb.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "../impl.h"
|
||||
|
||||
namespace impl {
|
||||
bool obbAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool obbObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool obbSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool obbPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool obbCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool obbMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool obbHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
}
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
bool planeAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool planeObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool planeSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool planePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool planeCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
namespace impl {
|
||||
bool rayTriangleIntersect( const pod::Ray& ray, const pod::Triangle& tri, float& t, float& u, float& v );
|
||||
bool rayAabbIntersect( const pod::Ray& ray, const pod::AABB& box, float& tMin, float& tMax );
|
||||
|
||||
bool rayAabb( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit );
|
||||
bool rayObb( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit );
|
||||
bool raySphere( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit );
|
||||
bool rayPlane( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit );
|
||||
bool rayCapsule( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit );
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
#include "../impl.h"
|
||||
|
||||
namespace impl {
|
||||
bool sphereSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool sphereAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool sphereObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool sphereSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool spherePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool sphereCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool sphereMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
namespace impl {
|
||||
bool triangleTriangle( const pod::TriangleWithNormal& a, const pod::TriangleWithNormal& b, pod::Manifold& manifold );
|
||||
bool triangleAabb( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold );
|
||||
bool triangleObb( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold );
|
||||
bool triangleSphere( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold );
|
||||
bool trianglePlane( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold );
|
||||
bool triangleCapsule( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold );
|
||||
@ -12,6 +13,7 @@ namespace impl {
|
||||
|
||||
bool triangleTriangle( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool triangleAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool triangleObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool triangleSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool trianglePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool triangleCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
@ -1,10 +1,3 @@
|
||||
namespace pod {
|
||||
// Simple quaterions (designed [to store in arrays] with minimal headaches)
|
||||
template<typename T = NUM> using Quaternion = Vector4t<T>;
|
||||
}
|
||||
|
||||
// snip header
|
||||
|
||||
template<typename T> pod::Quaternion<T> uf::quaternion::identity() {
|
||||
return pod::Quaternion<T>{ 0, 0, 0, 1 };
|
||||
}
|
||||
@ -144,7 +137,7 @@ template<typename T> pod::Matrix3t<T> uf::quaternion::matrix3( const pod::Quater
|
||||
return pod::Matrix3t<T>({
|
||||
1 - yy - zz, xy + zw, xz - yw,
|
||||
xy - zw, 1 - xx - zz, yz + xw,
|
||||
xz + yw, yz - xw, 1 - xx - yy,
|
||||
xz + yw, yz - xw, 1 - xx - yy
|
||||
});
|
||||
}
|
||||
template<typename T> pod::Quaternion<T> uf::quaternion::axisAngle( const pod::Vector3t<T>& axis, T angle ) {
|
||||
@ -218,9 +211,9 @@ template<typename T> T& uf::quaternion::inverse_( T& q ) {
|
||||
template<typename T> pod::Quaternion<T> uf::quaternion::fromMatrix( const pod::Matrix4t<T>& m ) {
|
||||
pod::Quaternion<T> q;
|
||||
|
||||
T m00 = m[0], m01 = m[1], m02 = m[2];
|
||||
T m10 = m[4], m11 = m[5], m12 = m[6];
|
||||
T m20 = m[8], m21 = m[9], m22 = m[10];
|
||||
T m00 = m(0,0), m01 = m(0,1), m02 = m(0,2);
|
||||
T m10 = m(1,0), m11 = m(1,1), m12 = m(1,2);
|
||||
T m20 = m(2,0), m21 = m(2,1), m22 = m(2,2);
|
||||
|
||||
T trace = m00 + m11 + m22;
|
||||
if ( trace > 0 ) {
|
||||
|
||||
@ -14,6 +14,8 @@ namespace pod {
|
||||
alignas(16) pod::Vector3f max;
|
||||
};
|
||||
|
||||
typedef AABB OBB;
|
||||
|
||||
struct Sphere {
|
||||
float radius;
|
||||
};
|
||||
|
||||
@ -23,13 +23,14 @@ pod::Transform<T> /*UF_API*/ uf::transform::initialize() {
|
||||
template<typename T>
|
||||
pod::Transform<T>& /*UF_API*/ uf::transform::lookAt( pod::Transform<T>& transform, const pod::Vector3t<T>& at ) {
|
||||
pod::Vector3t<T> forward = uf::vector::normalize( at - transform.position );
|
||||
pod::Vector3t<T> right = uf::vector::normalize(uf::vector::cross( forward, transform.up ));
|
||||
pod::Vector3t<T> up = uf::vector::normalize(uf::vector::cross(at, right));
|
||||
pod::Vector3t<T> right = uf::vector::normalize(uf::vector::cross( transform.up, forward ));
|
||||
pod::Vector3t<T> up = uf::vector::normalize(uf::vector::cross( forward, right ));
|
||||
|
||||
transform.up = up;
|
||||
transform.right = right;
|
||||
transform.forward = forward;
|
||||
transform.orientation = uf::quaternion::lookAt( at, up );
|
||||
|
||||
transform.orientation = uf::quaternion::lookAt( forward, up );
|
||||
|
||||
return transform;
|
||||
}
|
||||
@ -49,7 +50,7 @@ pod::Transform<T>& /*UF_API*/ uf::transform::move( pod::Transform<T>& transform,
|
||||
template<typename T>
|
||||
pod::Transform<T>& /*UF_API*/ uf::transform::reorient( pod::Transform<T>& transform ) {
|
||||
pod::Quaternion<T> q = transform.orientation;
|
||||
transform.forward = { 2 * (q.x * q.z + q.w * q.y), 2 * (q.y * q.x - q.w * q.x), 1 - 2 * (q.x * q.x + q.y * q.y) };
|
||||
transform.forward = { 2 * (q.x * q.z + q.w * q.y), 2 * (q.y * q.x - q.w * q.z), 1 - 2 * (q.x * q.x + q.y * q.y) };
|
||||
transform.up = { 2 * (q.x * q.y - q.w * q.z), 1 - 2 * (q.x * q.x + q.z * q.z), 2 * (q.y * q.z + q.w * q.x)};
|
||||
transform.right = { 1 - 2 * (q.y * q.y + q.z * q.z), 2 * (q.x * q.y + q.w * q.z), 2 * (q.x * q.z - q.w * q.y)};
|
||||
return transform;
|
||||
@ -94,11 +95,7 @@ pod::Transform<T> /*UF_API*/ uf::transform::flatten( const pod::Transform<T>& tr
|
||||
const pod::Transform<T>* pointer = transform.reference;
|
||||
|
||||
while ( pointer && depth-- > 0 ) {
|
||||
combined.position = {
|
||||
combined.position.x + pointer->position.x,
|
||||
combined.position.y + pointer->position.y,
|
||||
combined.position.z + pointer->position.z,
|
||||
};
|
||||
combined.position = pointer->position + uf::quaternion::rotate(pointer->orientation, combined.position);
|
||||
combined.orientation = uf::quaternion::multiply( pointer->orientation, combined.orientation );
|
||||
combined.scale = {
|
||||
combined.scale.x * pointer->scale.x,
|
||||
|
||||
@ -110,152 +110,190 @@ void UF_API uf::load() {
|
||||
uf::config.readFromFile(uf::io::root+"config.json");
|
||||
}
|
||||
void UF_API uf::load( ext::json::Value& json ) {
|
||||
/*global*/::config.engine.gc.enabled = json["engine"]["debug"]["garbage collection"]["enabled"].as(/*global*/::config.engine.gc.enabled);
|
||||
/*global*/::config.engine.gc.every = json["engine"]["debug"]["garbage collection"]["every"].as(/*global*/::config.engine.gc.every);
|
||||
/*global*/::config.engine.gc.mode = json["engine"]["debug"]["garbage collection"]["mode"].as(/*global*/::config.engine.gc.mode);
|
||||
/*global*/::config.engine.gc.announce = json["engine"]["debug"]["garbage collection"]["announce"].as(/*global*/::config.engine.gc.announce);
|
||||
|
||||
/*global*/::config.engine.ext.ultralight.enabled = json["engine"]["ext"]["ultralight"]["enabled"].as(/*global*/::config.engine.ext.ultralight.enabled);
|
||||
/*global*/::config.engine.ext.discord.enabled = json["engine"]["ext"]["discord"]["enabled"].as(/*global*/::config.engine.ext.discord.enabled);
|
||||
/*global*/::config.engine.ext.imgui.enabled = json["engine"]["ext"]["imgui"]["enabled"].as(/*global*/::config.engine.ext.imgui.enabled);
|
||||
|
||||
/*global*/::config.engine.ext.vall_e.enabled = json["engine"]["ext"]["vall_e"]["enabled"].as(/*global*/::config.engine.ext.vall_e.enabled);
|
||||
/*global*/::config.engine.ext.vall_e.model_path = json["engine"]["ext"]["vall_e"]["model_path"].as(/*global*/::config.engine.ext.vall_e.model_path);
|
||||
/*global*/::config.engine.ext.vall_e.encodec_path = json["engine"]["ext"]["vall_e"]["encodec_path"].as(/*global*/::config.engine.ext.vall_e.encodec_path);
|
||||
|
||||
/*global*/::config.engine.limiter.print = json["engine"]["debug"]["framerate"]["print"].as(/*global*/::config.engine.limiter.print);
|
||||
|
||||
/*global*/::config.engine.fps.print = json["engine"]["debug"]["framerate"]["print"].as(/*global*/::config.engine.fps.print);
|
||||
/*global*/::config.engine.fps.every = json["engine"]["debug"]["framerate"]["every"].as(/*global*/::config.engine.fps.every);
|
||||
|
||||
uf::Mesh::defaultInterleaved = json["engine"]["scenes"]["meshes"]["interleaved"].as( uf::Mesh::defaultInterleaved );
|
||||
|
||||
uf::matrix::reverseInfiniteProjection = json["engine"]["scenes"]["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection );
|
||||
|
||||
uf::graph::initialBufferElements = json["engine"]["graph"]["initial buffer elements"].as(uf::graph::initialBufferElements);
|
||||
uf::graph::globalStorage = json["engine"]["graph"]["global storage"].as(uf::graph::globalStorage);
|
||||
|
||||
uf::Entity::deleteChildrenOnDestroy = json["engine"]["debug"]["entity"]["delete children on destroy"].as( uf::Entity::deleteChildrenOnDestroy );
|
||||
uf::Entity::deleteComponentsOnDestroy = json["engine"]["debug"]["entity"]["delete components on destroy"].as( uf::Entity::deleteComponentsOnDestroy );
|
||||
|
||||
uf::Object::assertionLoad = json["engine"]["debug"]["loader"]["assert"].as( uf::Object::assertionLoad );
|
||||
uf::asset::assertionLoad = json["engine"]["debug"]["loader"]["assert"].as( uf::asset::assertionLoad );
|
||||
uf::asset::asyncQueue = json["engine"]["debug"]["loader"]["async"].as( uf::asset::asyncQueue );
|
||||
|
||||
uf::userdata::autoDestruct = json["engine"]["debug"]["userdata"]["auto destruct"].as( uf::userdata::autoDestruct );
|
||||
uf::userdata::autoValidate = json["engine"]["debug"]["userdata"]["auto validate"].as( uf::userdata::autoValidate );
|
||||
|
||||
uf::Object::deferLazyCalls = json["engine"]["debug"]["hooks"]["defer lazy calls"].as( uf::Object::deferLazyCalls );
|
||||
uf::scene::printTaskCalls = json["engine"]["debug"]["scene"]["print task calls"].as( uf::scene::printTaskCalls );
|
||||
|
||||
auto& configEngineLimitersJson = json["engine"]["limiters"];
|
||||
|
||||
if ( configEngineLimitersJson["framerate"].as<uf::stl::string>() == "auto" && json["window"]["refresh rate"].is<size_t>() ) {
|
||||
float scale = 1.0;
|
||||
size_t refreshRate = json["window"]["refresh rate"].as<size_t>();
|
||||
configEngineLimitersJson["framerate"] = refreshRate * scale;
|
||||
UF_MSG_DEBUG("Setting framerate cap to {}", (int) refreshRate * scale);
|
||||
// Scene settings
|
||||
{
|
||||
auto& configEngineSceneJson = json["engine"]["scenes"];
|
||||
uf::Mesh::defaultInterleaved = configEngineSceneJson["meshes"]["interleaved"].as( uf::Mesh::defaultInterleaved );
|
||||
uf::matrix::reverseInfiniteProjection = configEngineSceneJson["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection );
|
||||
}
|
||||
|
||||
/* Frame limiter */ {
|
||||
size_t limit = configEngineLimitersJson["framerate"].as<size_t>();
|
||||
/*global*/::times.limiter = limit != 0 ? 1.0 / limit : 0;
|
||||
UF_MSG_DEBUG("Limiter set to {} ms", /*global*/::times.limiter);
|
||||
}
|
||||
/* Max delta time */{
|
||||
size_t limit = configEngineLimitersJson["deltaTime"].as<size_t>();
|
||||
uf::physics::time::clamp = limit != 0 ? 1.0 / limit : 0;
|
||||
// Graph settings
|
||||
{
|
||||
auto& configEngineGraphJson = json["engine"]["graph"];
|
||||
uf::graph::initialBufferElements = configEngineGraphJson["initial buffer elements"].as(uf::graph::initialBufferElements);
|
||||
uf::graph::globalStorage = configEngineGraphJson["global storage"].as(uf::graph::globalStorage);
|
||||
}
|
||||
|
||||
auto& configEngineThreadJson = json["engine"]["threads"];
|
||||
// Various debug settings
|
||||
{
|
||||
auto& configEngineDebugJson = json["engine"]["debug"];
|
||||
/*global*/::config.engine.gc.enabled = configEngineDebugJson["garbage collection"]["enabled"].as(/*global*/::config.engine.gc.enabled);
|
||||
/*global*/::config.engine.gc.every = configEngineDebugJson["garbage collection"]["every"].as(/*global*/::config.engine.gc.every);
|
||||
/*global*/::config.engine.gc.mode = configEngineDebugJson["garbage collection"]["mode"].as(/*global*/::config.engine.gc.mode);
|
||||
/*global*/::config.engine.gc.announce = configEngineDebugJson["garbage collection"]["announce"].as(/*global*/::config.engine.gc.announce);
|
||||
|
||||
if ( configEngineThreadJson["frame limiter"].as<uf::stl::string>() == "auto" && json["window"]["refresh rate"].is<size_t>() ) {
|
||||
float scale = 2.0;
|
||||
size_t refreshRate = json["window"]["refresh rate"].as<size_t>();
|
||||
configEngineThreadJson["frame limiter"] = refreshRate * scale;
|
||||
UF_MSG_DEBUG("Setting thread frame limiter to {}", (int) refreshRate * scale);
|
||||
/*global*/::config.engine.limiter.print = configEngineDebugJson["framerate"]["print"].as(/*global*/::config.engine.limiter.print);
|
||||
/*global*/::config.engine.fps.print = configEngineDebugJson["framerate"]["print"].as(/*global*/::config.engine.fps.print);
|
||||
/*global*/::config.engine.fps.every = configEngineDebugJson["framerate"]["every"].as(/*global*/::config.engine.fps.every);
|
||||
|
||||
uf::Entity::deleteChildrenOnDestroy = configEngineDebugJson["entity"]["delete children on destroy"].as( uf::Entity::deleteChildrenOnDestroy );
|
||||
uf::Entity::deleteComponentsOnDestroy = configEngineDebugJson["entity"]["delete components on destroy"].as( uf::Entity::deleteComponentsOnDestroy );
|
||||
|
||||
uf::Object::assertionLoad = configEngineDebugJson["loader"]["assert"].as( uf::Object::assertionLoad );
|
||||
uf::asset::assertionLoad = configEngineDebugJson["loader"]["assert"].as( uf::asset::assertionLoad );
|
||||
uf::asset::asyncQueue = configEngineDebugJson["loader"]["async"].as( uf::asset::asyncQueue );
|
||||
|
||||
uf::userdata::autoDestruct = configEngineDebugJson["userdata"]["auto destruct"].as( uf::userdata::autoDestruct );
|
||||
uf::userdata::autoValidate = configEngineDebugJson["userdata"]["auto validate"].as( uf::userdata::autoValidate );
|
||||
|
||||
uf::Object::deferLazyCalls = configEngineDebugJson["hooks"]["defer lazy calls"].as( uf::Object::deferLazyCalls );
|
||||
uf::scene::printTaskCalls = configEngineDebugJson["scene"]["print task calls"].as( uf::scene::printTaskCalls );
|
||||
}
|
||||
// Limiter settings
|
||||
{
|
||||
auto& configEngineLimitersJson = json["engine"]["limiters"];
|
||||
if ( configEngineLimitersJson["framerate"].as<uf::stl::string>() == "auto" && json["window"]["refresh rate"].is<size_t>() ) {
|
||||
float scale = 1.0;
|
||||
size_t refreshRate = json["window"]["refresh rate"].as<size_t>();
|
||||
configEngineLimitersJson["framerate"] = refreshRate * scale;
|
||||
UF_MSG_DEBUG("Setting framerate cap to {}", (int) refreshRate * scale);
|
||||
}
|
||||
|
||||
/* Frame limiter */ {
|
||||
size_t limit = configEngineLimitersJson["framerate"].as<size_t>();
|
||||
/*global*/::times.limiter = limit != 0 ? 1.0 / limit : 0;
|
||||
UF_MSG_DEBUG("Limiter set to {} ms", /*global*/::times.limiter);
|
||||
}
|
||||
/* Max delta time */{
|
||||
size_t limit = configEngineLimitersJson["deltaTime"].as<size_t>();
|
||||
uf::physics::time::clamp = limit != 0 ? 1.0 / limit : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Thread frame limiter */ {
|
||||
size_t limit = configEngineThreadJson["frame limiter"].as<size_t>();
|
||||
uf::thread::limiter = limit != 0 ? 1.0 / limit : 0;
|
||||
// Thread settings
|
||||
{
|
||||
auto& configEngineThreadJson = json["engine"]["threads"];
|
||||
if ( configEngineThreadJson["frame limiter"].as<uf::stl::string>() == "auto" && json["window"]["refresh rate"].is<size_t>() ) {
|
||||
float scale = 2.0;
|
||||
size_t refreshRate = json["window"]["refresh rate"].as<size_t>();
|
||||
configEngineThreadJson["frame limiter"] = refreshRate * scale;
|
||||
UF_MSG_DEBUG("Setting thread frame limiter to {}", (int) refreshRate * scale);
|
||||
}
|
||||
|
||||
/* Thread frame limiter */ {
|
||||
size_t limit = configEngineThreadJson["frame limiter"].as<size_t>();
|
||||
uf::thread::limiter = limit != 0 ? 1.0 / limit : 0;
|
||||
}
|
||||
|
||||
// Set worker threads
|
||||
if ( configEngineThreadJson["workers"].as<uf::stl::string>() == "auto" ) {
|
||||
auto threads = std::max( 1, (int) std::thread::hardware_concurrency() - 1 ) / 2;
|
||||
configEngineThreadJson["workers"] = threads;
|
||||
uf::thread::workers = configEngineThreadJson["workers"].as<size_t>();
|
||||
UF_MSG_DEBUG("Using {} worker threads", threads);
|
||||
} else if ( configEngineThreadJson["workers"].is<size_t>() ) {
|
||||
auto threads = configEngineThreadJson["workers"].as<size_t>();
|
||||
uf::thread::workers = threads;
|
||||
UF_MSG_DEBUG("Using {} worker threads", threads);
|
||||
}
|
||||
}
|
||||
|
||||
// Set worker threads
|
||||
if ( configEngineThreadJson["workers"].as<uf::stl::string>() == "auto" ) {
|
||||
auto threads = std::max( 1, (int) std::thread::hardware_concurrency() - 1 ) / 2;
|
||||
configEngineThreadJson["workers"] = threads;
|
||||
uf::thread::workers = configEngineThreadJson["workers"].as<size_t>();
|
||||
UF_MSG_DEBUG("Using {} worker threads", threads);
|
||||
} else if ( configEngineThreadJson["workers"].is<size_t>() ) {
|
||||
auto threads = configEngineThreadJson["workers"].as<size_t>();
|
||||
uf::thread::workers = threads;
|
||||
UF_MSG_DEBUG("Using {} worker threads", threads);
|
||||
// Physics settings
|
||||
{
|
||||
auto& confingEnginePhysicsJson = json["engine"]["physics"];
|
||||
uf::physics::settings.warmupSolver = confingEnginePhysicsJson["warmup solver"].as(uf::physics::settings.warmupSolver);
|
||||
uf::physics::settings.blockContactSolver = confingEnginePhysicsJson["block solver"].as(uf::physics::settings.blockContactSolver);
|
||||
uf::physics::settings.psgContactSolver = confingEnginePhysicsJson["psg solver"].as(uf::physics::settings.psgContactSolver);
|
||||
uf::physics::settings.useGjk = confingEnginePhysicsJson["gjk"].as(uf::physics::settings.useGjk);
|
||||
uf::physics::settings.fixedStep = confingEnginePhysicsJson["fixed step"].as(uf::physics::settings.fixedStep);
|
||||
uf::physics::settings.substeps = confingEnginePhysicsJson["substeps"].as(uf::physics::settings.substeps);
|
||||
uf::physics::settings.solverIterations = confingEnginePhysicsJson["solver iterations"].as(uf::physics::settings.solverIterations);
|
||||
}
|
||||
|
||||
// Audio settings
|
||||
auto& configEngineAudioJson = json["engine"]["audio"];
|
||||
{
|
||||
auto& configEngineAudioJson = json["engine"]["audio"];
|
||||
uf::audio::muted = configEngineAudioJson["mute"].as( uf::audio::muted );
|
||||
uf::audio::asyncUpdate = configEngineAudioJson["async update"].as( uf::audio::asyncUpdate );
|
||||
uf::audio::streamsByDefault = configEngineAudioJson["streams by default"].as( uf::audio::streamsByDefault );
|
||||
uf::audio::bufferSize = configEngineAudioJson["buffers"]["size"].as( uf::audio::bufferSize );
|
||||
uf::audio::buffers = configEngineAudioJson["buffers"]["count"].as( uf::audio::buffers );
|
||||
#if UF_AUDIO_MAPPED_VOLUMES
|
||||
ext::json::forEach( configEngineAudioJson["volumes"], []( const uf::stl::string& key, ext::json::Value& value ){
|
||||
float volume; volume = value.as(volume);
|
||||
uf::audio::volumes[key] = volume;
|
||||
});
|
||||
#else
|
||||
if ( ext::json::isObject( configEngineAudioJson["volumes"] ) ) {
|
||||
uf::audio::volumes::bgm = configEngineAudioJson["volumes"]["bgm"].as(uf::audio::volumes::bgm);
|
||||
uf::audio::volumes::sfx = configEngineAudioJson["volumes"]["sfx"].as(uf::audio::volumes::sfx);
|
||||
uf::audio::volumes::voice = configEngineAudioJson["volumes"]["voice"].as(uf::audio::volumes::voice);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uf::audio::muted = configEngineAudioJson["mute"].as( uf::audio::muted );
|
||||
uf::audio::asyncUpdate = configEngineAudioJson["async update"].as( uf::audio::asyncUpdate );
|
||||
uf::audio::streamsByDefault = configEngineAudioJson["streams by default"].as( uf::audio::streamsByDefault );
|
||||
uf::audio::bufferSize = configEngineAudioJson["buffers"]["size"].as( uf::audio::bufferSize );
|
||||
uf::audio::buffers = configEngineAudioJson["buffers"]["count"].as( uf::audio::buffers );
|
||||
#if UF_AUDIO_MAPPED_VOLUMES
|
||||
ext::json::forEach( configEngineAudioJson["volumes"], []( const uf::stl::string& key, ext::json::Value& value ){
|
||||
float volume; volume = value.as(volume);
|
||||
uf::audio::volumes[key] = volume;
|
||||
});
|
||||
#else
|
||||
if ( ext::json::isObject( configEngineAudioJson["volumes"] ) ) {
|
||||
uf::audio::volumes::bgm = configEngineAudioJson["volumes"]["bgm"].as(uf::audio::volumes::bgm);
|
||||
uf::audio::volumes::sfx = configEngineAudioJson["volumes"]["sfx"].as(uf::audio::volumes::sfx);
|
||||
uf::audio::volumes::voice = configEngineAudioJson["volumes"]["voice"].as(uf::audio::volumes::voice);
|
||||
// Various external settings
|
||||
{
|
||||
/*global*/::config.engine.ext.discord.enabled = json["engine"]["ext"]["discord"]["enabled"].as(/*global*/::config.engine.ext.discord.enabled);
|
||||
/*global*/::config.engine.ext.imgui.enabled = json["engine"]["ext"]["imgui"]["enabled"].as(/*global*/::config.engine.ext.imgui.enabled);
|
||||
}
|
||||
// VALL-E settings
|
||||
{
|
||||
auto& configEngineExtValleJson = json["engine"]["ext"]["vall_e"];
|
||||
/*global*/::config.engine.ext.vall_e.enabled = configEngineExtValleJson["enabled"].as(/*global*/::config.engine.ext.vall_e.enabled);
|
||||
/*global*/::config.engine.ext.vall_e.model_path = configEngineExtValleJson["model_path"].as(/*global*/::config.engine.ext.vall_e.model_path);
|
||||
/*global*/::config.engine.ext.vall_e.encodec_path = configEngineExtValleJson["encodec_path"].as(/*global*/::config.engine.ext.vall_e.encodec_path);
|
||||
}
|
||||
|
||||
#if UF_USE_ULTRALIGHT
|
||||
// Ultralight settings (painfully unused)
|
||||
{
|
||||
auto& configEngineExtUltralightJson = json["engine"]["ext"]["ultralight"];
|
||||
/*global*/::config.engine.ext.ultralight.enabled = configEngineExtUltralightJson["enabled"].as(/*global*/::config.engine.ext.ultralight.enabled);
|
||||
ext::ultralight::scale = configEngineExtUltralightJson["scale"].as( ext::ultralight::scale );
|
||||
ext::ultralight::log = configEngineExtUltralightJson["log"].as( ext::ultralight::log );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UF_USE_ULTRALIGHT
|
||||
ext::ultralight::scale = json["engine"]["ext"]["ultralight"]["scale"].as( ext::ultralight::scale );
|
||||
ext::ultralight::log = json["engine"]["ext"]["ultralight"]["log"].as( ext::ultralight::log );
|
||||
#endif
|
||||
// Renderer settings
|
||||
{
|
||||
#if UF_USE_VULKAN
|
||||
auto& configRenderJson = json["engine"]["ext"]["vulkan"];
|
||||
#elif UF_USE_OPENGL
|
||||
auto& configRenderJson = json["engine"]["ext"]["opengl"];
|
||||
#else
|
||||
auto& configRenderJson = json["engine"]["ext"]["software"];
|
||||
#endif
|
||||
auto& configRenderInvariantJson = configRenderJson["invariant"];
|
||||
auto& configRenderExperimentalJson = configRenderJson["experimental"];
|
||||
auto& configRenderPipelinesJson = configRenderJson["pipelines"];
|
||||
|
||||
#if UF_USE_VULKAN
|
||||
auto& configRenderJson = json["engine"]["ext"]["vulkan"];
|
||||
#elif UF_USE_OPENGL
|
||||
auto& configRenderJson = json["engine"]["ext"]["opengl"];
|
||||
#else
|
||||
auto& configRenderJson = json["engine"]["ext"]["software"];
|
||||
#endif
|
||||
auto& configRenderInvariantJson = configRenderJson["invariant"];
|
||||
auto& configRenderExperimentalJson = configRenderJson["experimental"];
|
||||
auto& configRenderPipelinesJson = configRenderJson["pipelines"];
|
||||
|
||||
uf::renderer::settings::validation::messages = configRenderJson["validation"]["messages"].as( uf::renderer::settings::validation::messages );
|
||||
uf::renderer::settings::validation::checkpoints = configRenderJson["validation"]["checkpoints"].as( uf::renderer::settings::validation::checkpoints );
|
||||
|
||||
uf::renderer::settings::experimental::batchQueueSubmissions = configRenderExperimentalJson["batch queue submissions"].as( uf::renderer::settings::experimental::batchQueueSubmissions );
|
||||
|
||||
#if UF_USE_VULKAN
|
||||
uf::renderer::settings::defaultStageBuffers = configRenderInvariantJson["default stage buffers"].as( uf::renderer::settings::defaultStageBuffers );
|
||||
uf::renderer::settings::defaultDeferBufferDestroy = configRenderInvariantJson["default defer buffer destroy"].as( uf::renderer::settings::defaultDeferBufferDestroy );
|
||||
#if 0
|
||||
uf::renderer::settings::defaultCommandBufferImmediate = true;
|
||||
/*global*/::requestDeferredCommandBufferSubmit = !configRenderInvariantJson["default command buffer immediate"].as( uf::renderer::settings::defaultCommandBufferImmediate );
|
||||
#else
|
||||
uf::renderer::settings::defaultCommandBufferImmediate = configRenderInvariantJson["default command buffer immediate"].as( uf::renderer::settings::defaultCommandBufferImmediate );
|
||||
#endif
|
||||
uf::renderer::settings::nBufferedUbos = configRenderInvariantJson["n-buffered uniform"].as( uf::renderer::settings::nBufferedUbos );
|
||||
#endif
|
||||
#if 1
|
||||
uf::renderer::settings::experimental::dedicatedThread = false;
|
||||
/*global*/::requestDedicatedRenderThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread );
|
||||
#else
|
||||
uf::renderer::settings::experimental::dedicatedThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread );
|
||||
#endif
|
||||
uf::renderer::settings::invariant::multithreadedRecording = configRenderInvariantJson["multithreaded recording"].as( uf::renderer::settings::invariant::multithreadedRecording );
|
||||
uf::renderer::settings::invariant::waitOnRenderEnd = configRenderInvariantJson["wait on render end"].as( uf::renderer::settings::invariant::waitOnRenderEnd );
|
||||
uf::renderer::settings::invariant::individualPipelines = configRenderInvariantJson["individual pipelines"].as( uf::renderer::settings::invariant::individualPipelines );
|
||||
uf::renderer::settings::validation::messages = configRenderJson["validation"]["messages"].as( uf::renderer::settings::validation::messages );
|
||||
uf::renderer::settings::validation::checkpoints = configRenderJson["validation"]["checkpoints"].as( uf::renderer::settings::validation::checkpoints );
|
||||
|
||||
uf::renderer::settings::experimental::batchQueueSubmissions = configRenderExperimentalJson["batch queue submissions"].as( uf::renderer::settings::experimental::batchQueueSubmissions );
|
||||
|
||||
#if UF_USE_VULKAN
|
||||
uf::renderer::settings::defaultStageBuffers = configRenderInvariantJson["default stage buffers"].as( uf::renderer::settings::defaultStageBuffers );
|
||||
uf::renderer::settings::defaultDeferBufferDestroy = configRenderInvariantJson["default defer buffer destroy"].as( uf::renderer::settings::defaultDeferBufferDestroy );
|
||||
#if 0
|
||||
uf::renderer::settings::defaultCommandBufferImmediate = true;
|
||||
/*global*/::requestDeferredCommandBufferSubmit = !configRenderInvariantJson["default command buffer immediate"].as( uf::renderer::settings::defaultCommandBufferImmediate );
|
||||
#else
|
||||
uf::renderer::settings::defaultCommandBufferImmediate = configRenderInvariantJson["default command buffer immediate"].as( uf::renderer::settings::defaultCommandBufferImmediate );
|
||||
#endif
|
||||
uf::renderer::settings::nBufferedUbos = configRenderInvariantJson["n-buffered uniform"].as( uf::renderer::settings::nBufferedUbos );
|
||||
#endif
|
||||
#if 1
|
||||
uf::renderer::settings::experimental::dedicatedThread = false;
|
||||
/*global*/::requestDedicatedRenderThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread );
|
||||
#else
|
||||
uf::renderer::settings::experimental::dedicatedThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread );
|
||||
#endif
|
||||
uf::renderer::settings::invariant::multithreadedRecording = configRenderInvariantJson["multithreaded recording"].as( uf::renderer::settings::invariant::multithreadedRecording );
|
||||
uf::renderer::settings::invariant::waitOnRenderEnd = configRenderInvariantJson["wait on render end"].as( uf::renderer::settings::invariant::waitOnRenderEnd );
|
||||
uf::renderer::settings::invariant::individualPipelines = configRenderInvariantJson["individual pipelines"].as( uf::renderer::settings::invariant::individualPipelines );
|
||||
}
|
||||
#if UF_USE_FFX_FSR || UF_USE_FFX_SDK
|
||||
ext::fsr::preset = json["engine"]["ext"]["fsr"]["preset"].as(ext::fsr::preset);
|
||||
ext::fsr::jitterScale = json["engine"]["ext"]["fsr"]["jitter scale"].as(ext::fsr::jitterScale);
|
||||
|
||||
@ -5,8 +5,13 @@
|
||||
namespace binds {
|
||||
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; }
|
||||
pod::Vector3f& angularVelocity( pod::PhysicsBody& self ) { return self.angularVelocity; }
|
||||
|
||||
void setVelocity( pod::PhysicsBody& self, const pod::Vector3f& v ) { uf::physics::setVelocity( self, v ); }
|
||||
void setAngularVelocity( pod::PhysicsBody& self, const pod::Quaternion<>& q, float dt = 0 ) { uf::physics::setAngularVelocity( self, q, dt ); }
|
||||
|
||||
void applyVelocity( pod::PhysicsBody& self, const pod::Vector3f& v ) { uf::physics::applyVelocity( self, v ); }
|
||||
void applyAngularVelocity( pod::PhysicsBody& self, const pod::Quaternion<>& q, float dt = 0 ) { uf::physics::applyAngularVelocity( self, q, dt ); }
|
||||
|
||||
float getMass( const pod::PhysicsBody& self ) { return self.mass; }
|
||||
void setMass( pod::PhysicsBody& self, float mass ) { self.mass = mass; }
|
||||
@ -36,9 +41,13 @@ namespace binds {
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::PhysicsBody,
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( hasBody, UF_LUA_C_FUN(::binds::hasBody) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( velocity, UF_LUA_C_FUN(::binds::velocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( angularVelocity, UF_LUA_C_FUN(::binds::angularVelocity) ),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setVelocity, UF_LUA_C_FUN(::binds::setVelocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyVelocity, UF_LUA_C_FUN(::binds::applyVelocity) ),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setAngularVelocity, UF_LUA_C_FUN(::binds::setAngularVelocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyAngularVelocity, UF_LUA_C_FUN(::binds::applyAngularVelocity) ),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyImpulse, UF_LUA_C_FUN(uf::physics::applyImpulse) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyRotation, UF_LUA_C_FUN(::binds::applyRotation) ),
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
|
||||
namespace impl {
|
||||
void updateStaticBody( pod::PhysicsBody& body ) {
|
||||
if ( !body.isStatic ) return;
|
||||
if ( !body.isStatic ) return;
|
||||
|
||||
body.bounds = impl::computeAABB( body );
|
||||
if ( body.world ) body.world->staticBvh.dirty = true;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
if ( body.world ) body.world->staticBvh.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,6 +74,8 @@ pod::Transform<> impl::getTransform( const pod::PhysicsBody& body ) {
|
||||
}
|
||||
|
||||
pod::Vector3f impl::getPosition( const pod::PhysicsBody& body, bool useTransform ) {
|
||||
useTransform = true; // guh
|
||||
|
||||
if ( !useTransform ) return impl::aabbCenter( body.bounds );
|
||||
return impl::getTransform( body ).position;
|
||||
}
|
||||
@ -112,7 +114,11 @@ pod::Matrix3f impl::computeWorldInverseInertia( const pod::PhysicsBody& b ) {
|
||||
pod::Matrix3f invI_local = uf::matrix::diagonal( b.inverseInertiaTensor );
|
||||
pod::Matrix3f R = uf::quaternion::matrix3(b.transform->orientation);
|
||||
|
||||
#if 1
|
||||
return R * invI_local * uf::matrix::transpose(R);
|
||||
#else
|
||||
return uf::matrix::transpose(R) * invI_local * R;
|
||||
#endif
|
||||
}
|
||||
|
||||
// normalizes the delta between two bodies / contacts by the distance (as it was already computed) if non-zero
|
||||
@ -423,14 +429,14 @@ bool impl::triangleTriangleIntersect( const pod::Triangle& a, const pod::Triangl
|
||||
if ( !impl::aabbOverlap( boxA, boxB ) ) return false;
|
||||
|
||||
// check vertices of a inside b or vice versa
|
||||
FOR_EACH(3, {
|
||||
for ( auto i = 0; i < 3; ++i ) {
|
||||
auto q = impl::closestPointOnTriangle( a.points[i], b );
|
||||
if ( uf::vector::magnitude( q - a.points[i] ) < EPS2 ) return true;
|
||||
});
|
||||
FOR_EACH(3, {
|
||||
};
|
||||
for ( auto i = 0; i < 3; ++i ) {
|
||||
auto q = impl::closestPointOnTriangle( b.points[i], a );
|
||||
if ( uf::vector::magnitude( q - b.points[i] ) < EPS2 ) return true;
|
||||
});
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -547,7 +553,7 @@ pod::TriangleWithNormal impl::fetchTriangle( const uf::Mesh& mesh, size_t triID,
|
||||
|
||||
bool impl::computeTriangleTriangleSegment( const pod::TriangleWithNormal& A, const pod::TriangleWithNormal& B, pod::Vector3f& p0, pod::Vector3f& p1 ) {
|
||||
int intersections = 0;
|
||||
pod::Vector3f intersectionBuffers[6];
|
||||
pod::Vector3f intersectionBuffers[6] = {};
|
||||
|
||||
auto checkAndPush = [&]( const pod::Vector3f& pt ) {
|
||||
// avoid duplicates
|
||||
@ -727,7 +733,8 @@ std::pair<pod::Vector3f, pod::Vector3f> impl::getCapsuleSegment( const pod::Phys
|
||||
pod::AABB impl::computeAABB( const pod::PhysicsBody& body ) {
|
||||
const auto transform = impl::getTransform( body );
|
||||
switch ( body.collider.type ) {
|
||||
case pod::ShapeType::AABB: {
|
||||
case pod::ShapeType::AABB:
|
||||
case pod::ShapeType::OBB: {
|
||||
return impl::transformAabbToWorld( body.collider.aabb, *body.transform );
|
||||
/*
|
||||
return {
|
||||
@ -817,11 +824,11 @@ bool impl::triAabbOverlap( const pod::Triangle& tri, const pod::AABB& box ) {
|
||||
if ( !axisTest( {-f2.y, f2.x, 0} ) ) return false;
|
||||
|
||||
// test AABB face axes
|
||||
FOR_EACH(3, {
|
||||
for ( auto i = 0; i < 3; ++i ) {
|
||||
float minVal = std::min({v0[i], v1[i], v2[i]});
|
||||
float maxVal = std::max({v0[i], v1[i], v2[i]});
|
||||
if ( minVal > e[i] || maxVal < -e[i] ) return false;
|
||||
});
|
||||
};
|
||||
|
||||
// test triangle normal axis
|
||||
auto n = uf::vector::cross( f0, f1 );
|
||||
|
||||
@ -193,7 +193,7 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
// pass manifolds to solver
|
||||
impl::solveContacts( manifolds, dt );
|
||||
// do position correction
|
||||
// impl::solvePositions( manifolds, dt );
|
||||
impl::solvePositions( manifolds, dt );
|
||||
// cache manifold positions
|
||||
if ( uf::physics::settings.warmupSolver ) {
|
||||
impl::updateManifoldCache( manifolds, uf::physics::settings.manifoldsCache );
|
||||
@ -260,7 +260,8 @@ void uf::physics::updateInertia( pod::PhysicsBody& body ) {
|
||||
}
|
||||
|
||||
switch ( body.collider.type ) {
|
||||
case pod::ShapeType::AABB: {
|
||||
case pod::ShapeType::AABB:
|
||||
case pod::ShapeType::OBB: {
|
||||
pod::Vector3f dims = (body.collider.aabb.max - body.collider.aabb.min);
|
||||
pod::Vector3f dimsSq = dims * dims;
|
||||
body.inertiaTensor = pod::Vector3f{ dimsSq.y + dimsSq.z, dimsSq.x + dimsSq.z, dimsSq.x + dimsSq.y } * (body.mass / 12.0f);
|
||||
@ -344,11 +345,13 @@ void uf::physics::updateInertia( pod::PhysicsBody& body ) {
|
||||
}
|
||||
}
|
||||
void uf::physics::applyForce( pod::PhysicsBody& body, const pod::Vector3f& force ) {
|
||||
if ( body.isStatic ) return; impl::wakeBody( body );
|
||||
if ( body.isStatic ) return;
|
||||
impl::wakeBody( body );
|
||||
body.forceAccumulator += force;
|
||||
}
|
||||
void uf::physics::applyForceAtPoint( pod::PhysicsBody& body, const pod::Vector3f& force, const pod::Vector3f& point ) {
|
||||
if ( body.isStatic ) return; impl::wakeBody( body );
|
||||
if ( body.isStatic ) return;
|
||||
impl::wakeBody( body );
|
||||
// linear force
|
||||
body.forceAccumulator += force;
|
||||
// angular force
|
||||
@ -367,6 +370,50 @@ void uf::physics::setVelocity( pod::PhysicsBody& body, const pod::Vector3f& v )
|
||||
impl::wakeBody( body );
|
||||
body.velocity = v;
|
||||
}
|
||||
void uf::physics::applyVelocity( pod::PhysicsBody& body, const pod::Vector3f& v ) {
|
||||
impl::wakeBody( body );
|
||||
body.velocity += v;
|
||||
}
|
||||
void uf::physics::setAngularVelocity( pod::PhysicsBody& body, const pod::Vector3f& v ) {
|
||||
impl::wakeBody( body );
|
||||
body.angularVelocity = v;
|
||||
}
|
||||
void uf::physics::setAngularVelocity( pod::PhysicsBody& body, const pod::Quaternion<>& q, float dt ) {
|
||||
if ( !dt ) dt = uf::physics::time::delta;
|
||||
float angle = 2.0f * std::acos( q.w );
|
||||
float sinHalfAngle = std::sqrt( 1.0f - q.w * q.w );
|
||||
|
||||
pod::Vector3f axis{ 0, 0, 0 };
|
||||
if ( sinHalfAngle > EPS ) {
|
||||
axis.x = q.x / sinHalfAngle;
|
||||
axis.y = q.y / sinHalfAngle;
|
||||
axis.z = q.z / sinHalfAngle;
|
||||
}
|
||||
|
||||
impl::wakeBody( body );
|
||||
body.angularVelocity = axis * ( angle / dt );
|
||||
UF_MSG_DEBUG("axis={}, angle={}, dt={}", uf::vector::toString( axis ), angle, dt );
|
||||
}
|
||||
void uf::physics::applyAngularVelocity( pod::PhysicsBody& body, const pod::Vector3f& v ) {
|
||||
impl::wakeBody( body );
|
||||
body.angularVelocity += v;
|
||||
}
|
||||
void uf::physics::applyAngularVelocity( pod::PhysicsBody& body, const pod::Quaternion<>& q, float dt ) {
|
||||
if ( !dt ) dt = uf::physics::time::delta;
|
||||
float angle = 2.0f * std::acos( q.w );
|
||||
float sinHalfAngle = std::sqrt( 1.0f - q.w * q.w );
|
||||
|
||||
pod::Vector3f axis{ 0, 0, 0 };
|
||||
if ( sinHalfAngle > EPS ) {
|
||||
axis.x = q.x / sinHalfAngle;
|
||||
axis.y = q.y / sinHalfAngle;
|
||||
axis.z = q.z / sinHalfAngle;
|
||||
}
|
||||
|
||||
impl::wakeBody( body );
|
||||
body.angularVelocity += axis * ( angle / dt );
|
||||
UF_MSG_DEBUG("axis={}, angle={}, dt={}", uf::vector::toString( axis ), angle, dt );
|
||||
}
|
||||
void uf::physics::applyRotation( pod::PhysicsBody& body, const pod::Quaternion<>& q ) {
|
||||
impl::wakeBody( body );
|
||||
uf::transform::rotate( *body.transform/*.reference*/, q );
|
||||
@ -404,7 +451,8 @@ pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, fl
|
||||
}
|
||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, const pod::AABB& aabb, float mass, const pod::Vector3f& offset ) {
|
||||
auto& body = uf::physics::create( world, object, mass, offset );
|
||||
body.collider.type = pod::ShapeType::AABB;
|
||||
//body.collider.type = pod::ShapeType::AABB;
|
||||
body.collider.type = pod::ShapeType::OBB;
|
||||
body.collider.aabb = aabb;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
@ -548,6 +596,7 @@ pod::RayQuery uf::physics::rayCast( const pod::Ray& ray, const pod::World& world
|
||||
|
||||
switch ( b->collider.type ) {
|
||||
case pod::ShapeType::AABB: impl::rayAabb( ray, *b, rayHit ); break;
|
||||
case pod::ShapeType::OBB: impl::rayObb( ray, *b, rayHit ); break;
|
||||
case pod::ShapeType::SPHERE: impl::raySphere( ray, *b, rayHit ); break;
|
||||
case pod::ShapeType::PLANE: impl::rayPlane( ray, *b, rayHit ); break;
|
||||
case pod::ShapeType::CAPSULE: impl::rayCapsule( ray, *b, rayHit ); break;
|
||||
|
||||
@ -84,13 +84,23 @@ bool impl::generateContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Mani
|
||||
if ( a.collider.type == pod::ShapeType::A && b.collider.type == pod::ShapeType::B ) return fun( a, b, manifold );
|
||||
|
||||
CHECK_CONTACT( AABB, AABB, impl::aabbAabb );
|
||||
CHECK_CONTACT( AABB, OBB, impl::aabbObb );
|
||||
CHECK_CONTACT( AABB, SPHERE, impl::aabbSphere );
|
||||
CHECK_CONTACT( AABB, PLANE, impl::aabbPlane );
|
||||
CHECK_CONTACT( AABB, CAPSULE, impl::aabbCapsule );
|
||||
CHECK_CONTACT( AABB, MESH, impl::aabbMesh );
|
||||
CHECK_CONTACT( AABB, CONVEX_HULL, impl::aabbHull );
|
||||
|
||||
CHECK_CONTACT( OBB, AABB, impl::obbAabb );
|
||||
CHECK_CONTACT( OBB, OBB, impl::obbObb );
|
||||
CHECK_CONTACT( OBB, SPHERE, impl::obbSphere );
|
||||
CHECK_CONTACT( OBB, PLANE, impl::obbPlane );
|
||||
CHECK_CONTACT( OBB, CAPSULE, impl::obbCapsule );
|
||||
CHECK_CONTACT( OBB, MESH, impl::obbMesh );
|
||||
CHECK_CONTACT( OBB, CONVEX_HULL, impl::obbHull );
|
||||
|
||||
CHECK_CONTACT( SPHERE, AABB, impl::sphereAabb );
|
||||
CHECK_CONTACT( SPHERE, OBB, impl::sphereObb );
|
||||
CHECK_CONTACT( SPHERE, SPHERE, impl::sphereSphere );
|
||||
CHECK_CONTACT( SPHERE, PLANE, impl::spherePlane );
|
||||
CHECK_CONTACT( SPHERE, CAPSULE, impl::sphereCapsule );
|
||||
@ -98,6 +108,7 @@ bool impl::generateContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Mani
|
||||
CHECK_CONTACT( SPHERE, CONVEX_HULL, impl::sphereHull );
|
||||
|
||||
CHECK_CONTACT( PLANE, AABB, impl::planeAabb );
|
||||
CHECK_CONTACT( PLANE, OBB, impl::planeObb );
|
||||
CHECK_CONTACT( PLANE, SPHERE, impl::planeSphere );
|
||||
CHECK_CONTACT( PLANE, PLANE, impl::planePlane );
|
||||
CHECK_CONTACT( PLANE, CAPSULE, impl::planeCapsule );
|
||||
@ -105,6 +116,7 @@ bool impl::generateContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Mani
|
||||
CHECK_CONTACT( PLANE, CONVEX_HULL, impl::planeHull );
|
||||
|
||||
CHECK_CONTACT( CAPSULE, AABB, impl::capsuleAabb );
|
||||
CHECK_CONTACT( CAPSULE, OBB, impl::capsuleObb );
|
||||
CHECK_CONTACT( CAPSULE, SPHERE, impl::capsuleSphere );
|
||||
CHECK_CONTACT( CAPSULE, PLANE, impl::capsulePlane );
|
||||
CHECK_CONTACT( CAPSULE, CAPSULE, impl::capsuleCapsule );
|
||||
@ -112,6 +124,7 @@ bool impl::generateContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Mani
|
||||
CHECK_CONTACT( CAPSULE, CONVEX_HULL, impl::capsuleHull );
|
||||
|
||||
CHECK_CONTACT( MESH, AABB, impl::meshAabb );
|
||||
CHECK_CONTACT( MESH, OBB, impl::meshObb );
|
||||
CHECK_CONTACT( MESH, SPHERE, impl::meshSphere );
|
||||
CHECK_CONTACT( MESH, PLANE, impl::meshPlane );
|
||||
CHECK_CONTACT( MESH, CAPSULE, impl::meshCapsule );
|
||||
@ -119,6 +132,7 @@ bool impl::generateContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Mani
|
||||
CHECK_CONTACT( MESH, CONVEX_HULL, impl::meshHull );
|
||||
|
||||
CHECK_CONTACT( CONVEX_HULL, AABB, impl::hullAabb );
|
||||
CHECK_CONTACT( CONVEX_HULL, OBB, impl::hullObb );
|
||||
CHECK_CONTACT( CONVEX_HULL, SPHERE, impl::hullSphere );
|
||||
CHECK_CONTACT( CONVEX_HULL, PLANE, impl::hullPlane );
|
||||
CHECK_CONTACT( CONVEX_HULL, CAPSULE, impl::hullCapsule );
|
||||
@ -365,10 +379,17 @@ void impl::integrate( pod::PhysicsBody& body, float dt ) {
|
||||
// angular integration
|
||||
//body.angularVelocity += body.torqueAccumulator * body.inverseInertiaTensor * dt;
|
||||
{
|
||||
#if 1
|
||||
pod::Matrix3f R = uf::quaternion::matrix3(body.transform->orientation);
|
||||
pod::Vector3f localTorque = uf::matrix::multiply( uf::matrix::transpose(R), body.torqueAccumulator );
|
||||
pod::Vector3f localAngAccel = localTorque * body.inverseInertiaTensor; // element-wise
|
||||
body.angularVelocity += uf::matrix::multiply( R, localAngAccel ) * dt;
|
||||
#else
|
||||
pod::Matrix3f R = uf::quaternion::matrix3(body.transform->orientation);
|
||||
pod::Vector3f localTorque = uf::matrix::multiply( R, body.torqueAccumulator );
|
||||
pod::Vector3f localAngAccel = localTorque * body.inverseInertiaTensor; // element-wise
|
||||
body.angularVelocity += uf::matrix::multiply( uf::matrix::transpose(R), localAngAccel ) * dt;
|
||||
#endif
|
||||
}
|
||||
|
||||
// update position
|
||||
@ -378,7 +399,7 @@ void impl::integrate( pod::PhysicsBody& body, float dt ) {
|
||||
float angularSpeed2 = uf::vector::magnitude( body.angularVelocity );
|
||||
if ( angularSpeed2 > EPS2 ) {
|
||||
float angularSpeed = std::sqrt( angularSpeed2 );
|
||||
pod::Quaternion<> dq = uf::quaternion::axisAngle( body.angularVelocity / angularSpeed, angularSpeed * dt);
|
||||
pod::Quaternion<> dq = uf::quaternion::axisAngle( body.angularVelocity / angularSpeed, -angularSpeed * dt);
|
||||
uf::transform::rotate( *body.transform/*.reference*/, dq );
|
||||
}
|
||||
|
||||
|
||||
@ -52,7 +52,10 @@ bool impl::aabbAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool impl::aabbObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( AABB, OBB );
|
||||
REVERSE_COLLIDER( a, b, impl::obbAabb );
|
||||
}
|
||||
bool impl::aabbSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( AABB, SPHERE );
|
||||
REVERSE_COLLIDER( a, b, impl::sphereAabb );
|
||||
|
||||
@ -45,6 +45,10 @@ bool impl::capsuleAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, po
|
||||
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
|
||||
return true;
|
||||
}
|
||||
bool impl::capsuleObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( CAPSULE, OBB );
|
||||
REVERSE_COLLIDER( a, b, impl::obbCapsule );
|
||||
}
|
||||
bool impl::capsulePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( CAPSULE, PLANE );
|
||||
const auto& capsule = a;
|
||||
|
||||
@ -50,7 +50,8 @@ void impl::getSupportFace( const pod::PhysicsBody& body, const pod::Vector3f& di
|
||||
outPoly[i] = hasTransform ? uf::transform::apply( transform, body.collider.triangle.points[i] ) : body.collider.triangle.points[i];
|
||||
});
|
||||
} break;
|
||||
case pod::ShapeType::AABB: {
|
||||
case pod::ShapeType::AABB:
|
||||
case pod::ShapeType::OBB: {
|
||||
outCount = 4;
|
||||
pod::Vector3f n = localDir;
|
||||
pod::Vector3f absN = { std::fabs(n.x), std::fabs(n.y), std::fabs(n.z) };
|
||||
|
||||
@ -4,9 +4,6 @@
|
||||
pod::Vector3f impl::support( const pod::PhysicsBody& body, const pod::Vector3f& dir ) {
|
||||
const auto transform = impl::getTransform( body );
|
||||
switch ( body.collider.type ) {
|
||||
case pod::ShapeType::SPHERE: {
|
||||
return transform.position + uf::vector::normalize( dir ) * body.collider.sphere.radius;
|
||||
} break;
|
||||
case pod::ShapeType::AABB: {
|
||||
return {
|
||||
( dir.x >= 0.0f ) ? body.bounds.max.x : body.bounds.min.x,
|
||||
@ -14,6 +11,18 @@ pod::Vector3f impl::support( const pod::PhysicsBody& body, const pod::Vector3f&
|
||||
( dir.z >= 0.0f ) ? body.bounds.max.z : body.bounds.min.z
|
||||
};
|
||||
} break;
|
||||
case pod::ShapeType::OBB: {
|
||||
pod::Vector3f localDir = uf::quaternion::rotate( uf::quaternion::inverse(transform.orientation), dir );
|
||||
pod::Vector3f localPt = {
|
||||
( localDir.x >= 0.0f ) ? body.collider.obb.max.x : body.collider.obb.min.x,
|
||||
( localDir.y >= 0.0f ) ? body.collider.obb.max.y : body.collider.obb.min.y,
|
||||
( localDir.z >= 0.0f ) ? body.collider.obb.max.z : body.collider.obb.min.z
|
||||
};
|
||||
return uf::transform::apply( transform, localPt );
|
||||
} break;
|
||||
case pod::ShapeType::SPHERE: {
|
||||
return transform.position + uf::vector::normalize( dir ) * body.collider.sphere.radius;
|
||||
} break;
|
||||
case pod::ShapeType::PLANE: {
|
||||
const auto& plane = body.collider.plane;
|
||||
pod::Vector3f n = plane.normal;
|
||||
|
||||
@ -34,6 +34,10 @@ bool impl::hullAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
ASSERT_COLLIDER_TYPES( CONVEX_HULL, AABB );
|
||||
return hullGeneric(a, b, manifold );
|
||||
}
|
||||
bool impl::hullObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( CONVEX_HULL, OBB );
|
||||
return hullGeneric(a, b, manifold );
|
||||
}
|
||||
bool impl::hullSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( CONVEX_HULL, SPHERE );
|
||||
return hullGeneric(a, b, manifold );
|
||||
|
||||
@ -25,6 +25,29 @@ bool impl::meshAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
bool impl::meshObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( MESH, OBB );
|
||||
|
||||
const auto& mesh = a;
|
||||
const auto& obb = b;
|
||||
|
||||
const auto& bvh = *mesh.collider.mesh.bvh;
|
||||
const auto& meshData = *mesh.collider.mesh.mesh;
|
||||
|
||||
// transform to local space for BVH query
|
||||
auto bounds = impl::transformAabbToLocal( obb.bounds, impl::getTransform( mesh ) );
|
||||
STATIC_THREAD_LOCAL(uf::stl::vector<pod::BVH::index_t>, candidates);
|
||||
impl::queryBVH( bvh, bounds, candidates );
|
||||
|
||||
bool hit = false;
|
||||
// do collision per triangle
|
||||
for ( auto triID : candidates ) {
|
||||
auto tri = impl::fetchTriangle( meshData, triID, mesh ); // transform triangle to world space
|
||||
if ( !impl::triangleObb( tri, obb, manifold ) ) continue;
|
||||
hit = true;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
bool impl::meshSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( MESH, SPHERE );
|
||||
|
||||
|
||||
277
engine/src/utils/math/physics/narrowphase/obb.cpp
Normal file
277
engine/src/utils/math/physics/narrowphase/obb.cpp
Normal file
@ -0,0 +1,277 @@
|
||||
#include <uf/utils/math/physics/common.h>
|
||||
#include <uf/utils/math/physics/narrowphase.h>
|
||||
|
||||
bool impl::obbObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( OBB, OBB );
|
||||
|
||||
auto tA = impl::getTransform( a );
|
||||
auto tB = impl::getTransform( b );
|
||||
|
||||
pod::Vector3f cA = uf::transform::apply( tA, (a.collider.obb.max + a.collider.obb.min) * 0.5f );
|
||||
pod::Vector3f cB = uf::transform::apply( tB, (b.collider.obb.max + b.collider.obb.min) * 0.5f );
|
||||
pod::Vector3f eA = (a.collider.obb.max - a.collider.obb.min) * 0.5f;
|
||||
pod::Vector3f eB = (b.collider.obb.max - b.collider.obb.min) * 0.5f;
|
||||
|
||||
pod::Vector3f axesA[3] = {
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{1,0,0}),
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{0,1,0}),
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{0,0,1})
|
||||
};
|
||||
pod::Vector3f axesB[3] = {
|
||||
uf::quaternion::rotate(tB.orientation, pod::Vector3f{1,0,0}),
|
||||
uf::quaternion::rotate(tB.orientation, pod::Vector3f{0,1,0}),
|
||||
uf::quaternion::rotate(tB.orientation, pod::Vector3f{0,0,1})
|
||||
};
|
||||
|
||||
float minOverlap = FLT_MAX;
|
||||
pod::Vector3f bestAxis;
|
||||
|
||||
auto testAxis = [&](const pod::Vector3f& axis) -> bool {
|
||||
float mag = uf::vector::magnitude(axis);
|
||||
if (mag < EPS) return true;
|
||||
pod::Vector3f n = axis / mag;
|
||||
|
||||
float pA = uf::vector::dot(cA, n);
|
||||
float rA = eA.x * std::fabs(uf::vector::dot(axesA[0], n)) +
|
||||
eA.y * std::fabs(uf::vector::dot(axesA[1], n)) +
|
||||
eA.z * std::fabs(uf::vector::dot(axesA[2], n));
|
||||
|
||||
float pB = uf::vector::dot(cB, n);
|
||||
float rB = eB.x * std::fabs(uf::vector::dot(axesB[0], n)) +
|
||||
eB.y * std::fabs(uf::vector::dot(axesB[1], n)) +
|
||||
eB.z * std::fabs(uf::vector::dot(axesB[2], n));
|
||||
|
||||
float dist = std::fabs(pB - pA);
|
||||
float overlap = (rA + rB) - dist;
|
||||
|
||||
if ( overlap < 0) return false;
|
||||
|
||||
if ( overlap < minOverlap ) {
|
||||
minOverlap = overlap;
|
||||
bestAxis = n;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
for ( auto i = 0; i < 3; ++i ) if ( !testAxis(axesA[i]) ) return false;
|
||||
for ( auto i = 0; i < 3; ++i ) if ( !testAxis(axesB[i]) ) return false;
|
||||
for ( auto i = 0; i < 3; ++i ) {
|
||||
for ( auto j = 0; j < 3; j++ ) if ( !testAxis(uf::vector::cross(axesA[i], axesB[j])) ) return false;
|
||||
};
|
||||
|
||||
if ( uf::vector::dot(bestAxis, cB - cA) < 0.0f ) bestAxis = -bestAxis;
|
||||
|
||||
// to-do: generate contact face
|
||||
pod::Vector3f contactPoint = cA + bestAxis * (eA.x * std::fabs(uf::vector::dot(axesA[0], bestAxis)) +
|
||||
eA.y * std::fabs(uf::vector::dot(axesA[1], bestAxis)) +
|
||||
eA.z * std::fabs(uf::vector::dot(axesA[2], bestAxis)));
|
||||
|
||||
manifold.points.emplace_back( pod::Contact{ contactPoint, bestAxis, minOverlap } );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool impl::obbAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( OBB, AABB );
|
||||
|
||||
auto tA = impl::getTransform( a );
|
||||
|
||||
pod::Vector3f cA = uf::transform::apply( tA, (a.collider.obb.max + a.collider.obb.min) * 0.5f );
|
||||
pod::Vector3f eA = (a.collider.obb.max - a.collider.obb.min) * 0.5f;
|
||||
pod::Vector3f axesA[3] = {
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{1,0,0}),
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{0,1,0}),
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{0,0,1})
|
||||
};
|
||||
|
||||
pod::Vector3f cB = impl::aabbCenter( b.bounds );
|
||||
pod::Vector3f eB = impl::aabbExtent( b.bounds );
|
||||
pod::Vector3f axesB[3] = { {1,0,0}, {0,1,0}, {0,0,1} };
|
||||
|
||||
float minOverlap = FLT_MAX;
|
||||
pod::Vector3f bestAxis;
|
||||
|
||||
auto testAxis = [&](const pod::Vector3f& axis) -> bool {
|
||||
float mag = uf::vector::magnitude(axis);
|
||||
if ( mag < EPS ) return true;
|
||||
pod::Vector3f n = axis / mag;
|
||||
|
||||
float pA = uf::vector::dot(cA, n);
|
||||
float rA = eA.x * std::fabs(uf::vector::dot(axesA[0], n)) +
|
||||
eA.y * std::fabs(uf::vector::dot(axesA[1], n)) +
|
||||
eA.z * std::fabs(uf::vector::dot(axesA[2], n));
|
||||
|
||||
float pB = uf::vector::dot(cB, n);
|
||||
float rB = eB.x * std::fabs(n.x) + eB.y * std::fabs(n.y) + eB.z * std::fabs(n.z);
|
||||
|
||||
float dist = std::fabs(pB - pA);
|
||||
float overlap = (rA + rB) - dist;
|
||||
if ( overlap < 0 ) return false;
|
||||
if ( overlap < minOverlap ) {
|
||||
minOverlap = overlap;
|
||||
bestAxis = n;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
for ( auto i = 0; i < 3; ++i ) if ( !testAxis(axesA[i]) ) return false;
|
||||
for ( auto i = 0; i < 3; ++i ) if ( !testAxis(axesB[i]) ) return false;
|
||||
for ( auto i = 0; i < 3; ++i ) {
|
||||
for ( auto j = 0; j < 3; j++ ) if ( !testAxis(uf::vector::cross(axesA[i], axesB[j])) ) return false;
|
||||
};
|
||||
|
||||
if ( uf::vector::dot(bestAxis, cB - cA) < 0.0f ) bestAxis = -bestAxis;
|
||||
|
||||
pod::Vector3f contactPoint = cA + bestAxis * (eA.x * std::fabs(uf::vector::dot(axesA[0], bestAxis)) +
|
||||
eA.y * std::fabs(uf::vector::dot(axesA[1], bestAxis)) +
|
||||
eA.z * std::fabs(uf::vector::dot(axesA[2], bestAxis)));
|
||||
|
||||
manifold.points.emplace_back( pod::Contact{ contactPoint, bestAxis, minOverlap } );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool impl::obbSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( OBB, SPHERE );
|
||||
|
||||
auto tA = impl::getTransform( a );
|
||||
auto localCenter = ( a.collider.obb.max + a.collider.obb.min ) * 0.5f;
|
||||
auto extents = ( a.collider.obb.max - a.collider.obb.min ) * 0.5f;
|
||||
|
||||
auto sphereCenter = impl::getPosition( b );
|
||||
float radius = b.collider.sphere.radius;
|
||||
|
||||
auto localP = uf::transform::applyInverse( tA, sphereCenter ) - localCenter;
|
||||
auto closestLocal = uf::vector::clamp( localP, -extents, extents );
|
||||
|
||||
auto deltaLocal = localP - closestLocal;
|
||||
float distSq = uf::vector::dot( deltaLocal, deltaLocal );
|
||||
|
||||
if ( distSq > radius * radius ) return false;
|
||||
|
||||
auto closestWorld = uf::transform::apply( tA, closestLocal + localCenter );
|
||||
float dist = std::sqrt( distSq );
|
||||
|
||||
pod::Vector3f normal;
|
||||
float penetration;
|
||||
|
||||
if ( dist < EPS ) {
|
||||
float minDist = FLT_MAX;
|
||||
int axis = 0;
|
||||
float sign = 1.0f;
|
||||
|
||||
FOR_EACH(3, {
|
||||
float distToMax = extents[i] - localP[i];
|
||||
float distToMin = localP[i] - (-extents[i]);
|
||||
if (distToMax < minDist) { minDist = distToMax; axis = i; sign = 1.0f; }
|
||||
if (distToMin < minDist) { minDist = distToMin; axis = i; sign = -1.0f; }
|
||||
});
|
||||
|
||||
pod::Vector3f localNormal = {0,0,0};
|
||||
localNormal[axis] = sign;
|
||||
normal = uf::quaternion::rotate( tA.orientation, localNormal );
|
||||
penetration = radius + minDist;
|
||||
} else {
|
||||
normal = uf::quaternion::rotate( tA.orientation, deltaLocal / dist );
|
||||
penetration = radius - dist;
|
||||
}
|
||||
|
||||
manifold.points.emplace_back( pod::Contact{ closestWorld, normal, penetration } );
|
||||
return true;
|
||||
}
|
||||
bool impl::obbPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( OBB, PLANE );
|
||||
|
||||
auto tA = impl::getTransform( a );
|
||||
pod::Vector3f cA = uf::transform::apply( tA, (a.collider.obb.max + a.collider.obb.min) * 0.5f );
|
||||
pod::Vector3f eA = (a.collider.obb.max - a.collider.obb.min) * 0.5f;
|
||||
pod::Vector3f axesA[3] = {
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{1,0,0}),
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{0,1,0}),
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{0,0,1})
|
||||
};
|
||||
|
||||
pod::Vector3f normal = b.collider.plane.normal;
|
||||
float offset = b.collider.plane.offset;
|
||||
|
||||
float rA = eA.x * std::fabs(uf::vector::dot(axesA[0], normal)) +
|
||||
eA.y * std::fabs(uf::vector::dot(axesA[1], normal)) +
|
||||
eA.z * std::fabs(uf::vector::dot(axesA[2], normal));
|
||||
|
||||
float dist = uf::vector::dot(cA, normal) - offset;
|
||||
if ( dist > rA ) return false; // in front of plane
|
||||
|
||||
pod::Vector3f deepestPoint = cA
|
||||
- axesA[0] * eA.x * (uf::vector::dot(axesA[0], normal) > 0 ? 1.0f : -1.0f)
|
||||
- axesA[1] * eA.y * (uf::vector::dot(axesA[1], normal) > 0 ? 1.0f : -1.0f)
|
||||
- axesA[2] * eA.z * (uf::vector::dot(axesA[2], normal) > 0 ? 1.0f : -1.0f);
|
||||
|
||||
float penetration = rA - dist;
|
||||
manifold.points.emplace_back( pod::Contact{ deepestPoint, normal, penetration } );
|
||||
return true;
|
||||
|
||||
}
|
||||
bool impl::obbCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( OBB, CAPSULE );
|
||||
|
||||
auto tA = impl::getTransform( a );
|
||||
pod::Vector3f cA = uf::transform::apply( tA, (a.collider.obb.max + a.collider.obb.min) * 0.5f );
|
||||
pod::Vector3f eA = (a.collider.obb.max - a.collider.obb.min) * 0.5f;
|
||||
pod::Vector3f axesA[3] = {
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{1,0,0}),
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{0,1,0}),
|
||||
uf::quaternion::rotate(tA.orientation, pod::Vector3f{0,0,1})
|
||||
};
|
||||
|
||||
auto [p1, p2] = impl::getCapsuleSegment( b );
|
||||
pod::Vector3f cB = (p1 + p2) * 0.5f;
|
||||
pod::Vector3f capAxis = uf::vector::normalize(p2 - p1);
|
||||
float halfHeight = b.collider.capsule.halfHeight;
|
||||
float radius = b.collider.capsule.radius;
|
||||
|
||||
float minOverlap = FLT_MAX;
|
||||
pod::Vector3f bestAxis;
|
||||
|
||||
auto testAxis = [&](const pod::Vector3f& axis) -> bool {
|
||||
float mag = uf::vector::magnitude(axis);
|
||||
if (mag < EPS) return true;
|
||||
pod::Vector3f n = axis / mag;
|
||||
|
||||
float pA = uf::vector::dot(cA, n);
|
||||
float rA = eA.x * std::fabs(uf::vector::dot(axesA[0], n)) +
|
||||
eA.y * std::fabs(uf::vector::dot(axesA[1], n)) +
|
||||
eA.z * std::fabs(uf::vector::dot(axesA[2], n));
|
||||
|
||||
float pB = uf::vector::dot(cB, n);
|
||||
float rB = halfHeight * std::fabs(uf::vector::dot(capAxis, n)) + radius;
|
||||
|
||||
float dist = std::fabs(pB - pA);
|
||||
float overlap = (rA + rB) - dist;
|
||||
|
||||
if (overlap < 0) return false;
|
||||
|
||||
if (overlap < minOverlap) {
|
||||
minOverlap = overlap;
|
||||
bestAxis = n;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if ( !testAxis(capAxis) ) return false;
|
||||
for ( auto i = 0; i < 3; ++i ) if ( !testAxis(axesA[i]) ) return false;
|
||||
for ( auto i = 0; i < 3; ++i ) if ( !testAxis(uf::vector::cross(axesA[i], capAxis)) ) return false;
|
||||
|
||||
if ( uf::vector::dot(bestAxis, cB - cA) < 0.0f ) bestAxis = -bestAxis;
|
||||
|
||||
pod::Vector3f contactPoint = cB - bestAxis * radius;
|
||||
|
||||
manifold.points.emplace_back( pod::Contact{ contactPoint, bestAxis, minOverlap } );
|
||||
return true;
|
||||
}
|
||||
bool impl::obbMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( OBB, MESH );
|
||||
REVERSE_COLLIDER( a, b, impl::meshObb );
|
||||
}
|
||||
bool impl::obbHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( OBB, CONVEX_HULL );
|
||||
REVERSE_COLLIDER( a, b, impl::hullObb );
|
||||
}
|
||||
@ -23,6 +23,10 @@ bool impl::planeAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod:
|
||||
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
|
||||
return true;
|
||||
}
|
||||
bool impl::planeObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( PLANE, OBB );
|
||||
REVERSE_COLLIDER( a, b, impl::obbPlane );
|
||||
}
|
||||
bool impl::planeSphere(const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold) {
|
||||
ASSERT_COLLIDER_TYPES(PLANE, SPHERE);
|
||||
|
||||
|
||||
@ -77,6 +77,40 @@ bool impl::rayAabb( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQ
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool impl::rayObb( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit ) {
|
||||
auto tA = impl::getTransform( body );
|
||||
|
||||
pod::Ray localRay;
|
||||
localRay.origin = uf::transform::applyInverse( tA, ray.origin );
|
||||
localRay.direction = uf::quaternion::rotate( uf::quaternion::inverse(tA.orientation), ray.direction );
|
||||
|
||||
pod::AABB localBox = { body.collider.obb.min, body.collider.obb.max };
|
||||
|
||||
float tMin, tMax;
|
||||
if ( !impl::rayAabbIntersect( localRay, localBox, tMin, tMax ) ) return false;
|
||||
|
||||
if ( tMin < rayHit.contact.penetration ) {
|
||||
rayHit.hit = true;
|
||||
rayHit.body = &body;
|
||||
rayHit.contact.penetration = tMin;
|
||||
|
||||
rayHit.contact.point = ray.origin + ray.direction * tMin;
|
||||
|
||||
auto localPoint = localRay.origin + localRay.direction * tMin;
|
||||
auto center = (localBox.max + localBox.min) * 0.5f;
|
||||
auto extents = (localBox.max - localBox.min) * 0.5f;
|
||||
auto localDelta = localPoint - center;
|
||||
auto absDelta = pod::Vector3f{ std::fabs(localDelta.x) / extents.x, std::fabs(localDelta.y) / extents.y, std::fabs(localDelta.z) / extents.z };
|
||||
|
||||
pod::Vector3f localNormal = {0,0,0};
|
||||
if ( absDelta.x > absDelta.y && absDelta.x > absDelta.z ) localNormal.x = localDelta.x > 0 ? 1.0f : -1.0f;
|
||||
else if ( absDelta.y > absDelta.z ) localNormal.y = localDelta.y > 0 ? 1.0f : -1.0f;
|
||||
else localNormal.z = localDelta.z > 0 ? 1.0f : -1.0f;
|
||||
|
||||
rayHit.contact.normal = uf::quaternion::rotate( tA.orientation, localNormal );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool impl::raySphere( const pod::Ray& ray, const pod::PhysicsBody& body, pod::RayQuery& rayHit ) {
|
||||
auto center = impl::getPosition(body);
|
||||
float r = body.collider.sphere.radius;
|
||||
|
||||
@ -46,6 +46,10 @@ bool impl::sphereAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod
|
||||
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
|
||||
return true;
|
||||
}
|
||||
bool impl::sphereObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( SPHERE, OBB );
|
||||
REVERSE_COLLIDER( a, b, impl::obbSphere );
|
||||
}
|
||||
bool impl::spherePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( SPHERE, PLANE );
|
||||
REVERSE_COLLIDER( a, b, impl::planeSphere );
|
||||
|
||||
@ -153,6 +153,77 @@ bool impl::triangleAabb( const pod::TriangleWithNormal& tri, const pod::PhysicsB
|
||||
manifold.points.emplace_back( pod::Contact{ contact, bestAxis, minOverlap } );
|
||||
return true;
|
||||
}
|
||||
bool impl::triangleObb( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold ) {
|
||||
auto tB = impl::getTransform( body );
|
||||
|
||||
pod::Vector3f cB = uf::transform::apply( tB, (body.collider.obb.max + body.collider.obb.min) * 0.5f );
|
||||
pod::Vector3f eB = (body.collider.obb.max - body.collider.obb.min) * 0.5f;
|
||||
pod::Vector3f axesB[3] = {
|
||||
uf::quaternion::rotate(tB.orientation, pod::Vector3f{1,0,0}),
|
||||
uf::quaternion::rotate(tB.orientation, pod::Vector3f{0,1,0}),
|
||||
uf::quaternion::rotate(tB.orientation, pod::Vector3f{0,0,1})
|
||||
};
|
||||
|
||||
pod::Vector3f v0 = tri.points[0];
|
||||
pod::Vector3f v1 = tri.points[1];
|
||||
pod::Vector3f v2 = tri.points[2];
|
||||
|
||||
pod::Vector3f e0 = v1 - v0;
|
||||
pod::Vector3f e1 = v2 - v1;
|
||||
pod::Vector3f e2 = v0 - v2;
|
||||
pod::Vector3f edges[3] = { e0, e1, e2 };
|
||||
|
||||
pod::Vector3f triNormal = tri.normal;
|
||||
|
||||
float minOverlap = FLT_MAX;
|
||||
pod::Vector3f bestAxis;
|
||||
|
||||
auto testAxis = [&](const pod::Vector3f& axis) -> bool {
|
||||
float mag = uf::vector::magnitude(axis);
|
||||
if (mag < EPS) return true; // degenerate
|
||||
pod::Vector3f n = axis / mag;
|
||||
|
||||
float p0 = uf::vector::dot(v0, n);
|
||||
float p1 = uf::vector::dot(v1, n);
|
||||
float p2 = uf::vector::dot(v2, n);
|
||||
float minT = std::min({p0, p1, p2});
|
||||
float maxT = std::max({p0, p1, p2});
|
||||
|
||||
float pB = uf::vector::dot(cB, n);
|
||||
float rB = eB.x * std::fabs(uf::vector::dot(axesB[0], n)) +
|
||||
eB.y * std::fabs(uf::vector::dot(axesB[1], n)) +
|
||||
eB.z * std::fabs(uf::vector::dot(axesB[2], n));
|
||||
float minB = pB - rB;
|
||||
float maxB = pB + rB;
|
||||
|
||||
if ( minT > maxB || maxT < minB ) return false;
|
||||
|
||||
float overlap = std::min(maxT, maxB) - std::max(minT, minB);
|
||||
if ( overlap < minOverlap ) {
|
||||
minOverlap = overlap;
|
||||
bestAxis = n;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if ( !testAxis(triNormal) ) return false;
|
||||
for ( auto i = 0; i < 3; ++i ) if ( !testAxis(axesB[i]) ) return false;;
|
||||
for ( auto i = 0; i < 3; ++i ) {
|
||||
for ( auto j = 0; j < 3; j++ ) if ( !testAxis(uf::vector::cross(edges[i], axesB[j])) ) return false;
|
||||
};
|
||||
|
||||
pod::Vector3f triCenter = (v0 + v1 + v2) / 3.0f;
|
||||
if ( uf::vector::dot(bestAxis, cB - triCenter) < 0.0f ) bestAxis = -bestAxis;
|
||||
|
||||
float rB = eB.x * std::fabs(uf::vector::dot(axesB[0], bestAxis)) +
|
||||
eB.y * std::fabs(uf::vector::dot(axesB[1], bestAxis)) +
|
||||
eB.z * std::fabs(uf::vector::dot(axesB[2], bestAxis));
|
||||
|
||||
pod::Vector3f contact = cB - bestAxis * rB;
|
||||
|
||||
manifold.points.emplace_back( pod::Contact{ contact, bestAxis, minOverlap } );
|
||||
return true;
|
||||
}
|
||||
bool impl::triangleSphere( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold ) {
|
||||
const auto& sphere = body;
|
||||
|
||||
@ -274,6 +345,10 @@ bool impl::triangleAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, p
|
||||
ASSERT_COLLIDER_TYPES( TRIANGLE, AABB );
|
||||
return impl::triangleAabb( a.collider.triangle, b, manifold );
|
||||
}
|
||||
bool impl::triangleObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( TRIANGLE, OBB );
|
||||
return impl::triangleObb( a.collider.triangle, b, manifold );
|
||||
}
|
||||
bool impl::triangleSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( TRIANGLE, SPHERE );
|
||||
return impl::triangleSphere( a.collider.triangle, b, manifold );
|
||||
|
||||
@ -37,17 +37,28 @@ void impl::blockPGSSolver( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifo
|
||||
cc.bias = restitutionBias + penetrationBias;
|
||||
|
||||
// effective mass (normal)
|
||||
pod::Matrix3f invIa = impl::computeWorldInverseInertia( a );
|
||||
pod::Matrix3f invIb = impl::computeWorldInverseInertia( b );
|
||||
|
||||
pod::Vector3f rnA = uf::vector::cross( cc.rA, cc.normal );
|
||||
pod::Vector3f rnB = uf::vector::cross( cc.rB, cc.normal );
|
||||
|
||||
pod::Vector3f I_rnA = uf::matrix::multiply( invIa, rnA );
|
||||
pod::Vector3f I_rnB = uf::matrix::multiply( invIb, rnB );
|
||||
|
||||
float Kn = (a.isStatic ? 0.0f : a.inverseMass) + (b.isStatic ? 0.0f : b.inverseMass) +
|
||||
uf::vector::dot( uf::vector::cross( rnA * a.inverseInertiaTensor, cc.rA ) + uf::vector::cross( rnB * b.inverseInertiaTensor, cc.rB ), cc.normal );
|
||||
uf::vector::dot( uf::vector::cross( I_rnA, cc.rA ) + uf::vector::cross( I_rnB, cc.rB ), cc.normal );
|
||||
cc.effectiveMassN = (Kn > 0.0f) ? 1.0f / Kn : 0.0f;
|
||||
|
||||
// effective mass (tangent)
|
||||
pod::Vector3f rtA = uf::vector::cross( cc.rA, cc.tangent );
|
||||
pod::Vector3f rtB = uf::vector::cross( cc.rB, cc.tangent );
|
||||
|
||||
pod::Vector3f I_rtA = uf::matrix::multiply( invIa, rtA );
|
||||
pod::Vector3f I_rtB = uf::matrix::multiply( invIb, rtB );
|
||||
|
||||
float Kt = (a.isStatic ? 0.0f : a.inverseMass) + (b.isStatic ? 0.0f : b.inverseMass) +
|
||||
uf::vector::dot( uf::vector::cross( rtA * a.inverseInertiaTensor, cc.rA ) + uf::vector::cross( rtB * b.inverseInertiaTensor, cc.rB ), cc.tangent );
|
||||
uf::vector::dot( uf::vector::cross( I_rtA, cc.rA ) + uf::vector::cross( I_rtB, cc.rB ), cc.tangent );
|
||||
cc.effectiveMassT = ( Kt > 0.0f ) ? ( 1.0f / Kt ) : 0.0f;
|
||||
|
||||
// warm start
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
#define PHYSICS_STEP(time) for ( int i = 0; i < time * FRAMERATE; i++ ) uf::physics::step(world, INV_FRAMERATE);
|
||||
|
||||
namespace {
|
||||
namespace impl {
|
||||
uf::Mesh generateMesh( float size = 1 ) {
|
||||
uf::Mesh mesh;
|
||||
mesh.bind<pod::Vertex_3F2F, uint16_t>();
|
||||
@ -43,7 +43,7 @@ TEST(SphereSphere_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = sphereSphere(bodyA, bodyB, m);
|
||||
bool collided = impl::sphereSphere(bodyA, bodyB, m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
EXPECT_NEAR(m.points[0].penetration, 0.5f, EPS);
|
||||
@ -64,7 +64,7 @@ TEST(AabbAabb_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = aabbAabb(bodyA, bodyB, m);
|
||||
bool collided = impl::aabbAabb(bodyA, bodyB, m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
})
|
||||
@ -98,7 +98,7 @@ TEST(SphereSphere_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = sphereSphere(bodyA, bodyB, m);
|
||||
bool collided = impl::sphereSphere(bodyA, bodyB, m);
|
||||
EXPECT_TRUE(!collided);
|
||||
})
|
||||
|
||||
@ -116,7 +116,7 @@ TEST(SphereAabb_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = sphereAabb(bodyA, bodyB, m);
|
||||
bool collided = impl::sphereAabb(bodyA, bodyB, m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
EXPECT_TRUE(m.points[0].penetration > 0.0f);
|
||||
@ -136,7 +136,7 @@ TEST(SpherePlane_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = planeSphere(bodyB, bodyA, m);
|
||||
bool collided = impl::planeSphere(bodyB, bodyA, m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
EXPECT_NEAR(m.points[0].penetration, 0.5f, EPS);
|
||||
@ -154,7 +154,7 @@ TEST(SpherePlane_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = planeSphere(bodyB, bodyA, m);
|
||||
bool collided = impl::planeSphere(bodyB, bodyA, m);
|
||||
EXPECT_TRUE(!collided);
|
||||
})
|
||||
|
||||
@ -171,7 +171,7 @@ TEST(CapsuleCapsule_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = capsuleCapsule(bodyA, bodyB, m);
|
||||
bool collided = impl::capsuleCapsule(bodyA, bodyB, m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
EXPECT_TRUE(m.points[0].penetration > 0.0f);
|
||||
@ -306,7 +306,7 @@ TEST(SphereSphere_TouchingButNotOverlapping, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = sphereSphere(bodyA, bodyB, m);
|
||||
bool collided = impl::sphereSphere(bodyA, bodyB, m);
|
||||
|
||||
EXPECT_TRUE(collided); // should count as a collision
|
||||
EXPECT_NEAR(m.points[0].penetration, 0.0f, EPS);
|
||||
@ -516,7 +516,7 @@ TEST(CapsulePlane_ContactNormal, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = capsulePlane(bodyA, bodyB, m);
|
||||
bool collided = impl::capsulePlane(bodyA, bodyB, m);
|
||||
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
@ -556,7 +556,7 @@ TEST(CapsuleSphere_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = capsuleSphere(bodyA, bodyB, m);
|
||||
bool collided = impl::capsuleSphere(bodyA, bodyB, m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
})
|
||||
@ -574,7 +574,7 @@ TEST(CapsuleSphere_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = capsuleSphere(bodyA, bodyB, m);
|
||||
bool collided = impl::capsuleSphere(bodyA, bodyB, m);
|
||||
EXPECT_TRUE(!collided);
|
||||
})
|
||||
|
||||
@ -592,7 +592,7 @@ TEST(AabbSphere_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = aabbSphere( bodyA, bodyB, m );
|
||||
bool collided = impl::aabbSphere( bodyA, bodyB, m );
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
})
|
||||
@ -610,7 +610,7 @@ TEST(AabbSphere_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = aabbSphere(bodyA,bodyB,m);
|
||||
bool collided = impl::aabbSphere(bodyA,bodyB,m);
|
||||
EXPECT_TRUE(!collided);
|
||||
})
|
||||
|
||||
@ -627,7 +627,7 @@ TEST(AabbPlane_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = aabbPlane(bodyA,bodyB,m);
|
||||
bool collided = impl::aabbPlane(bodyA,bodyB,m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
})
|
||||
@ -644,7 +644,7 @@ TEST(AabbPlane_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = aabbPlane(bodyA,bodyB,m);
|
||||
bool collided = impl::aabbPlane(bodyA,bodyB,m);
|
||||
EXPECT_TRUE(!collided);
|
||||
})
|
||||
|
||||
@ -662,7 +662,7 @@ TEST(AabbCapsule_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = aabbCapsule(bodyA,bodyB,m);
|
||||
bool collided = impl::aabbCapsule(bodyA,bodyB,m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
})
|
||||
@ -680,7 +680,7 @@ TEST(AabbCapsule_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = aabbCapsule(bodyA,bodyB,m);
|
||||
bool collided = impl::aabbCapsule(bodyA,bodyB,m);
|
||||
EXPECT_TRUE(!collided);
|
||||
})
|
||||
|
||||
@ -698,7 +698,7 @@ TEST(SphereCapsule_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = sphereCapsule(bodyA,bodyB,m);
|
||||
bool collided = impl::sphereCapsule(bodyA,bodyB,m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
})
|
||||
@ -716,7 +716,7 @@ TEST(SphereCapsule_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = sphereCapsule(bodyA,bodyB,m);
|
||||
bool collided = impl::sphereCapsule(bodyA,bodyB,m);
|
||||
EXPECT_TRUE(!collided);
|
||||
})
|
||||
|
||||
@ -730,7 +730,7 @@ TEST(PlanePlane_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = planePlane(bodyA,bodyB,m);
|
||||
bool collided = impl::planePlane(bodyA,bodyB,m);
|
||||
EXPECT_TRUE(!collided); // always false in your engine
|
||||
})
|
||||
|
||||
@ -747,7 +747,7 @@ TEST(PlaneCapsule_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = planeCapsule(bodyA,bodyB,m);
|
||||
bool collided = impl::planeCapsule(bodyA,bodyB,m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
})
|
||||
@ -764,7 +764,7 @@ TEST(PlaneCapsule_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = planeCapsule(bodyA,bodyB,m);
|
||||
bool collided = impl::planeCapsule(bodyA,bodyB,m);
|
||||
EXPECT_TRUE(!collided);
|
||||
})
|
||||
TEST(MeshSphere_Collision, {
|
||||
@ -784,7 +784,7 @@ TEST(MeshSphere_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = meshSphere(bodyA, bodyB, m);
|
||||
bool collided = impl::meshSphere(bodyA, bodyB, m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
if ( !m.points.empty() ) EXPECT_TRUE(m.points[0].penetration > 0.0f);
|
||||
@ -805,7 +805,7 @@ TEST(MeshSphere_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = meshSphere(bodyA, bodyB, m);
|
||||
bool collided = impl::meshSphere(bodyA, bodyB, m);
|
||||
EXPECT_FALSE(collided);
|
||||
})
|
||||
|
||||
@ -825,7 +825,7 @@ TEST(MeshAabb_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = meshAabb(bodyA, bodyB, m);
|
||||
bool collided = impl::meshAabb(bodyA, bodyB, m);
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_TRUE(!m.points.empty());
|
||||
})
|
||||
@ -846,7 +846,7 @@ TEST(MeshAabb_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = meshAabb(bodyA, bodyB, m);
|
||||
bool collided = impl::meshAabb(bodyA, bodyB, m);
|
||||
EXPECT_FALSE(collided);
|
||||
})
|
||||
|
||||
@ -899,7 +899,7 @@ TEST(MeshMesh_Collision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = meshMesh(bodyA, bodyB, m);
|
||||
bool collided = impl::meshMesh(bodyA, bodyB, m);
|
||||
EXPECT_TRUE(collided);
|
||||
})
|
||||
|
||||
@ -919,7 +919,7 @@ TEST(MeshMesh_NoCollision, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = meshMesh(bodyA, bodyB, m);
|
||||
bool collided = impl::meshMesh(bodyA, bodyB, m);
|
||||
EXPECT_FALSE(collided);
|
||||
})
|
||||
|
||||
@ -945,7 +945,7 @@ TEST(TriangleTriangle_Collision_SimpleOverlap, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::triangleTriangle(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::triangleTriangle(bodyA, bodyB, m);
|
||||
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_FALSE(m.points.empty());
|
||||
@ -977,7 +977,7 @@ TEST(TriangleTriangle_Collision_CoplanarOverlap, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::triangleTriangle(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::triangleTriangle(bodyA, bodyB, m);
|
||||
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_FALSE(m.points.empty());
|
||||
@ -1005,7 +1005,7 @@ TEST(TriangleTriangle_Collision_TouchingEdge, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::triangleTriangle(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::triangleTriangle(bodyA, bodyB, m);
|
||||
|
||||
// Should still report as collision (tangent contact)
|
||||
EXPECT_TRUE(collided);
|
||||
@ -1034,7 +1034,7 @@ TEST(TriangleAabb_Collision_OverlapCenter, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::triangleAabb(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::triangleAabb(bodyA, bodyB, m);
|
||||
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_FALSE(m.points.empty());
|
||||
@ -1062,7 +1062,7 @@ TEST(TriangleAabb_Collision_NoOverlap, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::triangleAabb(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::triangleAabb(bodyA, bodyB, m);
|
||||
EXPECT_FALSE(collided);
|
||||
})
|
||||
|
||||
@ -1086,7 +1086,7 @@ TEST(TrianglePlane_Collision_BelowPlane, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::trianglePlane(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::trianglePlane(bodyA, bodyB, m);
|
||||
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_FALSE(m.points.empty());
|
||||
@ -1114,7 +1114,7 @@ TEST(TrianglePlane_NoCollision_AbovePlane, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::trianglePlane(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::trianglePlane(bodyA, bodyB, m);
|
||||
EXPECT_FALSE(collided);
|
||||
})
|
||||
|
||||
@ -1138,7 +1138,7 @@ TEST(TriangleSphere_Collision_Tangent, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::triangleSphere(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::triangleSphere(bodyA, bodyB, m);
|
||||
|
||||
// At tangency: considered collision
|
||||
EXPECT_TRUE(collided);
|
||||
@ -1171,7 +1171,7 @@ TEST(TriangleCapsule_Collision_Overlap, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::triangleCapsule(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::triangleCapsule(bodyA, bodyB, m);
|
||||
|
||||
EXPECT_TRUE(collided);
|
||||
EXPECT_FALSE(m.points.empty());
|
||||
@ -1202,7 +1202,7 @@ TEST(TriangleCapsule_Collision_NoOverlap, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::triangleCapsule(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::triangleCapsule(bodyA, bodyB, m);
|
||||
EXPECT_FALSE(collided);
|
||||
})
|
||||
|
||||
@ -1228,7 +1228,7 @@ TEST(TriangleCapsule_Collision_Tangent, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::triangleCapsule(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::triangleCapsule(bodyA, bodyB, m);
|
||||
|
||||
// At tangency, should still count as collision (penetration ≈ 0)
|
||||
EXPECT_TRUE(collided);
|
||||
@ -1261,7 +1261,7 @@ TEST(TriangleCapsule_Collision_EdgeAlignment, {
|
||||
bodyB.bounds = impl::computeAABB( bodyB );
|
||||
|
||||
pod::Manifold m;
|
||||
bool collided = impl::triangleCapsule(bodyA, bodyB, m, EPS);
|
||||
bool collided = impl::triangleCapsule(bodyA, bodyB, m);
|
||||
|
||||
EXPECT_TRUE(collided);
|
||||
})
|
||||
@ -1,5 +1,5 @@
|
||||
FLAGS += -DUF_ENV_DREAMCAST
|
||||
REQ_DEPS += opengl gldc json:nlohmann zlib lua r:eactphysics simd ctti fmt freetype openal aldc ogg wav png
|
||||
REQ_DEPS += opengl gldc json:nlohmann zlib lua simd ctti fmt freetype openal aldc ogg wav png
|
||||
|
||||
INCS := -I./dep/dreamcast/include $(INCS)
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ ifneq (,$(findstring -DUF_DEV_ENV,$(FLAGS)))
|
||||
FLAGS += -march=native -g # -flto # -g
|
||||
endif
|
||||
|
||||
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit r:eactphysics simd ctti gltf imgui fmt freetype openal ogg wav
|
||||
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit 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)
|
||||
|
||||
@ -3,7 +3,7 @@ ifneq (,$(findstring -DUF_DEV_ENV,$(FLAGS)))
|
||||
FLAGS += -march=native -g # -flto # -g
|
||||
endif
|
||||
|
||||
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit r:eactphysics simd ctti gltf imgui fmt freetype openal ogg wav
|
||||
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit 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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user