diff --git a/bin/data/config.json b/bin/data/config.json index 7d89bba9..891bca5e 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -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 diff --git a/bin/data/entities/door.json b/bin/data/entities/door.json index 72049cc4..2d24eed5 100644 --- a/bin/data/entities/door.json +++ b/bin/data/entities/door.json @@ -7,7 +7,7 @@ "physics": { "mass": 0, "inertia": [0, 0, 0], - "type": "mesh" // "bounding box" + "type": "bounding box" } } } \ No newline at end of file diff --git a/bin/data/entities/physics_prop.json b/bin/data/entities/physics_prop.json index d0689bdf..41ba0c0c 100644 --- a/bin/data/entities/physics_prop.json +++ b/bin/data/entities/physics_prop.json @@ -1,4 +1,5 @@ { + "assets": [], "behaviors": [ "SoundEmitterBehavior" ], diff --git a/bin/data/entities/scripts/player.lua b/bin/data/entities/scripts/player.lua index 69d17c6c..1fc46d25 100644 --- a/bin/data/entities/scripts/player.lua +++ b/bin/data/entities/scripts/player.lua @@ -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 diff --git a/bin/data/shaders/base/line/frag.glsl b/bin/data/shaders/base/line/frag.glsl index 935d731a..46d0c4f2 100644 --- a/bin/data/shaders/base/line/frag.glsl +++ b/bin/data/shaders/base/line/frag.glsl @@ -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; } \ No newline at end of file diff --git a/bin/data/shaders/base/line/vert.glsl b/bin/data/shaders/base/line/vert.glsl index 32b9484c..e5763af9 100644 --- a/bin/data/shaders/base/line/vert.glsl +++ b/bin/data/shaders/base/line/vert.glsl @@ -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); } \ No newline at end of file diff --git a/engine/inc/uf/ext/opengl/graphic.h b/engine/inc/uf/ext/opengl/graphic.h index 8aba4c8f..debc0493 100644 --- a/engine/inc/uf/ext/opengl/graphic.h +++ b/engine/inc/uf/ext/opengl/graphic.h @@ -6,7 +6,7 @@ #include #include #include - +#include #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 Graphics; } } diff --git a/engine/inc/uf/ext/vulkan/graphic.h b/engine/inc/uf/ext/vulkan/graphic.h index de26bd96..82d00e47 100644 --- a/engine/inc/uf/ext/vulkan/graphic.h +++ b/engine/inc/uf/ext/vulkan/graphic.h @@ -6,6 +6,7 @@ #include #include #include +#include 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 Graphics; } } \ No newline at end of file diff --git a/engine/inc/uf/ext/vulkan/rendermodes/deferred.h b/engine/inc/uf/ext/vulkan/rendermodes/deferred.h index 7fec1dc9..4f5f3994 100644 --- a/engine/inc/uf/ext/vulkan/rendermodes/deferred.h +++ b/engine/inc/uf/ext/vulkan/rendermodes/deferred.h @@ -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 ); diff --git a/engine/inc/uf/ext/vulkan/rendertarget.h b/engine/inc/uf/ext/vulkan/rendertarget.h index a063e8fc..fb798a65 100644 --- a/engine/inc/uf/ext/vulkan/rendertarget.h +++ b/engine/inc/uf/ext/vulkan/rendertarget.h @@ -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&, const uf::stl::vector&, const uf::stl::vector&, size_t, size_t = 0, bool = true ); size_t attach( const Attachment::Descriptor& descriptor, Attachment* attachment = NULL ); + size_t aliasAttachment( const Attachment& attachment ); }; } } \ No newline at end of file diff --git a/engine/inc/uf/macros.h b/engine/inc/uf/macros.h index e5e26255..20778074 100644 --- a/engine/inc/uf/macros.h +++ b/engine/inc/uf/macros.h @@ -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 ) diff --git a/engine/inc/uf/utils/math/physics/common.h b/engine/inc/uf/utils/math/physics/common.h index 483888d2..905fc15e 100644 --- a/engine/inc/uf/utils/math/physics/common.h +++ b/engine/inc/uf/utils/math/physics/common.h @@ -1,6 +1,7 @@ #pragma once #include "impl.h" +#include "draw.h" // to-do: organize this mess namespace impl { diff --git a/engine/inc/uf/utils/math/physics/draw.h b/engine/inc/uf/utils/math/physics/draw.h new file mode 100644 index 00000000..fe810b89 --- /dev/null +++ b/engine/inc/uf/utils/math/physics/draw.h @@ -0,0 +1,19 @@ +#pragma once + +#include "impl.h" + +namespace impl { + struct Vertex { + pod::Vector3f position; + pod::Vector4f color; + + static uf::stl::vector 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 ); +} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/impl.h b/engine/inc/uf/utils/math/physics/impl.h index 477c601d..44e9c252 100644 --- a/engine/inc/uf/utils/math/physics/impl.h +++ b/engine/inc/uf/utils/math/physics/impl.h @@ -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 indices; pod::BVH::pairs_t pairs; + + uf::stl::vector 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 diff --git a/engine/inc/uf/utils/math/physics/narrowphase/aabb.h b/engine/inc/uf/utils/math/physics/narrowphase/aabb.h index 2819f267..bd340460 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/aabb.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/aabb.h @@ -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 ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/capsule.h b/engine/inc/uf/utils/math/physics/narrowphase/capsule.h index 5b36f90f..144d48a8 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/capsule.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/capsule.h @@ -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 ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/hull.h b/engine/inc/uf/utils/math/physics/narrowphase/hull.h index 84afacba..ce40f9cb 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/hull.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/hull.h @@ -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 ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/mesh.h b/engine/inc/uf/utils/math/physics/narrowphase/mesh.h index cf75358b..6a60a4af 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/mesh.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/mesh.h @@ -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 ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/obb.h b/engine/inc/uf/utils/math/physics/narrowphase/obb.h index 3a37c635..8820c06f 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/obb.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/obb.h @@ -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 ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/plane.h b/engine/inc/uf/utils/math/physics/narrowphase/plane.h index f376c6c0..95b4c871 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/plane.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/plane.h @@ -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 ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/ray.h b/engine/inc/uf/utils/math/physics/narrowphase/ray.h index bd6d0888..971ecce4 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/ray.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/ray.h @@ -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 ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/sphere.h b/engine/inc/uf/utils/math/physics/narrowphase/sphere.h index d993b028..dccdc524 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/sphere.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/sphere.h @@ -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 ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/narrowphase/triangle.h b/engine/inc/uf/utils/math/physics/narrowphase/triangle.h index 099b9e89..08da2e80 100644 --- a/engine/inc/uf/utils/math/physics/narrowphase/triangle.h +++ b/engine/inc/uf/utils/math/physics/narrowphase/triangle.h @@ -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 ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/transform/transform.inl b/engine/inc/uf/utils/math/transform/transform.inl index ccf1ec02..e5349267 100644 --- a/engine/inc/uf/utils/math/transform/transform.inl +++ b/engine/inc/uf/utils/math/transform/transform.inl @@ -95,13 +95,9 @@ pod::Transform /*UF_API*/ uf::transform::flatten( const pod::Transform& tr const pod::Transform* 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; diff --git a/engine/inc/uf/utils/math/vector.h b/engine/inc/uf/utils/math/vector.h index b3d5e1fb..48160504 100644 --- a/engine/inc/uf/utils/math/vector.h +++ b/engine/inc/uf/utils/math/vector.h @@ -16,6 +16,7 @@ #include #include #include +#include #if UF_USE_BFLOAT16 #include diff --git a/engine/inc/uf/utils/math/vector/pod.inl b/engine/inc/uf/utils/math/vector/pod.inl index 3e30b0a2..5859a1b7 100644 --- a/engine/inc/uf/utils/math/vector/pod.inl +++ b/engine/inc/uf/utils/math/vector/pod.inl @@ -743,7 +743,7 @@ template 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; } diff --git a/engine/src/engine/ext/ext.cpp b/engine/src/engine/ext/ext.cpp index 0a4a0609..cc6b0b1f 100644 --- a/engine/src/engine/ext/ext.cpp +++ b/engine/src/engine/ext/ext.cpp @@ -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 diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index 85f64d71..eb0574e8 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -134,12 +134,25 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { auto type = metadataJsonPhysics["type"].as(); float mass = metadataJsonPhysics["mass"].as(); + bool recenter = metadataJsonPhysics["recenter"].as(); 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{} ); diff --git a/engine/src/ext/opengl/opengl.cpp b/engine/src/ext/opengl/opengl.cpp index cfbe4d87..32f3e8b3 100644 --- a/engine/src/ext/opengl/opengl.cpp +++ b/engine/src/ext/opengl/opengl.cpp @@ -381,11 +381,20 @@ void ext::opengl::tick(){ auto& scene = uf::scene::getCurrentScene(); auto& graph = scene.getGraph(); for ( auto entity : graph ) { - if ( !entity->hasComponent() ) continue; - ext::opengl::Graphic& graphic = entity->getComponent(); - if ( graphic.initialized || !graphic.process || graphic.initialized ) continue; - graphic.initializePipeline(); - ext::opengl::states::rebuild = true; + if ( entity->hasComponent() ) { + auto& graphics = entity->getComponent(); + for ( auto& [ _, graphic ] : graphics ) { + if ( graphic.initialized || !graphic.process ) continue; + graphic.initializePipeline(); + ext::opengl::states::rebuild = true; + } + } + if ( entity->hasComponent() ) { + auto& graphic = entity->getComponent(); + if ( graphic.initialized || !graphic.process ) continue; + graphic.initializePipeline(); + ext::opengl::states::rebuild = true; + } } for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; diff --git a/engine/src/ext/opengl/rendermode.cpp b/engine/src/ext/opengl/rendermode.cpp index 68feec5b..60ea07e9 100644 --- a/engine/src/ext/opengl/rendermode.cpp +++ b/engine/src/ext/opengl/rendermode.cpp @@ -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() ) continue; - ext::opengl::Graphic& graphic = entity->getComponent(); - if ( !graphic.initialized || !graphic.process ) continue; - graphics.push_back(&graphic); + if ( entity->hasComponent() ) { + auto& g = entity->getComponent(); + for ( auto& [ _, graphic ] : g ) { + if ( !graphic.initialized || !graphic.process ) continue; + graphics.emplace_back(&graphic); + } + } + if ( entity->hasComponent() ) { + auto& graphic = entity->getComponent(); + if ( !graphic.initialized || !graphic.process ) continue; + graphics.emplace_back(&graphic); + } } this->synchronize(); diff --git a/engine/src/ext/vulkan/rendermode.cpp b/engine/src/ext/vulkan/rendermode.cpp index 647c9575..a892f50d 100644 --- a/engine/src/ext/vulkan/rendermode.cpp +++ b/engine/src/ext/vulkan/rendermode.cpp @@ -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() ) continue; - ext::vulkan::Graphic& graphic = entity->getComponent(); - if ( !graphic.initialized || !graphic.process ) continue; - graphics.emplace_back(&graphic); + if ( entity->hasComponent() ) { + auto& g = entity->getComponent(); + for ( auto& [ _, graphic ] : g ) { + if ( !graphic.initialized || !graphic.process ) continue; + graphics.emplace_back(&graphic); + } + } + if ( entity->hasComponent() ) { + auto& graphic = entity->getComponent(); + if ( !graphic.initialized || !graphic.process ) continue; + graphics.emplace_back(&graphic); + } } // this->synchronize(); diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index 72c07634..d3afde53 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -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 } ); diff --git a/engine/src/ext/vulkan/rendertarget.cpp b/engine/src/ext/vulkan/rendertarget.cpp index 70da89d7..71e714cb 100644 --- a/engine/src/ext/vulkan/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendertarget.cpp @@ -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] ); diff --git a/engine/src/ext/vulkan/vulkan.cpp b/engine/src/ext/vulkan/vulkan.cpp index 959e69f9..b4b1eefc 100644 --- a/engine/src/ext/vulkan/vulkan.cpp +++ b/engine/src/ext/vulkan/vulkan.cpp @@ -520,9 +520,17 @@ void ext::vulkan::tick() { auto& scene = uf::scene::getCurrentScene(); auto/*&*/ graph = scene.getGraph(); for ( auto entity : graph ) { - if ( entity->hasComponent() ) { - ext::vulkan::Graphic& graphic = entity->getComponent(); - if ( graphic.initialized || !graphic.process || graphic.initialized ) continue; + if ( entity->hasComponent() ) { + auto& graphics = entity->getComponent(); + for ( auto& [ _, graphic ] : graphics ) { + if ( graphic.initialized || !graphic.process ) continue; + graphic.update(); + ext::vulkan::states::rebuild = true; + } + } + if ( entity->hasComponent() ) { + auto& graphic = entity->getComponent(); + if ( graphic.initialized || !graphic.process ) continue; graphic.update(); ext::vulkan::states::rebuild = true; } diff --git a/engine/src/utils/math/physics/common.cpp b/engine/src/utils/math/physics/common.cpp index 732af248..d351b104 100644 --- a/engine/src/utils/math/physics/common.cpp +++ b/engine/src/utils/math/physics/common.cpp @@ -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 ); diff --git a/engine/src/utils/math/physics/draw.cpp b/engine/src/utils/math/physics/draw.cpp new file mode 100644 index 00000000..91d018b3 --- /dev/null +++ b/engine/src/utils/math/physics/draw.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include + +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 lines; + uf::stl::unordered_map 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(start.x * 10.0f); + int qy = static_cast(start.y * 10.0f); + int qz = static_cast(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(); + mesh.insertVertices(::lines); + + auto& scene = uf::scene::getCurrentScene(); + auto& graphics = scene.getComponent(); + 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(); + + // 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; + } +} diff --git a/engine/src/utils/math/physics/impl.cpp b/engine/src/utils/math/physics/impl.cpp index a09022cd..d8be4563 100644 --- a/engine/src/utils/math/physics/impl.cpp +++ b/engine/src/utils/math/physics/impl.cpp @@ -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 islands; + STATIC_THREAD_LOCAL(uf::stl::vector, 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, 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; } diff --git a/engine/src/utils/math/physics/narrowphase/aabb.cpp b/engine/src/utils/math/physics/narrowphase/aabb.cpp index 36771559..d8edf2ea 100644 --- a/engine/src/utils/math/physics/narrowphase/aabb.cpp +++ b/engine/src/utils/math/physics/narrowphase/aabb.cpp @@ -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] ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/capsule.cpp b/engine/src/utils/math/physics/narrowphase/capsule.cpp index 386291a3..e9cf88e5 100644 --- a/engine/src/utils/math/physics/narrowphase/capsule.cpp +++ b/engine/src/utils/math/physics/narrowphase/capsule.cpp @@ -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 ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/hull.cpp b/engine/src/utils/math/physics/narrowphase/hull.cpp index 10b7ba09..b780bd39 100644 --- a/engine/src/utils/math/physics/narrowphase/hull.cpp +++ b/engine/src/utils/math/physics/narrowphase/hull.cpp @@ -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] ); + } } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/mesh.cpp b/engine/src/utils/math/physics/narrowphase/mesh.cpp index f2959e28..bbc8d852 100644 --- a/engine/src/utils/math/physics/narrowphase/mesh.cpp +++ b/engine/src/utils/math/physics/narrowphase/mesh.cpp @@ -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] ); + } } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/obb.cpp b/engine/src/utils/math/physics/narrowphase/obb.cpp index 7a80c12d..61938c49 100644 --- a/engine/src/utils/math/physics/narrowphase/obb.cpp +++ b/engine/src/utils/math/physics/narrowphase/obb.cpp @@ -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] ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/plane.cpp b/engine/src/utils/math/physics/narrowphase/plane.cpp index ad41f6db..978777b9 100644 --- a/engine/src/utils/math/physics/narrowphase/plane.cpp +++ b/engine/src/utils/math/physics/narrowphase/plane.cpp @@ -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 ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/ray.cpp b/engine/src/utils/math/physics/narrowphase/ray.cpp index e7ac7be0..82313a74 100644 --- a/engine/src/utils/math/physics/narrowphase/ray.cpp +++ b/engine/src/utils/math/physics/narrowphase/ray.cpp @@ -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 ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/sphere.cpp b/engine/src/utils/math/physics/narrowphase/sphere.cpp index 8e41bbb7..2d6c0974 100644 --- a/engine/src/utils/math/physics/narrowphase/sphere.cpp +++ b/engine/src/utils/math/physics/narrowphase/sphere.cpp @@ -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 ); + } } \ No newline at end of file diff --git a/engine/src/utils/math/physics/narrowphase/triangle.cpp b/engine/src/utils/math/physics/narrowphase/triangle.cpp index dddd034d..83150ec7 100644 --- a/engine/src/utils/math/physics/narrowphase/triangle.cpp +++ b/engine/src/utils/math/physics/narrowphase/triangle.cpp @@ -1,7 +1,41 @@ #include #include +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 ); } \ No newline at end of file