From 6ffe08a013eb83884267de18b940d372800f40bf Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Sun, 6 Oct 2024 14:49:10 +0200 Subject: [PATCH] added grabbing with left click --- CMakeLists.txt | 3 + include/application.hpp | 25 +++- include/camera.hpp | 1 + include/grabber.hpp | 18 +++ include/input.hpp | 2 +- include/vulkan/descriptor_pool.hpp | 7 +- include/vulkan/pipeline.hpp | 6 - shaders/compile.sh | 3 +- shaders/grab.comp | 180 +++++++++++++++++++++++++++++ shaders/shader.vert | 6 +- src/application.cpp | 170 ++++++++++++++++++++------- src/camera.cpp | 128 ++++++++++++++++++++ src/grabber.cpp | 44 +++++++ src/vulkan/descriptor_pool.cpp | 11 +- 14 files changed, 541 insertions(+), 63 deletions(-) create mode 100644 include/grabber.hpp create mode 100644 shaders/grab.comp create mode 100644 src/grabber.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 937d2f2..d05d479 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,4 +24,7 @@ target_include_directories(VulkanSimulation PRIVATE include) target_compile_definitions(VulkanSimulation PRIVATE GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE + BLOCK_SIZE_GRAB=32 + BLOCK_SIZE_PBD=32 + BLOCK_SIZE_NORMAL=32 ) diff --git a/include/application.hpp b/include/application.hpp index 86c1c4c..bd89ebe 100644 --- a/include/application.hpp +++ b/include/application.hpp @@ -16,6 +16,7 @@ #include #include #include "constraints.hpp" +#include #include using std::unique_ptr, std::make_unique; @@ -33,6 +34,7 @@ class Fence; class Semaphore; class Camera; class DescriptorPool; +class Grabber; class Application { public: @@ -54,9 +56,17 @@ private: unique_ptr swapchain; unique_ptr descriptorPool; unique_ptr graphicsPipeline; - unique_ptr uniformBuffer; + + struct CameraUniformData { + glm::mat4 view; + glm::mat4 projection; + glm::vec2 viewport; + }; + unique_ptr cameraUniformBuffer; unique_ptr camera; + unique_ptr grabber; + unique_ptr grabBuffer; void createMeshBuffers(); size_t currentDrawVertexBuffer = 0; @@ -86,7 +96,14 @@ private: unique_ptr propertiesBuffer; Properties properties {}; + struct GrabPushConstants { + uint32_t state; + alignas(8) glm::vec2 screenPosition; + glm::vec2 screenDelta; + }; + void createComputePipelines(); + unique_ptr grabPipeline; unique_ptr pbdPipeline; unique_ptr normalPipeline; @@ -94,7 +111,9 @@ private: void recordDrawCommands(VkCommandBuffer cmdBuffer); void drawFrame(); - void recordComputeCommands(VkCommandBuffer cmdBuffer); + void recordGrabCommands(VkCommandBuffer cmdBuffer); + void recordPBDCommands(VkCommandBuffer cmdBuffer); + void recordNormalCommands(VkCommandBuffer cmdBuffer); struct PBDPushData { uint32_t state; ConstraintData::Partition edgePartition; @@ -102,4 +121,6 @@ private: }; void update(); + + static uint32_t GetGroupCount(uint32_t threads, uint32_t blockSize); }; diff --git a/include/camera.hpp b/include/camera.hpp index f022160..f6c1269 100644 --- a/include/camera.hpp +++ b/include/camera.hpp @@ -22,6 +22,7 @@ public: void update(float dt); glm::mat4 view() const; glm::mat4 projection() const; + glm::vec2 viewport() const; glm::vec3 localToWorld(const glm::vec3& direction) const; protected: void mouseMoved(const glm::vec2 &delta) override; diff --git a/include/grabber.hpp b/include/grabber.hpp new file mode 100644 index 0000000..aec0b67 --- /dev/null +++ b/include/grabber.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "input.hpp" +#include "glm/vec2.hpp" + +class Grabber : MouseListener { +public: + bool started(); + bool stopped(); + bool moved(glm::vec2 &delta); + glm::vec2 previousCursorPosition; +protected: + virtual void mouseButtonPressed(int button); + virtual void mouseButtonReleased(int button); +private: + bool start = false; + bool stop = false; +}; \ No newline at end of file diff --git a/include/input.hpp b/include/input.hpp index b2e1d75..bd865d4 100644 --- a/include/input.hpp +++ b/include/input.hpp @@ -16,6 +16,7 @@ public: static Input* instance; static std::map KeyIsDown; static std::map MouseButtonIsDown; + glm::vec2 currentCursorPosition {}; private: GLFWwindow* window; std::set listeners; @@ -26,7 +27,6 @@ private: void mouseButtonPressed(int button); void mouseButtonReleased(int button); void mouseMoved(const glm::vec2& newCursorPosition); - glm::vec2 currentCursorPosition; }; class Listener { diff --git a/include/vulkan/descriptor_pool.hpp b/include/vulkan/descriptor_pool.hpp index 8f32366..a00829e 100644 --- a/include/vulkan/descriptor_pool.hpp +++ b/include/vulkan/descriptor_pool.hpp @@ -7,9 +7,10 @@ class Buffer; enum class DescriptorSet { - WORLD = 0, - MESH = 1, - SIMULATION = 2 + WORLD, + SIMULATION, + MESH + }; class DescriptorPool { diff --git a/include/vulkan/pipeline.hpp b/include/vulkan/pipeline.hpp index 342dc21..908bcee 100644 --- a/include/vulkan/pipeline.hpp +++ b/include/vulkan/pipeline.hpp @@ -5,12 +5,6 @@ class Instance; -struct UniformBufferObject { - alignas(16) glm::mat4 model; - glm::mat4 view; - glm::mat4 projection; -}; - class Pipeline { public: VkPipeline handle = VK_NULL_HANDLE; diff --git a/shaders/compile.sh b/shaders/compile.sh index 8acbf25..37f194d 100755 --- a/shaders/compile.sh +++ b/shaders/compile.sh @@ -2,4 +2,5 @@ glslc shader.vert -o vert.spv glslc shader.frag -o frag.spv glslc pbd.comp -o pbd.spv -glslc normal.comp -o normal.spv \ No newline at end of file +glslc normal.comp -o normal.spv +glslc grab.comp -o grab.spv \ No newline at end of file diff --git a/shaders/grab.comp b/shaders/grab.comp new file mode 100644 index 0000000..acc6d99 --- /dev/null +++ b/shaders/grab.comp @@ -0,0 +1,180 @@ +#version 450 + +layout (local_size_x = 32) in; + +struct Vertex { + vec3 position; + vec3 color; + vec2 uv; + vec3 normal; + vec3 velocity; + vec3 prevPosition; + float inverseMass; +}; + +struct Face { + uint a; + uint b; + uint c; +}; + +layout (std430, set = 0, binding = 0) buffer VertexBuffer { + Vertex vertices[]; +}; +layout (std430, set = 0, binding = 1) buffer FaceBuffer { + Face faces[]; +}; + +layout (std140, set = 0, binding = 5) uniform Sizes { + uint vertexCount; + uint faceCount; +}; + +layout (set = 1, binding = 0) uniform CameraUniform { + mat4 view; + mat4 projection; + vec2 viewport; +} camera; + + +layout (std430, set = 2, binding = 1) buffer GrabInformation { + float originalInverseMass; + uint vID; + float distanceToFace; + bool foundHit; +}; + +layout (push_constant, std430) uniform PushConstants { + uint state; + vec2 screenPosition; + vec2 screenDelta; +}; + +vec3 toNDC(vec3 world){ + mat4 realProjection = camera.projection; + realProjection[1][1] *= -1; + + mat4 VP = realProjection * camera.view; + + vec4 inhomo = VP * vec4(world, 1); + + return vec3(inhomo.xyz / inhomo.w); +} + +vec3 toWorld(vec3 ndcCube){ + mat4 realProjection = camera.projection; + realProjection[1][1] *= -1; + mat4 VPinv = inverse(realProjection * camera.view); + + vec4 inhomo = VPinv * vec4(ndcCube, 1); + + return vec3(inhomo.xyz / inhomo.w); +} + +void rayForward(out vec3 origin, out vec3 direction){ + vec2 ndc = vec2( + (2 * screenPosition.x / camera.viewport.x) - 1, + 1 - (2 * screenPosition.y / camera.viewport.y) + ); + + vec3 a = vec3(ndc, 0); + vec3 b = vec3(ndc, 1); + + vec3 p1 = toWorld(a); + vec3 p2 = toWorld(b); + + origin = p1; + direction = normalize(p2 - p1); +} + +void testFace(uint fID){ + // test this face, if hit, set grabinformation if distance is new minimum + vec3 origin; + vec3 direction; + rayForward(origin, direction); + + Face face = faces[fID]; + vec3 a = vertices[face.a].position; + vec3 b = vertices[face.b].position; + vec3 c = vertices[face.c].position; + + vec3 ab = b - a; + vec3 ac = c - a; + + vec3 n = cross(ab, ac); + float r = dot(a - origin, n) / dot(direction, n); + vec3 q = origin + r * direction; + + vec3 qa = a - q; + vec3 qb = b - q; + vec3 qc = c - q; + + float area = length(cross(ab, ac)) / 2; + float alpha = length(cross(qb, qc)) / (2 * area); + float beta = length(cross(qc, qa)) / (2 * area); + float gamma = length(cross(qa, qb)) / (2 * area); + + bool isOne = abs(alpha + beta + gamma - 1) < 0.001; + + if (alpha >= 0 && alpha <= 1 && beta >= 0 && beta <= 1 && gamma >= 0 && gamma <= 1 && isOne){ + if (r < distanceToFace){ + foundHit = true; + vID = face.a; + distanceToFace = r; + } + } + + +} + +void move(){ + vec3 ndcDelta = vec3( + 2 * screenDelta.x / camera.viewport.x, + -2 * screenDelta.y / camera.viewport.y, + 0 + ); + + vec3 ndc = toNDC(vertices[vID].position); + vec3 ndc2 = ndc + ndcDelta; + + vec3 p2 = toWorld(ndc2); + + vec3 worldDelta = p2 - vertices[vID].position; + + vertices[vID].position += worldDelta; +} + +void release(){ + vertices[vID].inverseMass = originalInverseMass; + distanceToFace = 1e20; + foundHit = false; +} + +void main(){ + uint id = gl_GlobalInvocationID.x; + + switch (state){ + case 0: + if (id < faceCount){ + testFace(id); + } + break; + case 1: + if (id == 0 && foundHit){ + originalInverseMass = vertices[vID].inverseMass; + vertices[vID].inverseMass = 0; + } + break; + case 2: + if (id == 0 && foundHit){ + move(); + } + break; + case 3: + if (id == 0 && foundHit){ + release(); + } + break; + + } +} \ No newline at end of file diff --git a/shaders/shader.vert b/shaders/shader.vert index 17746dd..29bafbd 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -10,13 +10,13 @@ layout (location = 1) out vec2 uv; layout (location = 2) out vec3 normal; layout (set = 0, binding = 0) uniform UniformBufferObject { - mat4 model; mat4 view; mat4 projection; -} ubo; + vec2 viewport; +} camera; void main() { - gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition, 1.0); + gl_Position = camera.projection * camera.view * vec4(inPosition, 1.0); color = inColor; normal = inNormal; uv = inUV; diff --git a/src/application.cpp b/src/application.cpp index 23d7bfa..796dbb1 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -13,6 +13,7 @@ #include "mesh.hpp" #include "constraints.hpp" #include "timer.hpp" +#include "grabber.hpp" Application::Application() { createSyncObjects(); @@ -22,16 +23,27 @@ Application::Application() { swapchain->renderPass, {descriptorPool->layouts[DescriptorSet::WORLD]})); - VkDeviceSize bufferSize = sizeof(UniformBufferObject); + VkDeviceSize bufferSize = sizeof(CameraUniformData); - uniformBuffer = make_unique(bufferSize, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, + cameraUniformBuffer = make_unique(bufferSize, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); - descriptorPool->bindBuffer(*uniformBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::WORLD, 0); + descriptorPool->bindBuffer(*cameraUniformBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::WORLD, 0); camera = make_unique(swapchain->extent); + struct GrabInformation { + float originalInverseMass; + uint32_t vID; + float distanceToFace; + bool grabbing; + } initialGrabInformation {}; + initialGrabInformation.distanceToFace = 1e20; + grabBuffer = make_unique(sizeof(GrabInformation), &initialGrabInformation, sizeof(GrabInformation), + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); + grabber = make_unique(); + createMeshBuffers(); SizeInformation sizeInformation {}; @@ -60,6 +72,7 @@ Application::Application() { descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5); descriptorPool->bindBuffer(*propertiesBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::SIMULATION, 0); + descriptorPool->bindBuffer(*grabBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::SIMULATION, 1); createComputePipelines(); @@ -77,8 +90,6 @@ using namespace std::chrono; void Application::mainLoop() { std::future compute = std::async(std::launch::async, [this](){ while (!glfwWindowShouldClose(Instance::instance->window)){ - Timer timer; - auto t1 = system_clock::now(); update(); auto t2 = system_clock::now(); @@ -233,6 +244,21 @@ void Application::createComputePipelines() { vector layouts; vector pushRanges; + { + layouts.push_back(descriptorPool->layouts[DescriptorSet::MESH]); + layouts.push_back(descriptorPool->layouts[DescriptorSet::WORLD]); + layouts.push_back(descriptorPool->layouts[DescriptorSet::SIMULATION]); + pushRanges.push_back({ + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .offset = 0, + .size = sizeof(GrabPushConstants) + }); + grabPipeline = unique_ptr(new ComputePipeline("shaders/grab.spv", layouts, pushRanges)); + } + + layouts.clear(); + pushRanges.clear(); + { layouts.push_back(descriptorPool->layouts[DescriptorSet::MESH]); layouts.push_back(descriptorPool->layouts[DescriptorSet::SIMULATION]); @@ -265,21 +291,18 @@ void Application::updateUniformBuffer() { elapsed += 0.007; - UniformBufferObject ubo {}; - ubo.model = glm::mat4(1); + CameraUniformData ubo {}; ubo.view = camera->view(); ubo.projection = camera->projection(); ubo.projection[1][1] *= -1; + ubo.viewport = camera->viewport(); - memcpy(uniformBuffer->allocationInfo.pMappedData, &ubo, sizeof(UniformBufferObject)); + memcpy(cameraUniformBuffer->allocationInfo.pMappedData, &ubo, sizeof(CameraUniformData)); - VkMappedMemoryRange mappedMemoryRange {}; - mappedMemoryRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - mappedMemoryRange.offset = uniformBuffer->allocationInfo.offset; - mappedMemoryRange.size = uniformBuffer->allocationInfo.size; - mappedMemoryRange.memory = uniformBuffer->allocationInfo.deviceMemory; - - vkFlushMappedMemoryRanges(Instance::GetDevice(), 1, &mappedMemoryRange); + vmaFlushAllocation(Instance::GetAllocator(), + cameraUniformBuffer->allocation, + cameraUniformBuffer->allocationInfo.offset, + cameraUniformBuffer->allocationInfo.size); } void Application::drawFrame() { @@ -319,9 +342,9 @@ void Application::drawFrame() { VkBufferMemoryBarrier uniformBufferBarrier {}; uniformBufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - uniformBufferBarrier.size = uniformBuffer->size; + uniformBufferBarrier.size = cameraUniformBuffer->size; uniformBufferBarrier.offset = 0; - uniformBufferBarrier.buffer = uniformBuffer->handle; + uniformBufferBarrier.buffer = cameraUniformBuffer->handle; uniformBufferBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; uniformBufferBarrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT; @@ -403,6 +426,20 @@ void Application::drawFrame() { } } +void Application::recordDrawCommands(VkCommandBuffer cmdBuffer) { + vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->handle); + + VkBuffer buffers[] = {vertexBuffers[currentDrawVertexBuffer]->handle}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(cmdBuffer, 0, 1, buffers, offsets); + vkCmdBindIndexBuffer(cmdBuffer, faceBuffer->handle, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::WORLD], 0, nullptr); + + for (const auto &softBody : softBodies){ + vkCmdDrawIndexed(cmdBuffer, softBody->faces.size() * 3, 1, softBody->firstIndex, 0, 0); + } +} + void Application::update() { vkWaitForFences(Instance::GetDevice(), 1, &transferFence->handle, VK_TRUE, UINT64_MAX); vkResetFences(Instance::GetDevice(), 1, &transferFence->handle); @@ -418,7 +455,11 @@ void Application::update() { { vkResetCommandBuffer(cmdBuffer, 0); vkBeginCommandBuffer(cmdBuffer, &beginInfo); - recordComputeCommands(cmdBuffer); + + recordGrabCommands(cmdBuffer); + recordPBDCommands(cmdBuffer); + recordNormalCommands(cmdBuffer); + vkEndCommandBuffer(cmdBuffer); VkSubmitInfo submit {}; @@ -463,35 +504,74 @@ void Application::update() { } } -void Application::recordDrawCommands(VkCommandBuffer cmdBuffer) { - vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->handle); +uint32_t Application::GetGroupCount(uint32_t threads, uint32_t blockSize) { + return (threads - 1) / blockSize + 1; +} - VkBuffer buffers[] = {vertexBuffers[currentDrawVertexBuffer]->handle}; - VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(cmdBuffer, 0, 1, buffers, offsets); - vkCmdBindIndexBuffer(cmdBuffer, faceBuffer->handle, 0, VK_INDEX_TYPE_UINT32); - vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::WORLD], 0, nullptr); +void Application::recordGrabCommands(VkCommandBuffer cmdBuffer) { + VkMemoryBarrier barrier {}; + barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - for (const auto &softBody : softBodies){ - vkCmdDrawIndexed(cmdBuffer, softBody->faces.size() * 3, 1, softBody->firstIndex, 0, 0); + // TODO maybe add buffermemorybarrier for camera uniform, because it can be changed from main drawing thread + + vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, grabPipeline->handle); + vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, grabPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr); + vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, grabPipeline->layout, 1, 1, &descriptorPool->sets[DescriptorSet::WORLD], 0, nullptr); + vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, grabPipeline->layout, 2, 1, &descriptorPool->sets[DescriptorSet::SIMULATION], 0, nullptr); + + GrabPushConstants pushConstants {}; + + if (grabber->started()){ + pushConstants.state = 0; + pushConstants.screenPosition = grabber->previousCursorPosition; + vkCmdPushConstants(cmdBuffer, grabPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(GrabPushConstants), &pushConstants); + + uint32_t faceInvocations = GetGroupCount(faceBuffer->size / sizeof(Face), BLOCK_SIZE_GRAB); + + vkCmdDispatch(cmdBuffer, faceInvocations, 1, 1); + + vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, + 0, nullptr, 0, nullptr); + + pushConstants.state = 1; + vkCmdPushConstants(cmdBuffer, grabPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(GrabPushConstants), &pushConstants); + vkCmdDispatch(cmdBuffer, 1, 1, 1); } -} -void Application::recordComputeCommands(VkCommandBuffer cmdBuffer) { -#define BlOCK_SIZE 32 + vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, + 0, nullptr, 0, nullptr); - auto getGroupCount = [](uint32_t threads, uint32_t blockSize){ - return (threads - 1) / blockSize + 1; - }; + glm::vec2 screenDelta; + if (grabber->moved(screenDelta)){ + pushConstants.state = 2; + pushConstants.screenDelta = screenDelta; + vkCmdPushConstants(cmdBuffer, grabPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(GrabPushConstants), &pushConstants); + vkCmdDispatch(cmdBuffer, 1, 1, 1); + } - uint32_t vertexGroupCount = getGroupCount(vertexBuffers[1 - currentDrawVertexBuffer]->size / sizeof(Vertex), BlOCK_SIZE); - uint32_t faceGroupCount = getGroupCount(faceBuffer->size / sizeof(Face), BlOCK_SIZE); + vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, + 0, nullptr, 0, nullptr); + + if (grabber->stopped()){ + pushConstants.state = 3; + vkCmdPushConstants(cmdBuffer, grabPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(GrabPushConstants), &pushConstants); + vkCmdDispatch(cmdBuffer, 1, 1, 1); + } + vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, + 0, nullptr, 0, nullptr); +} + +void Application::recordPBDCommands(VkCommandBuffer cmdBuffer) { VkMemoryBarrier barrier {}; barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + uint32_t vertexGroupCount = GetGroupCount(vertexBuffers[1 - currentDrawVertexBuffer]->size / sizeof(Vertex), BLOCK_SIZE_PBD); + vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->handle); vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr); vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->layout, 1, 1, &descriptorPool->sets[DescriptorSet::SIMULATION], 0, nullptr); @@ -520,7 +600,7 @@ void Application::recordComputeCommands(VkCommandBuffer cmdBuffer) { offsetof(PBDPushData, edgePartition), sizeof(partitions), partitions); - uint32_t invocations = getGroupCount(edgePartition.size + tetrahedronPartition.size, BlOCK_SIZE); + uint32_t invocations = GetGroupCount(edgePartition.size + tetrahedronPartition.size, BLOCK_SIZE_PBD); vkCmdDispatch(cmdBuffer, invocations, 1, 1); vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); @@ -531,12 +611,21 @@ void Application::recordComputeCommands(VkCommandBuffer cmdBuffer) { vkCmdDispatch(cmdBuffer, vertexGroupCount, 1, 1); vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); } +} + +void Application::recordNormalCommands(VkCommandBuffer cmdBuffer) { + VkMemoryBarrier barrier {}; + barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + + uint32_t vertexGroupCount = GetGroupCount(vertexBuffers[1 - currentDrawVertexBuffer]->size / sizeof(Vertex), BLOCK_SIZE_NORMAL); + uint32_t faceGroupCount = GetGroupCount(faceBuffer->size / sizeof(Face), BLOCK_SIZE_NORMAL); vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->handle); vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr); - - state = 0; + uint32_t state = 0; vkCmdPushConstants(cmdBuffer, normalPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(uint32_t), &state); vkCmdDispatch(cmdBuffer, vertexGroupCount, 1, 1); vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); @@ -557,4 +646,3 @@ void Application::recordComputeCommands(VkCommandBuffer cmdBuffer) { - diff --git a/src/camera.cpp b/src/camera.cpp index 534862d..a5efd7f 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -33,6 +33,10 @@ glm::mat4 Camera::projection() const { return glm::perspective(glm::radians(fov), aspect, near, far); } +glm::vec2 Camera::viewport() const { + return glm::vec2(static_cast(extent.width), static_cast(extent.height)); +} + glm::vec3 Camera::localToWorld(const glm::vec3& direction) const { float x = glm::sin(phi) * glm::cos(theta); float y = glm::sin(theta); @@ -58,3 +62,127 @@ void Camera::mouseMoved(const glm::vec2 &delta) { float margin = 0.01; theta = glm::clamp(theta, -glm::half_pi() + margin, glm::half_pi() - margin); } + +/* + * Vector3d Camera::toNDC(const Vector3d &pWorld) const { + Matrix4d VP = getProjection() * getView(); + return (VP * pWorld.homogeneous()).hnormalized(); +} + +Vector3d Camera::toWorld(const Vector3d &ndcCube) const { + Matrix4d VPinv = (getProjection() * getView()).inverse(); + return (VPinv * ndcCube.homogeneous()).hnormalized(); +} + +Ray Camera::rayForward(const Vector2d &screen) const { + Vector2d ndc = {(screen.x() / viewport.width() * 2) - 1, (2 - (screen.y() / viewport.height()) * 2) - 1}; + + Vector3d a, b; + a.head(2) = b.head(2) = ndc; + a(2) = -1; // near + b(2) = 1; // far + + Vector3d p1 = toWorld(a); + Vector3d p2 = toWorld(b); + + return {p1, (p2 - p1).normalized()}; +} + +Vector3d Camera::movePoint(const Vector3d &p, const Vector2d& pixelDelta) const { + Vector3d ndcDelta = {(pixelDelta.x() / viewport.width() * 2), -(pixelDelta.y() / viewport.height()) * 2, 0}; + + Vector3d ndc = toNDC(p); + Vector3d ndc2 = ndc + ndcDelta; + + Vector3d p2 = toWorld(ndc2); + + return p2 - p; +} + */ + +/* + * bool SoftBody::testRay(const Ray &ray, RayHit& rayHit) { + + GLfloat* gpuData; +#if USE_GPU + glBindBuffer(GL_SHADER_STORAGE_BUFFER, VBO); + gpuData = static_cast(glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY)); +#endif + + std::vector validResults; + for (size_t triangleId = 0; triangleId < outerFaces.size(); triangleId++){ + Face f = outerFaces[triangleId]; + Vector3d a = vertices[f.a].p; + Vector3d b = vertices[f.b].p; + Vector3d c = vertices[f.c].p; + +#if USE_GPU + a = Vector3f( + gpuData[f.a * GL_VERTEX_SIZE + 0], + gpuData[f.a * GL_VERTEX_SIZE + 1], + gpuData[f.a * GL_VERTEX_SIZE + 2]).cast(); + b = Vector3f( + gpuData[f.b * GL_VERTEX_SIZE + 0], + gpuData[f.b * GL_VERTEX_SIZE + 1], + gpuData[f.b * GL_VERTEX_SIZE + 2]).cast(); + c = Vector3f( + gpuData[f.c * GL_VERTEX_SIZE + 0], + gpuData[f.c * GL_VERTEX_SIZE + 1], + gpuData[f.c * GL_VERTEX_SIZE + 2]).cast(); +#endif + + Vector3d ab = b - a; + Vector3d ac = c - a; + * + * Line G: x = rayOrigin + r * rayDirection + * Plane A: (x - a) * n = 0 + * Intersection point q between G and A + * + * 0 = (x - a) * n = (o + r * d - a) * n = o * n + r * d * n - a * n + * <=> 0 = o * n + r * d * n - a * n + * <=> r * d * n = a * n - o * n = (a - o) * n + * <=> r = ((a - o) * n) / (d * n) + * q = o + r * d + * + * Select nearest point of triangle to q + * + * + * + +Vector3d n = ab.cross(ac); +double r = (a - ray.origin).dot(n) / ray.direction.dot(n); +Vector3d q = ray.origin + r * ray.direction; + +// check if q is inside triangle +// https://math.stackexchange.com/questions/4322/check-whether-a-point-is-within-a-3d-triangle + +Vector3d qa = a - q; +Vector3d qb = b - q; +Vector3d qc = c - q; + +double area = ab.cross(ac).norm() / 2; +double alpha = (qb).cross(qc).norm() / (2 * area); +double beta = (qc).cross(qa).norm() / (2 * area); +double gamma = (qa).cross(qb).norm() / (2 * area); + +bool isOne = std::abs(alpha + beta + gamma - 1) < 0.00001; + +if (alpha >= 0 && alpha <= 1 && beta >= 0 && beta <= 1 && gamma >= 0 && gamma <= 1 && isOne){ + +// find vertex nearest to q +size_t vId; +if (qa.norm() < qb.norm()){ +if (qa.norm() < qc.norm()) +vId = f.a; +else +vId = f.c; +} else if (qb.norm() < qc.norm()) +vId = f.b; +else +vId = f.c; + +validResults.push_back(RayHit(r, q, triangleId, vId)); +} + +} + */ diff --git a/src/grabber.cpp b/src/grabber.cpp new file mode 100644 index 0000000..208e8d5 --- /dev/null +++ b/src/grabber.cpp @@ -0,0 +1,44 @@ +#include "grabber.hpp" + +void Grabber::mouseButtonPressed(int button) { + if (button != GLFW_MOUSE_BUTTON_LEFT) + return; + + start = true; + previousCursorPosition = Input::instance->currentCursorPosition; +} + +void Grabber::mouseButtonReleased(int button) { + if (button != GLFW_MOUSE_BUTTON_LEFT) + return; + + stop = true; +} + +bool Grabber::started() { + if (start){ + start = false; + return true; + } + return false; +} + +bool Grabber::stopped() { + if (stop){ + stop = false; + return true; + } + return false; +} + +bool Grabber::moved(glm::vec2 &delta) { + if (!Input::MouseButtonIsDown[GLFW_MOUSE_BUTTON_LEFT]) + return false; + + glm::vec2 currentCursorPosition = Input::instance->currentCursorPosition; + if (previousCursorPosition == currentCursorPosition) + return false; + delta = currentCursorPosition - previousCursorPosition; + previousCursorPosition = currentCursorPosition; + return true; +} diff --git a/src/vulkan/descriptor_pool.cpp b/src/vulkan/descriptor_pool.cpp index 0fa7b74..bfe1eca 100644 --- a/src/vulkan/descriptor_pool.cpp +++ b/src/vulkan/descriptor_pool.cpp @@ -29,28 +29,27 @@ DescriptorPool::DescriptorPool() { }; // camera - addBinding(DescriptorSet::WORLD, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT); + addBinding(DescriptorSet::WORLD, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT); + // lights + addBinding(DescriptorSet::WORLD, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT); // vertices addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); - // faces addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); - // edges addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); - // triangles addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); - // tetrahedra addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); - // sizes addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); // simulation properties addBinding(DescriptorSet::SIMULATION, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); + // grab information + addBinding(DescriptorSet::SIMULATION, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); for (const auto &[set, bindings] : setBindings) createLayout(set, bindings);