added grabbing with left click

feature/softbody-runtime-control
Benjamin Kraft 3 months ago
parent b44339ea14
commit 6ffe08a013
  1. 3
      CMakeLists.txt
  2. 25
      include/application.hpp
  3. 1
      include/camera.hpp
  4. 18
      include/grabber.hpp
  5. 2
      include/input.hpp
  6. 7
      include/vulkan/descriptor_pool.hpp
  7. 6
      include/vulkan/pipeline.hpp
  8. 1
      shaders/compile.sh
  9. 180
      shaders/grab.comp
  10. 6
      shaders/shader.vert
  11. 164
      src/application.cpp
  12. 128
      src/camera.cpp
  13. 44
      src/grabber.cpp
  14. 11
      src/vulkan/descriptor_pool.cpp

@ -24,4 +24,7 @@ target_include_directories(VulkanSimulation PRIVATE include)
target_compile_definitions(VulkanSimulation PRIVATE target_compile_definitions(VulkanSimulation PRIVATE
GLM_FORCE_RADIANS GLM_FORCE_RADIANS
GLM_FORCE_DEPTH_ZERO_TO_ONE GLM_FORCE_DEPTH_ZERO_TO_ONE
BLOCK_SIZE_GRAB=32
BLOCK_SIZE_PBD=32
BLOCK_SIZE_NORMAL=32
) )

@ -16,6 +16,7 @@
#include <map> #include <map>
#include <glm/vec2.hpp> #include <glm/vec2.hpp>
#include "constraints.hpp" #include "constraints.hpp"
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
using std::unique_ptr, std::make_unique; using std::unique_ptr, std::make_unique;
@ -33,6 +34,7 @@ class Fence;
class Semaphore; class Semaphore;
class Camera; class Camera;
class DescriptorPool; class DescriptorPool;
class Grabber;
class Application { class Application {
public: public:
@ -54,9 +56,17 @@ private:
unique_ptr<Swapchain> swapchain; unique_ptr<Swapchain> swapchain;
unique_ptr<DescriptorPool> descriptorPool; unique_ptr<DescriptorPool> descriptorPool;
unique_ptr<GraphicsPipeline> graphicsPipeline; unique_ptr<GraphicsPipeline> graphicsPipeline;
unique_ptr<Buffer> uniformBuffer;
struct CameraUniformData {
glm::mat4 view;
glm::mat4 projection;
glm::vec2 viewport;
};
unique_ptr<Buffer> cameraUniformBuffer;
unique_ptr<Camera> camera; unique_ptr<Camera> camera;
unique_ptr<Grabber> grabber;
unique_ptr<Buffer> grabBuffer;
void createMeshBuffers(); void createMeshBuffers();
size_t currentDrawVertexBuffer = 0; size_t currentDrawVertexBuffer = 0;
@ -86,7 +96,14 @@ private:
unique_ptr<Buffer> propertiesBuffer; unique_ptr<Buffer> propertiesBuffer;
Properties properties {}; Properties properties {};
struct GrabPushConstants {
uint32_t state;
alignas(8) glm::vec2 screenPosition;
glm::vec2 screenDelta;
};
void createComputePipelines(); void createComputePipelines();
unique_ptr<ComputePipeline> grabPipeline;
unique_ptr<ComputePipeline> pbdPipeline; unique_ptr<ComputePipeline> pbdPipeline;
unique_ptr<ComputePipeline> normalPipeline; unique_ptr<ComputePipeline> normalPipeline;
@ -94,7 +111,9 @@ private:
void recordDrawCommands(VkCommandBuffer cmdBuffer); void recordDrawCommands(VkCommandBuffer cmdBuffer);
void drawFrame(); void drawFrame();
void recordComputeCommands(VkCommandBuffer cmdBuffer); void recordGrabCommands(VkCommandBuffer cmdBuffer);
void recordPBDCommands(VkCommandBuffer cmdBuffer);
void recordNormalCommands(VkCommandBuffer cmdBuffer);
struct PBDPushData { struct PBDPushData {
uint32_t state; uint32_t state;
ConstraintData::Partition edgePartition; ConstraintData::Partition edgePartition;
@ -102,4 +121,6 @@ private:
}; };
void update(); void update();
static uint32_t GetGroupCount(uint32_t threads, uint32_t blockSize);
}; };

