Compare commits
3 Commits
07f2a7d17b
...
a1f62ef0c3
| Author | SHA1 | Date | |
|---|---|---|---|
| a1f62ef0c3 | |||
| 6b07173804 | |||
| 142f584684 |
@ -8,7 +8,7 @@
|
||||
"useLightmaps": false,
|
||||
"max": 32,
|
||||
"shadows": {
|
||||
"enabled": true,
|
||||
"enabled": false,
|
||||
"update": 4,
|
||||
"max": 16,
|
||||
"samples": 2
|
||||
@ -110,18 +110,18 @@
|
||||
"invariant": {
|
||||
"default stage buffers": true,
|
||||
"default defer buffer destroy": true,
|
||||
"default command buffer immediate": false,
|
||||
"default command buffer immediate": true,
|
||||
"n-buffered uniform": false,
|
||||
"multithreaded recording": true
|
||||
},
|
||||
"pipelines": {
|
||||
"deferred": true,
|
||||
"gui": true,
|
||||
"vsync": true, // vsync on vulkan side rather than engine-side
|
||||
"vsync": false, // vsync on vulkan side rather than engine-side
|
||||
"hdr": true,
|
||||
"vxgi": true, // to-do: fix issues
|
||||
"vxgi": false, // to-do: fix issues
|
||||
"culling": false,
|
||||
"bloom": true,
|
||||
"bloom": false,
|
||||
"dof": false,
|
||||
"rt": false,
|
||||
"fsr": false,
|
||||
@ -335,6 +335,17 @@
|
||||
"ultralight": { "enabled": true, "scale": 1.5 },
|
||||
"discord": { "enabled": false }
|
||||
},
|
||||
"physics": {
|
||||
"warmup solver": false,
|
||||
"block solver": true,
|
||||
"psg solver": true,
|
||||
"correction percent": 0.0,
|
||||
"gjk": false,
|
||||
"debug draw": false,
|
||||
"fixed step": true,
|
||||
"substeps": 4,
|
||||
"solver iterations": 10
|
||||
},
|
||||
"audio": {
|
||||
"mute": false,
|
||||
"async update": false,
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
"physics": {
|
||||
"mass": 0,
|
||||
"inertia": [0, 0, 0],
|
||||
"type": "mesh" // "bounding box"
|
||||
"type": "bounding box"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,10 +7,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
|
||||
|
||||
@ -99,12 +99,10 @@ ent:bind( "tick", function(self)
|
||||
local flattenedTransform = nil
|
||||
|
||||
if fixedCamera then
|
||||
flattenedTransform = transform:flatten()
|
||||
-- flattenedTransform.position.y = flattenedTransform.position.y
|
||||
else
|
||||
flattenedTransform = cameraTransform:flatten()
|
||||
end
|
||||
flattenedTransform.forward = ( transform.forward + Vector3f( 0, cameraTransform.forward.y, 0 ) ):normalize();
|
||||
flattenedTransform = transform:flatten()
|
||||
else
|
||||
flattenedTransform = cameraTransform:flatten()
|
||||
end
|
||||
|
||||
-- toggle flashlight
|
||||
if light.enabled then
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
[ 0, 0, 0, 0 ]
|
||||
],
|
||||
"shader": {
|
||||
"mode": 10,
|
||||
"mode": 0,
|
||||
"scalar": 16,
|
||||
"parameters": [ 0, 0, 0, "time" ]
|
||||
}
|
||||
|
||||
@ -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" } },
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
#version 450
|
||||
#pragma shader_stage(fragment)
|
||||
|
||||
layout (location = 0) in vec3 inPosition;
|
||||
layout (location = 1) in vec3 inColor;
|
||||
|
||||
layout (location = 0) out uvec2 outId;
|
||||
layout (location = 1) out vec2 outNormals;
|
||||
layout (location = 2) out vec4 outAlbedo;
|
||||
layout (location = 0) in vec4 inColor;
|
||||
layout (location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outAlbedo = vec4(inColor, 1);
|
||||
outColor = inColor;
|
||||
}
|
||||
@ -4,10 +4,10 @@
|
||||
#include "../../common/macros.h"
|
||||
#include "../../common/structs.h"
|
||||
|
||||
layout (constant_id = 0) const uint PASSES = 6;
|
||||
layout (constant_id = 0) const uint PASSES = 1;
|
||||
|
||||
layout (location = 0) in vec3 inPos;
|
||||
layout (location = 1) in vec3 inColor;
|
||||
layout (location = 1) in vec4 inColor;
|
||||
|
||||
layout( push_constant ) uniform PushBlock {
|
||||
uint pass;
|
||||
@ -18,12 +18,9 @@ layout (binding = 0) uniform Camera {
|
||||
Viewport viewport[PASSES];
|
||||
} camera;
|
||||
|
||||
layout (location = 0) out vec3 outPosition;
|
||||
layout (location = 1) out vec3 outColor;
|
||||
layout (location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outPosition = vec3(camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0));
|
||||
outColor = inColor;
|
||||
|
||||
gl_Position = camera.viewport[PushConstant.pass].projection * camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0);
|
||||
}
|
||||
@ -3,7 +3,6 @@
|
||||
// enable if shaderNonUniform is not supported
|
||||
// Nvidia hardware does not require nonuniformEXT, but AMD does
|
||||
#endif
|
||||
|
||||
// implicit variables
|
||||
#ifndef MULTISAMPLING
|
||||
#define MULTISAMPLING 1
|
||||
@ -20,8 +19,11 @@
|
||||
#ifndef MAX_SHADOWS
|
||||
#define MAX_SHADOWS ubo.settings.lighting.maxShadows
|
||||
#endif
|
||||
#ifndef USE_CAMERA_VIEWPORT
|
||||
#define USE_CAMERA_VIEWPORT 0
|
||||
#endif
|
||||
#ifndef VIEW_MATRIX
|
||||
#if VXGI
|
||||
#if VXGI || !USE_CAMERA_VIEWPORT
|
||||
#define VIEW_MATRIX ubo.eyes[surface.pass].view
|
||||
#else
|
||||
#define VIEW_MATRIX camera.viewport[surface.pass].view
|
||||
@ -80,7 +82,7 @@
|
||||
#endif
|
||||
#if BARYCENTRIC
|
||||
#ifndef BARYCENTRIC_CALCULATE
|
||||
#define BARYCENTRIC_CALCULATE 1
|
||||
#define BARYCENTRIC_CALCULATE 0
|
||||
#endif
|
||||
#ifndef BUFFER_REFERENCE
|
||||
#define BUFFER_REFERENCE 1
|
||||
|
||||
@ -199,10 +199,15 @@ void populateSurface() {
|
||||
{
|
||||
vec2 inUv = (vec2(gl_GlobalInvocationID.xy) / vec2(renderSize)) * 2.0f - 1.0f;
|
||||
|
||||
#if USE_CAMERA_VIEWPORT
|
||||
const mat4 iProjection = inverse( camera.viewport[surface.pass].projection );
|
||||
const mat4 iView = inverse( camera.viewport[surface.pass].view );
|
||||
const mat4 iProjectionView = inverse( camera.viewport[surface.pass].projection * mat4(mat3(camera.viewport[surface.pass].view)) );
|
||||
|
||||
const mat4 iProjectionView = /*iProjection * iView;*/ inverse( camera.viewport[surface.pass].projection * mat4(mat3(camera.viewport[surface.pass].view)) );
|
||||
#else
|
||||
const mat4 iView = ubo.eyes[surface.pass].iView;
|
||||
const mat4 iProjection = ubo.eyes[surface.pass].iProjection;
|
||||
const mat4 iProjectionView = /*iProjection * iView;*/ inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) );
|
||||
#endif
|
||||
const vec4 near4 = iProjectionView * (vec4(inUv, -1.0, 1.0));
|
||||
const vec4 far4 = iProjectionView * (vec4(inUv, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include <uf/ext/opengl/texture.h>
|
||||
#include <uf/ext/opengl/shader.h>
|
||||
#include <uf/utils/mesh/mesh.h>
|
||||
|
||||
#include <uf/utils/memory/unordered_map.h>
|
||||
#define UF_GRAPHIC_POINTERED_USERDATA 1
|
||||
|
||||
namespace ext {
|
||||
@ -103,6 +103,8 @@ namespace ext {
|
||||
void record( CommandBuffer& commandBuffer, size_t pass = 0, size_t draw = 0 ) const;
|
||||
void record( CommandBuffer& commandBuffer, const GraphicDescriptor& descriptor, size_t pass = 0, size_t draw = 0 ) const;
|
||||
};
|
||||
|
||||
typedef uf::stl::unordered_map<uf::stl::string, Graphic> Graphics;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <uf/ext/vulkan/texture.h>
|
||||
#include <uf/ext/vulkan/shader.h>
|
||||
#include <uf/utils/mesh/mesh.h>
|
||||
#include <uf/utils/memory/unordered_map.h>
|
||||
|
||||
namespace ext {
|
||||
namespace vulkan {
|
||||
@ -140,5 +141,7 @@ namespace ext {
|
||||
void record( VkCommandBuffer commandBuffer, const GraphicDescriptor& descriptor, size_t pass = 0, size_t draw = 0, size_t offset = 0 ) const;
|
||||
|
||||
};
|
||||
|
||||
typedef uf::stl::unordered_map<uf::stl::string, Graphic> Graphics;
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,9 @@
|
||||
|
||||
namespace ext {
|
||||
namespace vulkan {
|
||||
struct UF_API DeferredRenderMode : public ext::vulkan::RenderMode {
|
||||
struct UF_API DeferredRenderMode : public ext::vulkan::RenderMode {
|
||||
RenderTarget forwardRenderTarget;
|
||||
|
||||
virtual const uf::stl::string getType() const;
|
||||
|
||||
virtual GraphicDescriptor bindGraphicDescriptor( const GraphicDescriptor&, size_t = 0 );
|
||||
|
||||
@ -13,7 +13,7 @@ namespace ext {
|
||||
bool blend = false;
|
||||
uint8_t samples = 1;
|
||||
uint8_t mips = 0;
|
||||
bool screenshottable = true;
|
||||
bool screenshottable = false;
|
||||
bool aliased = false;
|
||||
|
||||
uint32_t width = 0;
|
||||
@ -57,6 +57,7 @@ namespace ext {
|
||||
void destroy();
|
||||
void addPass( VkPipelineStageFlags, VkAccessFlags, const uf::stl::vector<size_t>&, const uf::stl::vector<size_t>&, const uf::stl::vector<size_t>&, size_t, size_t = 0, bool = true );
|
||||
size_t attach( const Attachment::Descriptor& descriptor, Attachment* attachment = NULL );
|
||||
size_t aliasAttachment( const Attachment& attachment );
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -101,8 +101,8 @@
|
||||
#define TYPE_NAME(T) TYPE(T).name()
|
||||
#endif
|
||||
|
||||
#define MIN(X, Y) (X) < (Y) ? (X) : (Y)
|
||||
#define MAX(X, Y) (X) > (Y) ? (X) : (Y)
|
||||
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
||||
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
||||
#define CLAMP(X, LO, HI) MAX(LO, MIN(HI, X))
|
||||
#define LENGTH_OF(X) *(&X + 1) - X
|
||||
#define FOR_ARRAY(X) for ( auto i = 0; i < LENGTH_OF(X); ++i )
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "impl.h"
|
||||
#include "draw.h"
|
||||
|
||||
// to-do: organize this mess
|
||||
namespace impl {
|
||||
|
||||
19
engine/inc/uf/utils/math/physics/draw.h
Normal file
19
engine/inc/uf/utils/math/physics/draw.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "impl.h"
|
||||
|
||||
namespace impl {
|
||||
struct Vertex {
|
||||
pod::Vector3f position;
|
||||
pod::Vector4f color;
|
||||
|
||||
static uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
|
||||
};
|
||||
|
||||
/*FORCE_INLINE*/ void addLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color = { 1, 1, 1, 1 } );
|
||||
/*FORCE_INLINE*/ void addTransientLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color = { 1, 1, 1, 1 }, const pod::PhysicsBody* a = NULL, const pod::PhysicsBody* b = NULL );
|
||||
|
||||
void drawManifold( const pod::Manifold& manifold );
|
||||
void drawBody( const pod::PhysicsBody& body );
|
||||
void draw( const pod::World& world, float dt = 0 );
|
||||
}
|
||||
@ -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;
|
||||
@ -248,7 +243,8 @@ namespace pod {
|
||||
|
||||
struct RayQuery {
|
||||
bool hit = false;
|
||||
const pod::PhysicsBody* body;
|
||||
const pod::PhysicsBody* body = NULL;
|
||||
const pod::PhysicsBody* invoker = NULL;
|
||||
pod::Contact contact = { pod::Vector3f{}, pod::Vector3f{}, FLT_MAX };
|
||||
};
|
||||
|
||||
@ -256,14 +252,17 @@ namespace pod {
|
||||
bool awake = true;
|
||||
uf::stl::vector<uint32_t> indices;
|
||||
pod::BVH::pairs_t pairs;
|
||||
|
||||
uf::stl::vector<pod::Manifold> manifolds;
|
||||
};
|
||||
|
||||
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
|
||||
bool debugDraw = false; // draws wireframe of collision bodies
|
||||
uint32_t substeps = 4; // number of substeps per frame tick
|
||||
uint32_t reserveCount = 32; // amount of elements to reserve for vectors used in this system, to-do: have it tie to a memory pool allocator
|
||||
|
||||
@ -362,6 +361,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,9 +4,12 @@
|
||||
|
||||
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 );
|
||||
bool aabbMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool aabbHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
void drawAabb( const pod::PhysicsBody& body );
|
||||
}
|
||||
@ -3,10 +3,13 @@
|
||||
#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 );
|
||||
|
||||
void drawCapsule( const pod::PhysicsBody& body );
|
||||
}
|
||||
@ -4,9 +4,12 @@
|
||||
|
||||
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 );
|
||||
bool hullMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool hullHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
void drawHull( const pod::PhysicsBody& body );
|
||||
}
|
||||
@ -4,9 +4,12 @@
|
||||
|
||||
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 );
|
||||
bool meshMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool meshHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
void drawMesh( const pod::PhysicsBody& body );
|
||||
}
|
||||
15
engine/inc/uf/utils/math/physics/narrowphase/obb.h
Normal file
15
engine/inc/uf/utils/math/physics/narrowphase/obb.h
Normal file
@ -0,0 +1,15 @@
|
||||
#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 );
|
||||
|
||||
void drawObb( const pod::PhysicsBody& body );
|
||||
}
|
||||
@ -4,9 +4,12 @@
|
||||
|
||||
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 );
|
||||
bool planeMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
bool planeHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
void drawPlane( const pod::PhysicsBody& body );
|
||||
}
|
||||
@ -5,10 +5,14 @@
|
||||
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 );
|
||||
bool rayMesh( const pod::Ray& r, const pod::PhysicsBody& body, pod::RayQuery& rayHit );
|
||||
bool rayHull( const pod::Ray& r, const pod::PhysicsBody& body, pod::RayQuery& rayHit );
|
||||
|
||||
void drawRay( const pod::Ray& r, const pod::RayQuery& query );
|
||||
}
|
||||
@ -3,10 +3,13 @@
|
||||
#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 );
|
||||
bool sphereHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
void drawSphere( const pod::PhysicsBody& body );
|
||||
}
|
||||
@ -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,8 +13,11 @@ 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 );
|
||||
bool triangleHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold );
|
||||
|
||||
void drawTriangle( const pod::PhysicsBody& body );
|
||||
}
|
||||
@ -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,17 +95,9 @@ 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 * pointer->scale);
|
||||
combined.orientation = uf::quaternion::multiply( pointer->orientation, combined.orientation );
|
||||
combined.scale = {
|
||||
combined.scale.x * pointer->scale.x,
|
||||
combined.scale.y * pointer->scale.y,
|
||||
combined.scale.z * pointer->scale.z,
|
||||
};
|
||||
combined.scale = combined.scale * pointer->scale;
|
||||
combined.model = pointer->model * combined.model;
|
||||
|
||||
if ( pointer == pointer->reference ) break;
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include <uf/ext/json/json.h>
|
||||
#include <uf/utils/serialize/serializer.h>
|
||||
#include <uf/utils/math/angle.h>
|
||||
#include <uf/utils/math/hash.h>
|
||||
|
||||
#if UF_USE_BFLOAT16
|
||||
#include <stdfloat>
|
||||
|
||||
@ -743,7 +743,7 @@ template<typename T>
|
||||
size_t uf::vector::hash( const T& v ) {
|
||||
size_t hash = 0;
|
||||
FOR_EACH(T::size, {
|
||||
hash ^= v[i];
|
||||
uf::hash( hash, v[i] );
|
||||
});
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -110,152 +110,192 @@ 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& configEnginePhysicsJson = json["engine"]["physics"];
|
||||
uf::physics::settings.warmupSolver = configEnginePhysicsJson["warmup solver"].as(uf::physics::settings.warmupSolver);
|
||||
uf::physics::settings.blockContactSolver = configEnginePhysicsJson["block solver"].as(uf::physics::settings.blockContactSolver);
|
||||
uf::physics::settings.psgContactSolver = configEnginePhysicsJson["psg solver"].as(uf::physics::settings.psgContactSolver);
|
||||
uf::physics::settings.useGjk = configEnginePhysicsJson["gjk"].as(uf::physics::settings.useGjk);
|
||||
uf::physics::settings.debugDraw = configEnginePhysicsJson["debug draw"].as(uf::physics::settings.debugDraw);
|
||||
uf::physics::settings.fixedStep = configEnginePhysicsJson["fixed step"].as(uf::physics::settings.fixedStep);
|
||||
uf::physics::settings.substeps = configEnginePhysicsJson["substeps"].as(uf::physics::settings.substeps);
|
||||
uf::physics::settings.solverIterations = configEnginePhysicsJson["solver iterations"].as(uf::physics::settings.solverIterations);
|
||||
uf::physics::settings.baumgarteCorrectionPercent = configEnginePhysicsJson["correction percent"].as(uf::physics::settings.baumgarteCorrectionPercent);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
@ -134,12 +134,25 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
|
||||
auto type = metadataJsonPhysics["type"].as<uf::stl::string>();
|
||||
float mass = metadataJsonPhysics["mass"].as<float>();
|
||||
|
||||
bool recenter = metadataJsonPhysics["recenter"].as<bool>();
|
||||
pod::Vector3f offset = uf::vector::decode( metadataJsonPhysics["offset"], pod::Vector3f{} );
|
||||
|
||||
if ( offset == pod::Vector3f{} ) recenter = true;
|
||||
|
||||
if ( type == "bounding box" || type == "aabb" ) {
|
||||
pod::Vector3f min = uf::vector::decode( metadataJsonPhysics["min"], pod::Vector3f{-0.5f, -0.5f, -0.5f} );
|
||||
pod::Vector3f max = uf::vector::decode( metadataJsonPhysics["max"], pod::Vector3f{0.5f, 0.5f, 0.5f} );
|
||||
|
||||
// recenter
|
||||
if ( recenter ) {
|
||||
pod::Vector3f center = (max + min) * 0.5f;
|
||||
pod::Vector3f extents = (max - min) * 0.5f;
|
||||
|
||||
min = -extents;
|
||||
max = extents;
|
||||
offset = center;
|
||||
}
|
||||
|
||||
uf::physics::create( self, pod::AABB{ .min = min, .max = max }, mass, offset );
|
||||
} else if ( type == "plane" ) {
|
||||
pod::Vector3f direction = uf::vector::decode( metadataJsonPhysics["direction"], pod::Vector3f{} );
|
||||
|
||||
@ -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) ),
|
||||
|
||||
@ -381,11 +381,20 @@ void ext::opengl::tick(){
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& graph = scene.getGraph();
|
||||
for ( auto entity : graph ) {
|
||||
if ( !entity->hasComponent<uf::Graphic>() ) continue;
|
||||
ext::opengl::Graphic& graphic = entity->getComponent<uf::Graphic>();
|
||||
if ( graphic.initialized || !graphic.process || graphic.initialized ) continue;
|
||||
graphic.initializePipeline();
|
||||
ext::opengl::states::rebuild = true;
|
||||
if ( entity->hasComponent<ext::opengl::Graphics>() ) {
|
||||
auto& graphics = entity->getComponent<ext::opengl::Graphics>();
|
||||
for ( auto& [ _, graphic ] : graphics ) {
|
||||
if ( graphic.initialized || !graphic.process ) continue;
|
||||
graphic.initializePipeline();
|
||||
ext::opengl::states::rebuild = true;
|
||||
}
|
||||
}
|
||||
if ( entity->hasComponent<ext::opengl::Graphic>() ) {
|
||||
auto& graphic = entity->getComponent<ext::opengl::Graphic>();
|
||||
if ( graphic.initialized || !graphic.process ) continue;
|
||||
graphic.initializePipeline();
|
||||
ext::opengl::states::rebuild = true;
|
||||
}
|
||||
}
|
||||
for ( auto& renderMode : renderModes ) {
|
||||
if ( !renderMode ) continue;
|
||||
|
||||
@ -60,10 +60,18 @@ void ext::opengl::RenderMode::createCommandBuffers() {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto/*&*/ graph = scene.getGraph();
|
||||
for ( auto entity : graph ) {
|
||||
if ( !entity->hasComponent<uf::Graphic>() ) continue;
|
||||
ext::opengl::Graphic& graphic = entity->getComponent<uf::Graphic>();
|
||||
if ( !graphic.initialized || !graphic.process ) continue;
|
||||
graphics.push_back(&graphic);
|
||||
if ( entity->hasComponent<ext::opengl::Graphics>() ) {
|
||||
auto& g = entity->getComponent<ext::opengl::Graphics>();
|
||||
for ( auto& [ _, graphic ] : g ) {
|
||||
if ( !graphic.initialized || !graphic.process ) continue;
|
||||
graphics.emplace_back(&graphic);
|
||||
}
|
||||
}
|
||||
if ( entity->hasComponent<ext::opengl::Graphic>() ) {
|
||||
auto& graphic = entity->getComponent<ext::opengl::Graphic>();
|
||||
if ( !graphic.initialized || !graphic.process ) continue;
|
||||
graphics.emplace_back(&graphic);
|
||||
}
|
||||
}
|
||||
|
||||
this->synchronize();
|
||||
|
||||
@ -226,10 +226,18 @@ void ext::vulkan::RenderMode::createCommandBuffers() {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto/*&*/ graph = scene.getGraph();
|
||||
for ( auto entity : graph ) {
|
||||
if ( !entity->hasComponent<uf::Graphic>() ) continue;
|
||||
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
|
||||
if ( !graphic.initialized || !graphic.process ) continue;
|
||||
graphics.emplace_back(&graphic);
|
||||
if ( entity->hasComponent<ext::vulkan::Graphics>() ) {
|
||||
auto& g = entity->getComponent<ext::vulkan::Graphics>();
|
||||
for ( auto& [ _, graphic ] : g ) {
|
||||
if ( !graphic.initialized || !graphic.process ) continue;
|
||||
graphics.emplace_back(&graphic);
|
||||
}
|
||||
}
|
||||
if ( entity->hasComponent<ext::vulkan::Graphic>() ) {
|
||||
auto& graphic = entity->getComponent<ext::vulkan::Graphic>();
|
||||
if ( !graphic.initialized || !graphic.process ) continue;
|
||||
graphics.emplace_back(&graphic);
|
||||
}
|
||||
}
|
||||
|
||||
// this->synchronize();
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
#if BARYCENTRIC
|
||||
// 0 keeps a buffer for barycentric coordinates, 1 will reconstruct in the deferred pass
|
||||
#ifndef BARYCENTRIC_CALCULATE
|
||||
#define BARYCENTRIC_CALCULATE 1
|
||||
#define BARYCENTRIC_CALCULATE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -159,7 +159,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
/*.usage = */VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
|
||||
/*.blend = */false,
|
||||
/*.samples = */msaa,
|
||||
//*.mips = */1,
|
||||
/*.mips = */1,
|
||||
});
|
||||
// output buffers
|
||||
attachments.color = renderTarget.attach(RenderTarget::Attachment::Descriptor{
|
||||
@ -245,6 +245,39 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
// metadata.outputs.emplace_back(metadata.attachments["output"]);
|
||||
renderTarget.initialize( device );
|
||||
|
||||
// initialize forward+ renderTarget
|
||||
{
|
||||
forwardRenderTarget.device = &device;
|
||||
forwardRenderTarget.views = metadata.eyes;
|
||||
forwardRenderTarget.width = renderTarget.width;
|
||||
forwardRenderTarget.height = renderTarget.height;
|
||||
forwardRenderTarget.scale = renderTarget.scale;
|
||||
|
||||
size_t msaa = ext::vulkan::settings::msaa;
|
||||
|
||||
struct {
|
||||
size_t color, depth;
|
||||
} attachmentsPlus = {};
|
||||
|
||||
attachmentsPlus.color = forwardRenderTarget.aliasAttachment(this->getAttachment("color"));
|
||||
attachmentsPlus.depth = forwardRenderTarget.aliasAttachment(this->getAttachment("depth"));
|
||||
|
||||
metadata.attachments["color+"] = attachmentsPlus.color;
|
||||
metadata.attachments["depth+"] = attachmentsPlus.depth;
|
||||
|
||||
forwardRenderTarget.addPass(
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
{ attachmentsPlus.color },
|
||||
{},
|
||||
{},
|
||||
attachmentsPlus.depth,
|
||||
0,
|
||||
true
|
||||
);
|
||||
|
||||
forwardRenderTarget.initialize( device );
|
||||
}
|
||||
|
||||
{
|
||||
uf::Mesh mesh;
|
||||
mesh.vertex.count = 3;
|
||||
@ -599,7 +632,17 @@ void ext::vulkan::DeferredRenderMode::tick() {
|
||||
if ( resized ) {
|
||||
this->resized = false;
|
||||
rebuild = true;
|
||||
|
||||
renderTarget.initialize( *renderTarget.device );
|
||||
|
||||
|
||||
forwardRenderTarget.width = renderTarget.width;
|
||||
forwardRenderTarget.height = renderTarget.height;
|
||||
forwardRenderTarget.scale = renderTarget.scale;
|
||||
forwardRenderTarget.attachments.clear();
|
||||
forwardRenderTarget.aliasAttachment(this->getAttachment("color"));
|
||||
forwardRenderTarget.aliasAttachment(this->getAttachment("depth"));
|
||||
forwardRenderTarget.initialize( *forwardRenderTarget.device );
|
||||
}
|
||||
|
||||
// update blitter descriptor set
|
||||
@ -660,6 +703,8 @@ void ext::vulkan::DeferredRenderMode::render() {
|
||||
//unlockMutex( this->mostRecentCommandPoolId );
|
||||
}
|
||||
void ext::vulkan::DeferredRenderMode::destroy() {
|
||||
forwardRenderTarget.destroy();
|
||||
|
||||
// cleanup
|
||||
::postprocesses::depthPyramid.atomicCounter.destroy(false);
|
||||
::postprocesses::bloom.atomicCounter.destroy(false);
|
||||
@ -819,6 +864,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
for ( auto graphic : graphics ) {
|
||||
// only draw graphics that are assigned to this type of render mode
|
||||
if ( graphic->descriptor.renderMode != this->getName() ) continue;
|
||||
if ( graphic->descriptor.renderTarget != 0 /*this->getName()*/ ) continue;
|
||||
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, ::fmt::format("graphic[{}]", currentDraw) );
|
||||
graphic->record( commandBuffer, descriptor, 0, currentDraw++, frame );
|
||||
@ -875,6 +921,65 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
::transitionAttachmentsFrom( this, shader, commandBuffer );
|
||||
}
|
||||
|
||||
// forward+
|
||||
{
|
||||
{
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "forward:setImageLayout" );
|
||||
|
||||
// Transition Color
|
||||
VkImageSubresourceRange colorRange = {};
|
||||
colorRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
colorRange.baseMipLevel = 0;
|
||||
colorRange.levelCount = 1;
|
||||
colorRange.baseArrayLayer = 0;
|
||||
colorRange.layerCount = metadata.eyes; // Or this->views
|
||||
|
||||
uf::renderer::Texture::setImageLayout(
|
||||
commandBuffer,
|
||||
forwardRenderTarget.attachments[0].image,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
colorRange
|
||||
);
|
||||
|
||||
// Transition Depth
|
||||
VkImageSubresourceRange depthRange = colorRange;
|
||||
depthRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; // Depth aspect!
|
||||
|
||||
uf::renderer::Texture::setImageLayout(
|
||||
commandBuffer,
|
||||
forwardRenderTarget.attachments[1].image,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
depthRange
|
||||
);
|
||||
}
|
||||
|
||||
renderPassBeginInfo.clearValueCount = 0;
|
||||
renderPassBeginInfo.pClearValues = NULL;
|
||||
renderPassBeginInfo.renderPass = forwardRenderTarget.renderPass;
|
||||
renderPassBeginInfo.framebuffer = forwardRenderTarget.framebuffers[frame];
|
||||
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
// render to geometry buffers
|
||||
{
|
||||
size_t currentPass = 0;
|
||||
size_t currentDraw = 0;
|
||||
for ( auto graphic : graphics ) {
|
||||
// only draw graphics that are assigned to this type of render mode
|
||||
if ( graphic->descriptor.renderTarget != 1 /*"forward"*/ ) continue;
|
||||
//if ( graphic->descriptor.renderMode != this->getName() ) continue;
|
||||
//if ( graphic->descriptor.pipeline != "forward" ) continue;
|
||||
ext::vulkan::GraphicDescriptor descriptor = graphic->descriptor; // bindGraphicDescriptor(graphic->descriptor, currentSubpass);
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, ::fmt::format("graphic[{}]", currentDraw) );
|
||||
graphic->record( commandBuffer, descriptor, 0, currentDraw++, frame );
|
||||
}
|
||||
}
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
}
|
||||
|
||||
if ( settings::pipelines::bloom && blitter.material.hasShader("compute", "bloom-down") ) {
|
||||
auto& shader = blitter.material.getShader("compute", "bloom-down");
|
||||
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
|
||||
|
||||
@ -218,6 +218,34 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
|
||||
|
||||
return index;
|
||||
}
|
||||
size_t ext::vulkan::RenderTarget::aliasAttachment( const Attachment& source ) {
|
||||
if ( this->views == 0 ) this->views = source.views.size(); // Keep view count consistent
|
||||
|
||||
size_t index = attachments.size();
|
||||
auto& attachment = attachments.emplace_back();
|
||||
|
||||
// 1. Copy the descriptor and mark it as aliased!
|
||||
// This prevents RenderTarget::destroy from double-freeing the memory,
|
||||
// and prevents RenderTarget::initialize from trying to re-allocate it.
|
||||
attachment.descriptor = source.descriptor;
|
||||
attachment.descriptor.aliased = true;
|
||||
|
||||
// 2. Copy the Vulkan resource handles
|
||||
attachment.image = source.image;
|
||||
attachment.view = source.view;
|
||||
attachment.framebufferView = source.framebufferView;
|
||||
attachment.views = source.views; // Copy the vector of image views
|
||||
|
||||
// 3. Copy the pipeline states
|
||||
attachment.blendState = source.blendState;
|
||||
|
||||
// 4. Copy memory references (safe because aliased == true)
|
||||
attachment.mem = source.mem;
|
||||
attachment.allocation = source.allocation;
|
||||
attachment.allocationInfo = source.allocationInfo;
|
||||
|
||||
return index;
|
||||
}
|
||||
void ext::vulkan::RenderTarget::initialize( Device& device ) {
|
||||
// Bind
|
||||
this->device = &device;
|
||||
@ -254,6 +282,11 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
|
||||
description.finalLayout = ext::vulkan::Texture::remapRenderpassLayout( attachment.descriptor.layout );
|
||||
description.flags = 0;
|
||||
|
||||
if ( attachment.descriptor.aliased && !isSwapchain ) {
|
||||
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
description.initialLayout = attachment.descriptor.layout;
|
||||
}
|
||||
|
||||
attachments.emplace_back(description);
|
||||
}
|
||||
|
||||
@ -438,6 +471,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
|
||||
frameBufferCreateInfo.width = width;
|
||||
frameBufferCreateInfo.height = height;
|
||||
frameBufferCreateInfo.layers = 1;
|
||||
|
||||
// Create the framebuffer
|
||||
VK_CHECK_RESULT(vkCreateFramebuffer( device, &frameBufferCreateInfo, nullptr, &framebuffers[frame]));
|
||||
VK_REGISTER_HANDLE( framebuffers[frame] );
|
||||
|
||||
@ -520,9 +520,17 @@ void ext::vulkan::tick() {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto/*&*/ graph = scene.getGraph();
|
||||
for ( auto entity : graph ) {
|
||||
if ( entity->hasComponent<uf::Graphic>() ) {
|
||||
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
|
||||
if ( graphic.initialized || !graphic.process || graphic.initialized ) continue;
|
||||
if ( entity->hasComponent<ext::vulkan::Graphics>() ) {
|
||||
auto& graphics = entity->getComponent<ext::vulkan::Graphics>();
|
||||
for ( auto& [ _, graphic ] : graphics ) {
|
||||
if ( graphic.initialized || !graphic.process ) continue;
|
||||
graphic.update();
|
||||
ext::vulkan::states::rebuild = true;
|
||||
}
|
||||
}
|
||||
if ( entity->hasComponent<ext::vulkan::Graphic>() ) {
|
||||
auto& graphic = entity->getComponent<ext::vulkan::Graphic>();
|
||||
if ( graphic.initialized || !graphic.process ) continue;
|
||||
graphic.update();
|
||||
ext::vulkan::states::rebuild = true;
|
||||
}
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
#if UF_USE_UNUSED
|
||||
#include <uf/utils/math/collision.h>
|
||||
#include <uf/utils/math/collision/gjk.h>
|
||||
#include <uf/utils/math/collision/boundingbox.h>
|
||||
#include <uf/utils/math/collision/sphere.h>
|
||||
#include <uf/utils/math/collision/mesh.h>
|
||||
#include <uf/utils/math/collision/modular.h>
|
||||
#include <iostream>
|
||||
|
||||
uf::Collider::~Collider() {
|
||||
this->clear();
|
||||
}
|
||||
void uf::Collider::clear() {
|
||||
for ( pod::Collider* pointer : this->m_container ) delete pointer;
|
||||
this->m_container.clear();
|
||||
}
|
||||
|
||||
void uf::Collider::add( pod::Collider* pointer ) {
|
||||
this->m_container.push_back(pointer);
|
||||
}
|
||||
uf::Collider::container_t& uf::Collider::getContainer() {
|
||||
return this->m_container;
|
||||
}
|
||||
const uf::Collider::container_t& uf::Collider::getContainer() const {
|
||||
return this->m_container;
|
||||
}
|
||||
|
||||
std::size_t uf::Collider::getSize() const {
|
||||
return this->m_container.size();
|
||||
}
|
||||
|
||||
uf::stl::vector<pod::Collider::Manifold> uf::Collider::intersects( const uf::Collider& body, bool smart ) const {
|
||||
uf::stl::vector<pod::Collider::Manifold> manifolds;
|
||||
manifolds.reserve( this->m_container.size() * body.m_container.size() );
|
||||
for ( const pod::Collider* pointer : body.m_container ) {
|
||||
uf::stl::vector<pod::Collider::Manifold> result = this->intersects( *pointer, smart );
|
||||
manifolds.insert( manifolds.end(), result.begin(), result.end() );
|
||||
}
|
||||
return manifolds;
|
||||
}
|
||||
|
||||
uf::stl::vector<pod::Collider::Manifold> uf::Collider::intersects( const pod::Collider& body, bool smart ) const {
|
||||
// smart = false;
|
||||
uf::stl::vector<pod::Collider::Manifold> manifolds;
|
||||
for ( const pod::Collider* pointer : this->m_container ) {
|
||||
pod::Collider::Manifold& manifold = manifolds.emplace_back();
|
||||
if ( !pointer ) continue;
|
||||
if ( smart && pointer->type() == body.type() ) {
|
||||
if ( pointer->type() == "BoundingBox" ) {
|
||||
const uf::BoundingBox& a = *((const uf::BoundingBox*) pointer);
|
||||
const uf::BoundingBox& b = *((const uf::BoundingBox*) &body);
|
||||
manifold = a.intersects(b);
|
||||
} else if ( pointer->type() == "Sphere" ) {
|
||||
const uf::SphereCollider& a = *((const uf::SphereCollider*) pointer);
|
||||
const uf::SphereCollider& b = *((const uf::SphereCollider*) &body);
|
||||
manifold = a.intersects(b);
|
||||
}
|
||||
else
|
||||
manifold = pointer->intersects( body );
|
||||
} else manifold = pointer->intersects( body );
|
||||
}
|
||||
return manifolds;
|
||||
}
|
||||
#endif
|
||||
@ -1,5 +1,14 @@
|
||||
#include <uf/utils/math/physics/common.h>
|
||||
|
||||
namespace impl {
|
||||
void updateStaticBody( pod::PhysicsBody& body ) {
|
||||
if ( !body.isStatic ) return;
|
||||
|
||||
body.bounds = impl::computeAABB( body );
|
||||
if ( body.world ) body.world->staticBvh.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
// create ID from pointers
|
||||
uint64_t impl::makePairKey( const pod::PhysicsBody& a, const pod::PhysicsBody& b ) {
|
||||
uint64_t lhs = reinterpret_cast<uint64_t>(&a);
|
||||
@ -19,6 +28,7 @@ void impl::wakeBody( pod::PhysicsBody& body ) {
|
||||
}
|
||||
|
||||
body.activity.awake = true;
|
||||
if ( body.isStatic ) impl::updateStaticBody( body );
|
||||
}
|
||||
void impl::sleepBody( pod::PhysicsBody& body ) {
|
||||
bool wasAsleep = !body.activity.awake;
|
||||
@ -64,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;
|
||||
}
|
||||
@ -102,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
|
||||
@ -413,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;
|
||||
}
|
||||
|
||||
@ -537,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
|
||||
@ -717,12 +733,15 @@ 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: {
|
||||
// return impl::transformAabbToWorld( body.collider.aabb, *body.transform );
|
||||
case pod::ShapeType::AABB:
|
||||
case pod::ShapeType::OBB: {
|
||||
return impl::transformAabbToWorld( body.collider.aabb, transform );
|
||||
/*
|
||||
return {
|
||||
transform.position + body.collider.aabb.min,
|
||||
transform.position + body.collider.aabb.max,
|
||||
};
|
||||
*/
|
||||
} break;
|
||||
case pod::ShapeType::SPHERE: {
|
||||
return {
|
||||
@ -737,10 +756,7 @@ pod::AABB impl::computeAABB( const pod::PhysicsBody& body ) {
|
||||
case pod::ShapeType::MESH:
|
||||
case pod::ShapeType::CONVEX_HULL: {
|
||||
if ( body.collider.mesh.bvh && !body.collider.mesh.bvh->bounds.empty() )
|
||||
return {
|
||||
transform.position + body.collider.mesh.bvh->bounds[0].min,
|
||||
transform.position + body.collider.mesh.bvh->bounds[0].max,
|
||||
};
|
||||
return impl::transformAabbToWorld( body.collider.mesh.bvh->bounds[0], transform );
|
||||
const auto& meshData = *body.collider.mesh.mesh;
|
||||
pod::AABB bounds = { { FLT_MAX, FLT_MAX, FLT_MAX }, { -FLT_MAX, -FLT_MAX, -FLT_MAX } };
|
||||
for ( const auto& view : meshData.buffer_views ) impl::computeConvexHullAABB( view, view["position"], bounds );
|
||||
@ -808,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 );
|
||||
|
||||
141
engine/src/utils/math/physics/draw.cpp
Normal file
141
engine/src/utils/math/physics/draw.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
#include <uf/utils/math/physics/common.h>
|
||||
#include <uf/utils/math/physics/narrowphase.h>
|
||||
#include <uf/engine/scene/scene.h>
|
||||
#include <uf/engine/graph/graph.h>
|
||||
|
||||
namespace {
|
||||
// define a struct for a line because I hate hate hate tuple syntax
|
||||
struct Line {
|
||||
pod::Vector3f start = {};
|
||||
pod::Vector3f end = {};
|
||||
pod::Vector4f color = { 1, 1, 1, 1 };
|
||||
float ttl = 0;
|
||||
};
|
||||
|
||||
uf::stl::vector<impl::Vertex> lines;
|
||||
uf::stl::unordered_map<size_t, Line> transientLines;
|
||||
|
||||
size_t getHash( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color, const pod::PhysicsBody* a, const pod::PhysicsBody* b ) {
|
||||
size_t hash = 0;
|
||||
/*
|
||||
int qx = static_cast<int>(start.x * 10.0f);
|
||||
int qy = static_cast<int>(start.y * 10.0f);
|
||||
int qz = static_cast<int>(start.z * 10.0f);
|
||||
uf::hash(hash, a, b, qx, qy, qz);
|
||||
*/
|
||||
uf::hash(hash, start, end, color);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
UF_VERTEX_DESCRIPTOR(impl::Vertex,
|
||||
UF_VERTEX_DESCRIPTION(impl::Vertex, R32G32B32_SFLOAT, position)
|
||||
UF_VERTEX_DESCRIPTION(impl::Vertex, R32G32B32A32_SFLOAT, color)
|
||||
)
|
||||
|
||||
void impl::addLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color ) {
|
||||
::lines.emplace_back( impl::Vertex{ start, color } );
|
||||
::lines.emplace_back( impl::Vertex{ end, color } );
|
||||
}
|
||||
void impl::addTransientLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color, const pod::PhysicsBody* a, const pod::PhysicsBody* b ) {
|
||||
::transientLines[::getHash( start, end, color, a, b )] = Line{ start, end, color, 1.0f };
|
||||
}
|
||||
|
||||
void impl::drawManifold( const pod::Manifold& manifold ) {
|
||||
for ( auto& contact : manifold.points ) {
|
||||
auto& start = contact.point;
|
||||
auto end = contact.point + (contact.normal * MIN(contact.penetration, 0.1f));
|
||||
|
||||
impl::addTransientLine( start, end, pod::Vector4f{ 1, 0, 0, 1 }, manifold.a, manifold.b );
|
||||
}
|
||||
}
|
||||
void impl::drawBody( const pod::PhysicsBody& body ) {
|
||||
switch( body.collider.type ) {
|
||||
case pod::ShapeType::AABB:
|
||||
impl::drawAabb( body );
|
||||
break;
|
||||
case pod::ShapeType::OBB:
|
||||
impl::drawObb( body );
|
||||
break;
|
||||
case pod::ShapeType::SPHERE:
|
||||
impl::drawSphere( body );
|
||||
break;
|
||||
case pod::ShapeType::CAPSULE:
|
||||
impl::drawCapsule( body );
|
||||
break;
|
||||
case pod::ShapeType::PLANE:
|
||||
impl::drawPlane( body );
|
||||
break;
|
||||
case pod::ShapeType::TRIANGLE:
|
||||
impl::drawTriangle( body );
|
||||
break;
|
||||
case pod::ShapeType::MESH:
|
||||
impl::drawMesh( body );
|
||||
break;
|
||||
case pod::ShapeType::CONVEX_HULL:
|
||||
impl::drawHull( body );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void impl::draw( const pod::World& world, float dt ) {
|
||||
if ( world.bodies.empty() ) return;
|
||||
|
||||
::lines.clear();
|
||||
|
||||
for ( auto* body : world.bodies ) impl::drawBody( *body );
|
||||
for ( auto it = ::transientLines.begin(); it != ::transientLines.end(); ) {
|
||||
auto& line = it->second;
|
||||
|
||||
if ( line.ttl <= 0 ) it = ::transientLines.erase( it );
|
||||
else {
|
||||
impl::addLine( line.start, line.end, line.color * pod::Vector4f{ 1, 1, 1, line.ttl } );
|
||||
line.ttl -= dt;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ::lines.empty() ) return;
|
||||
|
||||
uf::Mesh mesh;
|
||||
mesh.bind<impl::Vertex>();
|
||||
mesh.insertVertices<impl::Vertex>(::lines);
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& graphics = scene.getComponent<uf::renderer::Graphics>();
|
||||
auto& graphic = graphics["physics"];
|
||||
if ( !graphic.initialized ) {
|
||||
graphic.device = &uf::renderer::device;
|
||||
graphic.material.device = &uf::renderer::device;
|
||||
|
||||
graphic.descriptor.depth.test = false;
|
||||
graphic.descriptor.depth.write = false;
|
||||
graphic.descriptor.renderTarget = 1; // "forward";
|
||||
graphic.descriptor.topology = uf::renderer::enums::PrimitiveTopology::LINE_LIST;
|
||||
graphic.descriptor.fill = uf::renderer::enums::PolygonMode::LINE;
|
||||
graphic.descriptor.lineWidth = 4;
|
||||
|
||||
uf::stl::string vertexShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/base/line/vert.spv");
|
||||
uf::stl::string fragmentShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/base/line/frag.spv");
|
||||
|
||||
graphic.material.metadata.autoInitializeUniformBuffers = false;
|
||||
graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX);
|
||||
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT);
|
||||
graphic.material.metadata.autoInitializeUniformBuffers = true;
|
||||
|
||||
auto& storage = uf::graph::globalStorage ? uf::graph::storage : scene.getComponent<pod::Graph::Storage>();
|
||||
|
||||
// vertex shader
|
||||
{
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
shader.aliasBuffer( storage.buffers.camera );
|
||||
}
|
||||
|
||||
graphic.initialize();
|
||||
graphic.initializeMesh( mesh );
|
||||
UF_MSG_DEBUG("Initialized graphic");
|
||||
} else {
|
||||
bool rebuild = graphic.updateMesh( mesh );
|
||||
if ( rebuild ) uf::renderer::states::rebuild = true;
|
||||
}
|
||||
}
|
||||
@ -68,6 +68,8 @@ void uf::physics::tick( pod::World& world, float dt ) {
|
||||
else uf::physics::step( world, uf::physics::timescale );
|
||||
accumulator -= uf::physics::timescale;
|
||||
}
|
||||
|
||||
if ( uf::physics::settings.debugDraw ) impl::draw( world, dt );
|
||||
}
|
||||
void uf::physics::terminate() {
|
||||
uf::physics::terminate( uf::scene::getCurrentScene() );
|
||||
@ -125,7 +127,7 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
}
|
||||
|
||||
// build islands from overlaps
|
||||
uf::stl::vector<pod::Island> islands;
|
||||
STATIC_THREAD_LOCAL(uf::stl::vector<pod::Island>, islands);
|
||||
impl::buildIslands( pairs, bodies, islands );
|
||||
|
||||
if ( uf::physics::settings.warmupSolver ) impl::prepareManifoldCache( uf::physics::settings.manifoldsCache, islands, bodies );
|
||||
@ -134,8 +136,8 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
//#pragma omp parallel for schedule(dynamic)
|
||||
auto tasks = uf::thread::schedule(true);
|
||||
for ( auto& island : islands ) tasks.queue([&]{
|
||||
STATIC_THREAD_LOCAL(uf::stl::vector<pod::Manifold>, manifolds);
|
||||
manifolds.reserve(uf::physics::settings.reserveCount);
|
||||
auto& manifolds = island.manifolds;
|
||||
manifolds.clear();
|
||||
|
||||
// sleeping island, skip (asleep islands shouldn't ever be in here)
|
||||
if ( !island.awake ) return;
|
||||
@ -193,7 +195,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 );
|
||||
@ -203,6 +205,14 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
|
||||
if ( uf::physics::settings.warmupSolver ) impl::pruneManifoldCache( uf::physics::settings.manifoldsCache );
|
||||
|
||||
if ( uf::physics::settings.debugDraw ) {
|
||||
for ( auto& island : islands ) {
|
||||
for ( auto& manifold : island.manifolds ) {
|
||||
impl::drawManifold( manifold );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto* b : bodies ) {
|
||||
if ( b->isStatic ) continue;
|
||||
impl::snapVelocity( *b, dt );
|
||||
@ -260,7 +270,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);
|
||||
@ -289,6 +300,13 @@ void uf::physics::updateInertia( pod::PhysicsBody& body ) {
|
||||
case pod::ShapeType::CONVEX_HULL: {
|
||||
const auto& bvh = *body.collider.mesh.bvh;
|
||||
|
||||
#if 1
|
||||
pod::Vector3f dims = (body.bounds.max - body.bounds.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);
|
||||
body.inertiaTensor = uf::vector::max( body.inertiaTensor, { EPS, EPS, EPS } );
|
||||
body.inverseInertiaTensor = 1.0f / body.inertiaTensor;
|
||||
#else
|
||||
pod::Matrix3f inertia = {};
|
||||
float totalVolume = 0.0f;
|
||||
|
||||
@ -337,6 +355,7 @@ void uf::physics::updateInertia( pod::PhysicsBody& body ) {
|
||||
body.inertiaTensor = { inertia(0,0), inertia(1,1), inertia(2,2) };
|
||||
body.inverseInertiaTensor = 1.0f / body.inertiaTensor;
|
||||
}
|
||||
#endif
|
||||
} break;
|
||||
// to-do: add others
|
||||
default: {
|
||||
@ -344,11 +363,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 +388,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,9 +469,11 @@ 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 );
|
||||
return body;
|
||||
}
|
||||
@ -531,6 +598,7 @@ pod::RayQuery uf::physics::rayCast( const pod::Ray& ray, const pod::World& world
|
||||
}
|
||||
pod::RayQuery uf::physics::rayCast( const pod::Ray& ray, const pod::World& world, const pod::PhysicsBody* body, float maxDistance ) {
|
||||
pod::RayQuery rayHit;
|
||||
rayHit.invoker = body;
|
||||
rayHit.contact.penetration = maxDistance;
|
||||
|
||||
auto& dynamicBvh = world.dynamicBvh;
|
||||
@ -548,6 +616,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;
|
||||
@ -555,6 +624,8 @@ pod::RayQuery uf::physics::rayCast( const pod::Ray& ray, const pod::World& world
|
||||
case pod::ShapeType::CONVEX_HULL: impl::rayHull( ray, *b, rayHit ); break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( uf::physics::settings.debugDraw ) impl::drawRay( ray, rayHit );
|
||||
|
||||
return rayHit;
|
||||
}
|
||||
|
||||
@ -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 );
|
||||
@ -72,4 +75,25 @@ bool impl::aabbMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
bool impl::aabbHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( AABB, CONVEX_HULL );
|
||||
REVERSE_COLLIDER( a, b, impl::hullAabb );
|
||||
}
|
||||
|
||||
void impl::drawAabb( const pod::PhysicsBody& body ) {
|
||||
auto& aabb = body.bounds;
|
||||
|
||||
pod::Vector3f corners[8] = {
|
||||
{aabb.min.x, aabb.min.y, aabb.min.z}, {aabb.max.x, aabb.min.y, aabb.min.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.min.z}, {aabb.min.x, aabb.max.y, aabb.min.z},
|
||||
{aabb.min.x, aabb.min.y, aabb.max.z}, {aabb.max.x, aabb.min.y, aabb.max.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.max.z}, {aabb.min.x, aabb.max.y, aabb.max.z}
|
||||
};
|
||||
|
||||
// bottom face
|
||||
impl::addLine( corners[0], corners[1] ); impl::addLine( corners[1], corners[2] );
|
||||
impl::addLine( corners[2], corners[3] ); impl::addLine( corners[3], corners[0] );
|
||||
// top face
|
||||
impl::addLine( corners[4], corners[5] ); impl::addLine( corners[5], corners[6] );
|
||||
impl::addLine( corners[6], corners[7] ); impl::addLine( corners[7], corners[4] );
|
||||
// vertical edges
|
||||
impl::addLine( corners[0], corners[4] ); impl::addLine( corners[1], corners[5] );
|
||||
impl::addLine( corners[2], corners[6] ); impl::addLine( corners[3], corners[7] );
|
||||
}
|
||||
@ -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;
|
||||
@ -99,4 +103,27 @@ bool impl::capsuleMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, po
|
||||
bool impl::capsuleHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( CAPSULE, CONVEX_HULL );
|
||||
REVERSE_COLLIDER( a, b, impl::hullCapsule );
|
||||
}
|
||||
|
||||
void impl::drawCapsule( const pod::PhysicsBody& body ) {
|
||||
float radius = body.collider.capsule.radius;
|
||||
auto transform = impl::getTransform(body);
|
||||
auto [p1, p2] = impl::getCapsuleSegment(body);
|
||||
|
||||
pod::Vector3f up = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0, 1, 0});
|
||||
pod::Vector3f right = uf::vector::normalize(impl::computeTangent(up));
|
||||
pod::Vector3f forward = uf::vector::cross(up, right);
|
||||
|
||||
pod::Vector3f rightOffset = right * radius;
|
||||
pod::Vector3f forwardOffset = forward * radius;
|
||||
|
||||
impl::addLine( p1 + rightOffset, p2 + rightOffset );
|
||||
impl::addLine( p1 - rightOffset, p2 - rightOffset );
|
||||
impl::addLine( p1 + forwardOffset, p2 + forwardOffset );
|
||||
impl::addLine( p1 - forwardOffset, p2 - forwardOffset );
|
||||
|
||||
impl::addLine( p1 + rightOffset, p1 - rightOffset );
|
||||
impl::addLine( p1 + forwardOffset, p1 - forwardOffset );
|
||||
impl::addLine( p2 + rightOffset, p2 - rightOffset );
|
||||
impl::addLine( p2 + forwardOffset, p2 - forwardOffset );
|
||||
}
|
||||
@ -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 );
|
||||
@ -76,4 +80,20 @@ bool impl::hullHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
hit = true;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
void impl::drawHull( const pod::PhysicsBody& body ) {
|
||||
const uf::Mesh* meshData = body.collider.convexHull.mesh;
|
||||
if ( !meshData ) return;
|
||||
|
||||
size_t totalTriangles = 0;
|
||||
for ( const auto& view : meshData->buffer_views ) totalTriangles += view.index.count / 3;
|
||||
|
||||
for ( size_t i = 0; i < totalTriangles; ++i ) {
|
||||
auto tri = impl::fetchTriangle(*meshData, i, body);
|
||||
|
||||
impl::addLine( tri.points[0], tri.points[1] );
|
||||
impl::addLine( tri.points[1], tri.points[2] );
|
||||
impl::addLine( tri.points[2], tri.points[0] );
|
||||
}
|
||||
}
|
||||
@ -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 );
|
||||
|
||||
@ -162,4 +185,20 @@ bool impl::meshHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
hit = true;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
void impl::drawMesh( const pod::PhysicsBody& body ) {
|
||||
const uf::Mesh* meshData = body.collider.mesh.mesh;
|
||||
if ( !meshData ) return;
|
||||
|
||||
size_t totalTriangles = 0;
|
||||
for ( const auto& view : meshData->buffer_views ) totalTriangles += view.index.count / 3;
|
||||
|
||||
for ( size_t i = 0; i < totalTriangles; ++i ) {
|
||||
auto tri = impl::fetchTriangle(*meshData, i, body);
|
||||
|
||||
impl::addLine( tri.points[0], tri.points[1] );
|
||||
impl::addLine( tri.points[1], tri.points[2] );
|
||||
impl::addLine( tri.points[2], tri.points[0] );
|
||||
}
|
||||
}
|
||||
302
engine/src/utils/math/physics/narrowphase/obb.cpp
Normal file
302
engine/src/utils/math/physics/narrowphase/obb.cpp
Normal file
@ -0,0 +1,302 @@
|
||||
#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 );
|
||||
}
|
||||
|
||||
void impl::drawObb( const pod::PhysicsBody& body ) {
|
||||
auto& aabb = body.collider.aabb;
|
||||
pod::Vector3f corners[8] = {
|
||||
{aabb.min.x, aabb.min.y, aabb.min.z}, {aabb.max.x, aabb.min.y, aabb.min.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.min.z}, {aabb.min.x, aabb.max.y, aabb.min.z},
|
||||
{aabb.min.x, aabb.min.y, aabb.max.z}, {aabb.max.x, aabb.min.y, aabb.max.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.max.z}, {aabb.min.x, aabb.max.y, aabb.max.z}
|
||||
};
|
||||
|
||||
auto transform = impl::getTransform(body);
|
||||
FOR_EACH( 8, {
|
||||
corners[i] = uf::transform::apply(transform, corners[i]);
|
||||
});
|
||||
|
||||
// bottom face
|
||||
impl::addLine( corners[0], corners[1] ); impl::addLine( corners[1], corners[2] );
|
||||
impl::addLine( corners[2], corners[3] ); impl::addLine( corners[3], corners[0] );
|
||||
// top face
|
||||
impl::addLine( corners[4], corners[5] ); impl::addLine( corners[5], corners[6] );
|
||||
impl::addLine( corners[6], corners[7] ); impl::addLine( corners[7], corners[4] );
|
||||
// vertical edges
|
||||
impl::addLine( corners[0], corners[4] ); impl::addLine( corners[1], corners[5] );
|
||||
impl::addLine( corners[2], corners[6] ); impl::addLine( corners[3], corners[7] );
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -59,4 +63,25 @@ bool impl::planeMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod:
|
||||
bool impl::planeHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( PLANE, CONVEX_HULL );
|
||||
REVERSE_COLLIDER( a, b, impl::hullPlane );
|
||||
}
|
||||
|
||||
void impl::drawPlane( const pod::PhysicsBody& body ) {
|
||||
auto transform = impl::getTransform(body);
|
||||
|
||||
pod::Vector3f right = uf::quaternion::rotate(transform.orientation, pod::Vector3f{1, 0, 0});
|
||||
pod::Vector3f forward = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0, 0, 1});
|
||||
|
||||
float size = 10.0f;
|
||||
pod::Vector3f p0 = transform.position + (right * size) + (forward * size);
|
||||
pod::Vector3f p1 = transform.position - (right * size) + (forward * size);
|
||||
pod::Vector3f p2 = transform.position - (right * size) - (forward * size);
|
||||
pod::Vector3f p3 = transform.position + (right * size) - (forward * size);
|
||||
|
||||
impl::addLine( p0, p1 );
|
||||
impl::addLine( p1, p2 );
|
||||
impl::addLine( p2, p3 );
|
||||
impl::addLine( p3, p0 );
|
||||
|
||||
impl::addLine( p0, p2 );
|
||||
impl::addLine( p1, p3 );
|
||||
}
|
||||
@ -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;
|
||||
@ -265,4 +299,11 @@ bool impl::rayHull( const pod::Ray& r, const pod::PhysicsBody& body, pod::RayQue
|
||||
}
|
||||
|
||||
return rayHit.hit;
|
||||
}
|
||||
|
||||
void impl::drawRay( const pod::Ray& ray, const pod::RayQuery& query ) {
|
||||
auto& start = ray.origin;
|
||||
auto end = ray.origin + ray.direction * query.contact.penetration;
|
||||
|
||||
impl::addTransientLine( start, end, query.hit ? pod::Vector4f{ 0, 1, 0, 1 } : pod::Vector4f{ 1, 0, 0, 1 }, query.invoker, query.body );
|
||||
}
|
||||
@ -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 );
|
||||
@ -61,4 +65,36 @@ bool impl::sphereMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod
|
||||
bool impl::sphereHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( SPHERE, CONVEX_HULL );
|
||||
REVERSE_COLLIDER( a, b, impl::hullSphere );
|
||||
}
|
||||
|
||||
void impl::drawSphere( const pod::PhysicsBody& body ) {
|
||||
float radius = body.collider.sphere.radius;
|
||||
auto transform = impl::getTransform(body);
|
||||
|
||||
const int segments = 16;
|
||||
const float PI = 3.14159265359f;
|
||||
const float angleIncrement = (2.0f * PI) / segments;
|
||||
|
||||
for ( auto i = 0; i < segments; ++i ) {
|
||||
float theta1 = i * angleIncrement;
|
||||
float theta2 = (i + 1) * angleIncrement;
|
||||
|
||||
float c1 = std::cos(theta1) * radius;
|
||||
float s1 = std::sin(theta1) * radius;
|
||||
float c2 = std::cos(theta2) * radius;
|
||||
float s2 = std::sin(theta2) * radius;
|
||||
|
||||
pod::Vector3f xy1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c1, s1, 0.0f});
|
||||
pod::Vector3f xy2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c2, s2, 0.0f});
|
||||
|
||||
pod::Vector3f xz1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c1, 0.0f, s1});
|
||||
pod::Vector3f xz2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c2, 0.0f, s2});
|
||||
|
||||
pod::Vector3f yz1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, c1, s1});
|
||||
pod::Vector3f yz2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, c2, s2});
|
||||
|
||||
impl::addLine( transform.position + xy1, transform.position + xy2 );
|
||||
impl::addLine( transform.position + xz1, transform.position + xz2 );
|
||||
impl::addLine( transform.position + yz1, transform.position + yz2 );
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,41 @@
|
||||
#include <uf/utils/math/physics/common.h>
|
||||
#include <uf/utils/math/physics/narrowphase.h>
|
||||
|
||||
namespace impl {
|
||||
bool triangleGeneric( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
const auto& tri = a;
|
||||
const auto& body = b;
|
||||
|
||||
pod::Simplex simplex;
|
||||
if ( !impl::gjk( tri, body, simplex ) ) return false;
|
||||
auto result = impl::epa( tri, body, simplex );
|
||||
if ( !impl::generateClippingManifold( tri, body, result, manifold ) ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool triangleGeneric( const pod::TriangleWithNormal& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
pod::PhysicsBody tri = {};
|
||||
tri.collider.type = pod::ShapeType::TRIANGLE;
|
||||
tri.collider.triangle = a;
|
||||
const auto& body = b;
|
||||
|
||||
return triangleGeneric( tri, body, manifold );
|
||||
}
|
||||
}
|
||||
|
||||
bool impl::triangleTriangle( const pod::TriangleWithNormal& a, const pod::TriangleWithNormal& b, pod::Manifold& manifold ) {
|
||||
if ( uf::physics::settings.useGjk ) {
|
||||
pod::PhysicsBody A = {};
|
||||
A.collider.type = pod::ShapeType::TRIANGLE;
|
||||
A.collider.triangle = a;
|
||||
|
||||
pod::PhysicsBody B = {};
|
||||
B.collider.type = pod::ShapeType::TRIANGLE;
|
||||
B.collider.triangle = b;
|
||||
|
||||
return impl::triangleGeneric( A, B, manifold );
|
||||
}
|
||||
|
||||
size_t axes = 0;
|
||||
pod::Vector3f axesBuffer[12];
|
||||
axesBuffer[axes++] = impl::triangleNormal(a);
|
||||
@ -88,6 +122,8 @@ bool impl::triangleTriangle( const pod::TriangleWithNormal& a, const pod::Triang
|
||||
}
|
||||
|
||||
bool impl::triangleAabb( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold ) {
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( tri, body, manifold );
|
||||
|
||||
const auto& aabb = body.bounds;
|
||||
|
||||
// box center and half extents
|
||||
@ -153,7 +189,82 @@ 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 ) {
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( tri, body, 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 ) {
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( tri, body, manifold );
|
||||
|
||||
const auto& sphere = body;
|
||||
|
||||
float r = sphere.collider.sphere.radius;
|
||||
@ -183,6 +294,8 @@ bool impl::triangleSphere( const pod::TriangleWithNormal& tri, const pod::Physic
|
||||
}
|
||||
// to-do: implement
|
||||
bool impl::trianglePlane( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold ) {
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( tri, body, manifold );
|
||||
|
||||
const auto& plane = body;
|
||||
auto normal = plane.collider.plane.normal;
|
||||
float d = plane.collider.plane.offset;
|
||||
@ -229,6 +342,8 @@ bool impl::trianglePlane( const pod::TriangleWithNormal& tri, const pod::Physics
|
||||
return hit;
|
||||
}
|
||||
bool impl::triangleCapsule( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold ) {
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( tri, body, manifold );
|
||||
|
||||
const auto& capsule = body;
|
||||
|
||||
float r = capsule.collider.capsule.radius;
|
||||
@ -268,22 +383,32 @@ bool impl::triangleHull( const pod::TriangleWithNormal& tri, const pod::PhysicsB
|
||||
|
||||
bool impl::triangleTriangle( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( TRIANGLE, TRIANGLE );
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( a, b, manifold );
|
||||
return impl::triangleTriangle( a.collider.triangle, b.collider.triangle, manifold );
|
||||
}
|
||||
bool impl::triangleAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( TRIANGLE, AABB );
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( a, b, manifold );
|
||||
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 );
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( a, b, manifold );
|
||||
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 );
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( a, b, manifold );
|
||||
return impl::triangleSphere( a.collider.triangle, b, manifold );
|
||||
}
|
||||
bool impl::trianglePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( TRIANGLE, PLANE );
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( a, b, manifold );
|
||||
return impl::trianglePlane( a.collider.triangle, b, manifold );
|
||||
}
|
||||
bool impl::triangleCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
ASSERT_COLLIDER_TYPES( TRIANGLE, CAPSULE );
|
||||
if ( uf::physics::settings.useGjk ) return impl::triangleGeneric( a, b, manifold );
|
||||
return impl::triangleCapsule( a.collider.triangle, b, manifold );
|
||||
}
|
||||
bool impl::triangleHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold ) {
|
||||
@ -296,4 +421,17 @@ bool impl::triangleHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, p
|
||||
auto result = impl::epa( tri, hull, simplex );
|
||||
if ( !impl::generateClippingManifold( tri, hull, result, manifold ) ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void impl::drawTriangle( const pod::PhysicsBody& body ) {
|
||||
const auto& tri = body.collider.triangle;
|
||||
auto transform = impl::getTransform(body);
|
||||
|
||||
pod::Vector3f v0 = uf::transform::apply(transform, tri.points[0]);
|
||||
pod::Vector3f v1 = uf::transform::apply(transform, tri.points[1]);
|
||||
pod::Vector3f v2 = uf::transform::apply(transform, tri.points[2]);
|
||||
|
||||
impl::addLine( v0, v1 );
|
||||
impl::addLine( v1, v2 );
|
||||
impl::addLine( v2, v0 );
|
||||
}
|
||||
@ -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