added forward+ rendermode, added debug draw for physics system (revealed my meshAabb/neshObb ocntact points were wrong)
This commit is contained in:
parent
6b07173804
commit
a1f62ef0c3
@ -8,7 +8,7 @@
|
||||
"useLightmaps": false,
|
||||
"max": 32,
|
||||
"shadows": {
|
||||
"enabled": true,
|
||||
"enabled": false,
|
||||
"update": 4,
|
||||
"max": 16,
|
||||
"samples": 2
|
||||
@ -110,7 +110,7 @@
|
||||
"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
|
||||
},
|
||||
@ -121,7 +121,7 @@
|
||||
"hdr": true,
|
||||
"vxgi": false, // to-do: fix issues
|
||||
"culling": false,
|
||||
"bloom": true,
|
||||
"bloom": false,
|
||||
"dof": false,
|
||||
"rt": false,
|
||||
"fsr": false,
|
||||
@ -336,10 +336,12 @@
|
||||
"discord": { "enabled": false }
|
||||
},
|
||||
"physics": {
|
||||
"warmup solver": true,
|
||||
"warmup solver": false,
|
||||
"block solver": true,
|
||||
"psg solver": true,
|
||||
"gjk": true,
|
||||
"correction percent": 0.0,
|
||||
"gjk": false,
|
||||
"debug draw": false,
|
||||
"fixed step": true,
|
||||
"substeps": 4,
|
||||
"solver iterations": 10
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
"physics": {
|
||||
"mass": 0,
|
||||
"inertia": [0, 0, 0],
|
||||
"type": "mesh" // "bounding box"
|
||||
"type": "bounding box"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"assets": [],
|
||||
"behaviors": [
|
||||
"SoundEmitterBehavior"
|
||||
],
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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 );
|
||||
}
|
||||
@ -243,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 };
|
||||
};
|
||||
|
||||
@ -251,6 +252,8 @@ namespace pod {
|
||||
bool awake = true;
|
||||
uf::stl::vector<uint32_t> indices;
|
||||
pod::BVH::pairs_t pairs;
|
||||
|
||||
uf::stl::vector<pod::Manifold> manifolds;
|
||||
};
|
||||
|
||||
struct PhysicsSettings {
|
||||
@ -259,6 +262,7 @@ namespace pod {
|
||||
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
|
||||
|
||||
|
||||
@ -10,4 +10,6 @@ namespace impl {
|
||||
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 );
|
||||
}
|
||||
@ -10,4 +10,6 @@ namespace impl {
|
||||
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 );
|
||||
}
|
||||
@ -10,4 +10,6 @@ namespace impl {
|
||||
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 );
|
||||
}
|
||||
@ -10,4 +10,6 @@ namespace impl {
|
||||
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 );
|
||||
}
|
||||
@ -10,4 +10,6 @@ namespace impl {
|
||||
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 );
|
||||
}
|
||||
@ -10,4 +10,6 @@ namespace impl {
|
||||
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 );
|
||||
}
|
||||
@ -13,4 +13,6 @@ namespace impl {
|
||||
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 );
|
||||
}
|
||||
@ -10,4 +10,6 @@ namespace impl {
|
||||
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 );
|
||||
}
|
||||
@ -18,4 +18,6 @@ namespace impl {
|
||||
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 );
|
||||
}
|
||||
@ -95,13 +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 = pointer->position + uf::quaternion::rotate(pointer->orientation, combined.position);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -200,14 +200,16 @@ void UF_API uf::load( ext::json::Value& json ) {
|
||||
|
||||
// Physics settings
|
||||
{
|
||||
auto& confingEnginePhysicsJson = json["engine"]["physics"];
|
||||
uf::physics::settings.warmupSolver = confingEnginePhysicsJson["warmup solver"].as(uf::physics::settings.warmupSolver);
|
||||
uf::physics::settings.blockContactSolver = confingEnginePhysicsJson["block solver"].as(uf::physics::settings.blockContactSolver);
|
||||
uf::physics::settings.psgContactSolver = confingEnginePhysicsJson["psg solver"].as(uf::physics::settings.psgContactSolver);
|
||||
uf::physics::settings.useGjk = confingEnginePhysicsJson["gjk"].as(uf::physics::settings.useGjk);
|
||||
uf::physics::settings.fixedStep = confingEnginePhysicsJson["fixed step"].as(uf::physics::settings.fixedStep);
|
||||
uf::physics::settings.substeps = confingEnginePhysicsJson["substeps"].as(uf::physics::settings.substeps);
|
||||
uf::physics::settings.solverIterations = confingEnginePhysicsJson["solver iterations"].as(uf::physics::settings.solverIterations);
|
||||
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
|
||||
|
||||
@ -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{} );
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -735,7 +735,7 @@ pod::AABB impl::computeAABB( const pod::PhysicsBody& body ) {
|
||||
switch ( body.collider.type ) {
|
||||
case pod::ShapeType::AABB:
|
||||
case pod::ShapeType::OBB: {
|
||||
return impl::transformAabbToWorld( body.collider.aabb, *body.transform );
|
||||
return impl::transformAabbToWorld( body.collider.aabb, transform );
|
||||
/*
|
||||
return {
|
||||
transform.position + body.collider.aabb.min,
|
||||
@ -756,7 +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 impl::transformAabbToWorld( body.collider.mesh.bvh->bounds[0], *body.transform );
|
||||
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 );
|
||||
|
||||
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;
|
||||
@ -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 );
|
||||
@ -290,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;
|
||||
|
||||
@ -338,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: {
|
||||
@ -455,6 +473,7 @@ pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, co
|
||||
body.collider.type = pod::ShapeType::OBB;
|
||||
body.collider.aabb = aabb;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
|
||||
uf::physics::updateInertia( body );
|
||||
return body;
|
||||
}
|
||||
@ -579,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;
|
||||
@ -604,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;
|
||||
}
|
||||
|
||||
@ -75,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] );
|
||||
}
|
||||
@ -103,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 );
|
||||
}
|
||||
@ -80,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] );
|
||||
}
|
||||
}
|
||||
@ -185,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] );
|
||||
}
|
||||
}
|
||||
@ -274,4 +274,29 @@ bool impl::obbMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::M
|
||||
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] );
|
||||
}
|
||||
@ -63,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 );
|
||||
}
|
||||
@ -299,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 );
|
||||
}
|
||||
@ -65,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
|
||||
@ -154,7 +190,9 @@ bool impl::triangleAabb( const pod::TriangleWithNormal& tri, const pod::PhysicsB
|
||||
return true;
|
||||
}
|
||||
bool impl::triangleObb( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold ) {
|
||||
auto tB = impl::getTransform( body );
|
||||
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;
|
||||
@ -225,6 +263,8 @@ bool impl::triangleObb( const pod::TriangleWithNormal& tri, const pod::PhysicsBo
|
||||
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;
|
||||
@ -254,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;
|
||||
@ -300,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;
|
||||
@ -339,26 +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 ) {
|
||||
@ -371,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 );
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user