@ -22,6 +22,7 @@ public:
void update(float dt); void update(float dt);
glm::mat4 view() const; glm::mat4 view() const;
glm::mat4 projection() const; glm::mat4 projection() const;
glm::vec2 viewport() const;
glm::vec3 localToWorld(const glm::vec3& direction) const; glm::vec3 localToWorld(const glm::vec3& direction) const;
protected: protected:
void mouseMoved(const glm::vec2 &delta) override; void mouseMoved(const glm::vec2 &delta) override;

@ -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;
};

@ -16,6 +16,7 @@ public:
static Input* instance; static Input* instance;
static std::map<int, bool> KeyIsDown; static std::map<int, bool> KeyIsDown;
static std::map<int, bool> MouseButtonIsDown; static std::map<int, bool> MouseButtonIsDown;
glm::vec2 currentCursorPosition {};
private: private:
GLFWwindow* window; GLFWwindow* window;
std::set<Listener*> listeners; std::set<Listener*> listeners;
@ -26,7 +27,6 @@ private:
void mouseButtonPressed(int button); void mouseButtonPressed(int button);
void mouseButtonReleased(int button); void mouseButtonReleased(int button);
void mouseMoved(const glm::vec2& newCursorPosition); void mouseMoved(const glm::vec2& newCursorPosition);
glm::vec2 currentCursorPosition;
}; };
class Listener { class Listener {

@ -7,9 +7,10 @@
class Buffer; class Buffer;
enum class DescriptorSet { enum class DescriptorSet {
WORLD = 0, WORLD,
MESH = 1, SIMULATION,
SIMULATION = 2 MESH
}; };
class DescriptorPool { class DescriptorPool {

@ -5,12 +5,6 @@
class Instance; class Instance;
struct UniformBufferObject {
alignas(16) glm::mat4 model;
glm::mat4 view;
glm::mat4 projection;
};
class Pipeline { class Pipeline {
public: public:
VkPipeline handle = VK_NULL_HANDLE; VkPipeline handle = VK_NULL_HANDLE;

@ -3,3 +3,4 @@ glslc shader.vert -o vert.spv
glslc shader.frag -o frag.spv glslc shader.frag -o frag.spv
glslc pbd.comp -o pbd.spv glslc pbd.comp -o pbd.spv
glslc normal.comp -o normal.spv glslc normal.comp -o normal.spv
glslc grab.comp -o grab.spv

@ -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;
}
}

@ -10,13 +10,13 @@ layout (location = 1) out vec2 uv;
layout (location = 2) out vec3 normal; layout (location = 2) out vec3 normal;
layout (set = 0, binding = 0) uniform UniformBufferObject { layout (set = 0, binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view; mat4 view;
mat4 projection; mat4 projection;
} ubo; vec2 viewport;
} camera;
void main() { 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; color = inColor;
normal = inNormal; normal = inNormal;
uv = inUV; uv = inUV;

@ -13,6 +13,7 @@
#include "mesh.hpp" #include "mesh.hpp"
#include "constraints.hpp" #include "constraints.hpp"
#include "timer.hpp" #include "timer.hpp"
#include "grabber.hpp"
Application::Application() { Application::Application() {
createSyncObjects(); createSyncObjects();
@ -22,16 +23,27 @@ Application::Application() {
swapchain->renderPass, swapchain->renderPass,
{descriptorPool->layouts[DescriptorSet::WORLD]})); {descriptorPool->layouts[DescriptorSet::WORLD]}));
VkDeviceSize bufferSize = sizeof(UniformBufferObject); VkDeviceSize bufferSize = sizeof(CameraUniformData);
uniformBuffer = make_unique<Buffer>(bufferSize, cameraUniformBuffer = make_unique<Buffer>(bufferSize,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); 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<Camera>(swapchain->extent); camera = make_unique<Camera>(swapchain->extent);
struct GrabInformation {
float originalInverseMass;
uint32_t vID;
float distanceToFace;
bool grabbing;
} initialGrabInformation {};
initialGrabInformation.distanceToFace = 1e20;
grabBuffer = make_unique<Buffer>(sizeof(GrabInformation), &initialGrabInformation, sizeof(GrabInformation),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
grabber = make_unique<Grabber>();
createMeshBuffers(); createMeshBuffers();
SizeInformation sizeInformation {}; SizeInformation sizeInformation {};
@ -60,6 +72,7 @@ Application::Application() {
descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5); descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5);
descriptorPool->bindBuffer(*propertiesBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::SIMULATION, 0); descriptorPool->bindBuffer(*propertiesBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::SIMULATION, 0);
descriptorPool->bindBuffer(*grabBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::SIMULATION, 1);
createComputePipelines(); createComputePipelines();
@ -77,8 +90,6 @@ using namespace std::chrono;
void Application::mainLoop() { void Application::mainLoop() {
std::future compute = std::async(std::launch::async, [this](){ std::future compute = std::async(std::launch::async, [this](){
while (!glfwWindowShouldClose(Instance::instance->window)){ while (!glfwWindowShouldClose(Instance::instance->window)){
Timer timer;
auto t1 = system_clock::now(); auto t1 = system_clock::now();
update(); update();
auto t2 = system_clock::now(); auto t2 = system_clock::now();
@ -233,6 +244,21 @@ void Application::createComputePipelines() {
vector<VkDescriptorSetLayout> layouts; vector<VkDescriptorSetLayout> layouts;
vector<VkPushConstantRange> pushRanges; vector<VkPushConstantRange> 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<ComputePipeline>(new ComputePipeline("shaders/grab.spv", layouts, pushRanges));
}
layouts.clear();
pushRanges.clear();
{ {
layouts.push_back(descriptorPool->layouts[DescriptorSet::MESH]); layouts.push_back(descriptorPool->layouts[DescriptorSet::MESH]);
layouts.push_back(descriptorPool->layouts[DescriptorSet::SIMULATION]); layouts.push_back(descriptorPool->layouts[DescriptorSet::SIMULATION]);
@ -265,21 +291,18 @@ void Application::updateUniformBuffer() {
elapsed += 0.007; elapsed += 0.007;
UniformBufferObject ubo {}; CameraUniformData ubo {};
ubo.model = glm::mat4(1);
ubo.view = camera->view(); ubo.view = camera->view();
ubo.projection = camera->projection(); ubo.projection = camera->projection();
ubo.projection[1][1] *= -1; 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 {}; vmaFlushAllocation(Instance::GetAllocator(),
mappedMemoryRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; cameraUniformBuffer->allocation,
mappedMemoryRange.offset = uniformBuffer->allocationInfo.offset; cameraUniformBuffer->allocationInfo.offset,
mappedMemoryRange.size = uniformBuffer->allocationInfo.size; cameraUniformBuffer->allocationInfo.size);
mappedMemoryRange.memory = uniformBuffer->allocationInfo.deviceMemory;
vkFlushMappedMemoryRanges(Instance::GetDevice(), 1, &mappedMemoryRange);
} }
void Application::drawFrame() { void Application::drawFrame() {
@ -319,9 +342,9 @@ void Application::drawFrame() {
VkBufferMemoryBarrier uniformBufferBarrier {}; VkBufferMemoryBarrier uniformBufferBarrier {};
uniformBufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; uniformBufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
uniformBufferBarrier.size = uniformBuffer->size; uniformBufferBarrier.size = cameraUniformBuffer->size;
uniformBufferBarrier.offset = 0; uniformBufferBarrier.offset = 0;
uniformBufferBarrier.buffer = uniformBuffer->handle; uniformBufferBarrier.buffer = cameraUniformBuffer->handle;
uniformBufferBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; uniformBufferBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
uniformBufferBarrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_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() { void Application::update() {
vkWaitForFences(Instance::GetDevice(), 1, &transferFence->handle, VK_TRUE, UINT64_MAX); vkWaitForFences(Instance::GetDevice(), 1, &transferFence->handle, VK_TRUE, UINT64_MAX);
vkResetFences(Instance::GetDevice(), 1, &transferFence->handle); vkResetFences(Instance::GetDevice(), 1, &transferFence->handle);
@ -418,7 +455,11 @@ void Application::update() {
{ {
vkResetCommandBuffer(cmdBuffer, 0); vkResetCommandBuffer(cmdBuffer, 0);
vkBeginCommandBuffer(cmdBuffer, &beginInfo); vkBeginCommandBuffer(cmdBuffer, &beginInfo);
recordComputeCommands(cmdBuffer);
recordGrabCommands(cmdBuffer);
recordPBDCommands(cmdBuffer);
recordNormalCommands(cmdBuffer);
vkEndCommandBuffer(cmdBuffer); vkEndCommandBuffer(cmdBuffer);
VkSubmitInfo submit {}; VkSubmitInfo submit {};
@ -463,35 +504,74 @@ void Application::update() {
} }
} }
void Application::recordDrawCommands(VkCommandBuffer cmdBuffer) { uint32_t Application::GetGroupCount(uint32_t threads, uint32_t blockSize) {
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->handle); return (threads - 1) / blockSize + 1;
}
VkBuffer buffers[] = {vertexBuffers[currentDrawVertexBuffer]->handle}; void Application::recordGrabCommands(VkCommandBuffer cmdBuffer) {
VkDeviceSize offsets[] = {0}; VkMemoryBarrier barrier {};
vkCmdBindVertexBuffers(cmdBuffer, 0, 1, buffers, offsets); barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
vkCmdBindIndexBuffer(cmdBuffer, faceBuffer->handle, 0, VK_INDEX_TYPE_UINT32); barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::WORLD], 0, nullptr); barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
for (const auto &softBody : softBodies){ // TODO maybe add buffermemorybarrier for camera uniform, because it can be changed from main drawing thread
vkCmdDrawIndexed(cmdBuffer, softBody->faces.size() * 3, 1, softBody->firstIndex, 0, 0);
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);
} }
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier,
0, nullptr, 0, nullptr);
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);
} }
void Application::recordComputeCommands(VkCommandBuffer cmdBuffer) { vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier,
#define BlOCK_SIZE 32 0, nullptr, 0, nullptr);
auto getGroupCount = [](uint32_t threads, uint32_t blockSize){ if (grabber->stopped()){
return (threads - 1) / blockSize + 1; pushConstants.state = 3;
}; 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); vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier,
uint32_t faceGroupCount = getGroupCount(faceBuffer->size / sizeof(Face), BlOCK_SIZE); 0, nullptr, 0, nullptr);
}
void Application::recordPBDCommands(VkCommandBuffer cmdBuffer) {
VkMemoryBarrier barrier {}; VkMemoryBarrier barrier {};
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | 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); 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, 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); 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), offsetof(PBDPushData, edgePartition),
sizeof(partitions), partitions); 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); 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); 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); 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); 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); 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); vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr);
uint32_t state = 0;
state = 0;
vkCmdPushConstants(cmdBuffer, normalPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(uint32_t), &state); vkCmdPushConstants(cmdBuffer, normalPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(uint32_t), &state);
vkCmdDispatch(cmdBuffer, vertexGroupCount, 1, 1); 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); 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) {

@ -33,6 +33,10 @@ glm::mat4 Camera::projection() const {
return glm::perspective(glm::radians(fov), aspect, near, far); return glm::perspective(glm::radians(fov), aspect, near, far);
} }
glm::vec2 Camera::viewport() const {
return glm::vec2(static_cast<float>(extent.width), static_cast<float>(extent.height));
}
glm::vec3 Camera::localToWorld(const glm::vec3& direction) const { glm::vec3 Camera::localToWorld(const glm::vec3& direction) const {
float x = glm::sin(phi) * glm::cos(theta); float x = glm::sin(phi) * glm::cos(theta);
float y = glm::sin(theta); float y = glm::sin(theta);
@ -58,3 +62,127 @@ void Camera::mouseMoved(const glm::vec2 &delta) {
float margin = 0.01; float margin = 0.01;
theta = glm::clamp(theta, -glm::half_pi<float>() + margin, glm::half_pi<float>() - margin); theta = glm::clamp(theta, -glm::half_pi<float>() + margin, glm::half_pi<float>() - 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<GLfloat*>(glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY));
#endif
std::vector<RayHit> 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<double>();
b = Vector3f(
gpuData[f.b * GL_VERTEX_SIZE + 0],
gpuData[f.b * GL_VERTEX_SIZE + 1],
gpuData[f.b * GL_VERTEX_SIZE + 2]).cast<double>();
c = Vector3f(
gpuData[f.c * GL_VERTEX_SIZE + 0],
gpuData[f.c * GL_VERTEX_SIZE + 1],
gpuData[f.c * GL_VERTEX_SIZE + 2]).cast<double>();
#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));
}
}
*/

@ -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;
}

@ -29,28 +29,27 @@ DescriptorPool::DescriptorPool() {
}; };
// camera // 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 // vertices
addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
// faces // faces
addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
// edges // edges
addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
// triangles // triangles
addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
// tetrahedra // tetrahedra
addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
// sizes // sizes
addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
// simulation properties // simulation properties
addBinding(DescriptorSet::SIMULATION, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); 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) for (const auto &[set, bindings] : setBindings)
createLayout(set, bindings); createLayout(set, bindings);

Loading…
Cancel
Save