Compare commits

...

4 Commits

  1. 18
      imgui.ini
  2. 28
      include/application.hpp
  3. 1
      include/constraints.hpp
  4. 12
      include/fixed_list.hpp
  5. 2
      include/soft_body.hpp
  6. 30
      include/vulkan/buffer.hpp
  7. 2024
      models/icosphere.ply
  8. 2021
      models/icosphere_medium.ply
  9. BIN
      models/vulkanscene.blend
  10. 1
      shaders/compile.sh
  11. 230
      src/application.cpp
  12. 33
      src/constraints.cpp
  13. 17
      src/fixed_list.cpp
  14. 2
      src/soft_body.cpp
  15. 102
      src/vulkan/buffer.cpp

@ -29,17 +29,25 @@ Size=249,166
Collapsed=0
[Window][Performance]
Pos=1617,2
Size=302,1002
Pos=1716,2
Size=203,345
Collapsed=0
DockId=0x00000001,0
DockId=0x00000002,0
[Window][Performance 2]
Pos=1617,2
Size=302,1002
Collapsed=0
DockId=0x00000001,1
DockId=0x00000002,1
[Window][Scene]
Pos=1716,349
Size=203,655
Collapsed=0
DockId=0x00000004,0
[Docking][Data]
DockNode ID=0x00000001 Pos=1617,2 Size=302,1002 Selected=0x60B79D0E
DockNode ID=0x00000001 Pos=1716,2 Size=203,1002 Split=Y Selected=0x60B79D0E
DockNode ID=0x00000002 Parent=0x00000001 SizeRef=203,345 Selected=0x60B79D0E
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=203,655 Selected=0xE192E354

@ -16,11 +16,14 @@
#include <map>
#include <glm/vec2.hpp>
#include "constraints.hpp"
#include "fixed_list.hpp"
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>
#include <list>
using std::unique_ptr, std::make_unique;
using std::vector;
using std::optional;
class SoftBody;
class Instance;
@ -35,6 +38,7 @@ class Semaphore;
class Camera;
class DescriptorPool;
class Grabber;
struct SizesUniformData;
class Application {
public:
@ -44,10 +48,12 @@ public:
private:
void imGuiWindows();
struct PerformanceInformation {
float totalUpdateDuration;
static const size_t saves = 30;
FixedList recentTotalUpdateDurations = FixedList(saves);
float updateDuration;
float frameDuration;
} performanceInformation {};
FixedList recentFrameDurations = FixedList(saves);
} performanceInformation;
void createSyncObjects();
@ -71,17 +77,21 @@ private:
unique_ptr<Grabber> grabber;
unique_ptr<Buffer> grabBuffer;
void createMeshBuffers();
void addSoftBody(const std::string& modelFile, size_t count=1);
void removeSoftBody(const unique_ptr<SoftBody>& softBody);
void updateConstraintBuffers(VkCommandBuffer commandBuffer);
size_t currentDrawVertexBuffer = 0;
unique_ptr<Buffer> vertexBuffers[2];
unique_ptr<Buffer> faceBuffer;
unique_ptr<Buffer> edgeBuffer;
unique_ptr<Buffer> triangleBuffer;
unique_ptr<Buffer> tetrahedronBuffer;
optional<unique_ptr<Buffer>> vertexBuffers[2];
optional<unique_ptr<Buffer>> faceBuffer;
optional<unique_ptr<Buffer>> edgeBuffer;
optional<unique_ptr<Buffer>> triangleBuffer;
optional<unique_ptr<Buffer>> tetrahedronBuffer;
ConstraintData constraintData {};
vector<unique_ptr<SoftBody>> softBodies;
unique_ptr<Buffer> sizeInformationBuffer;
SizesUniformData *sizeInformation = nullptr;
unique_ptr<Buffer> simulationPropertiesBuffer;

@ -51,6 +51,7 @@ struct ConstraintData {
void recordNewPartition();
void writePartitionInformation();
void insert(const ConstraintData& other);
private:
uint32_t prePartitionEdgeCount;
uint32_t prePartitionTetrahedronCount;

@ -0,0 +1,12 @@
#pragma once
#include <list>
#include <cstddef>
class FixedList : private std::list<float> {
size_t maxSize;
public:
explicit FixedList(size_t maxSize);
void push(float value);
float average() const;
};

@ -28,7 +28,7 @@ public:
vector<Face> faces;
ConstraintData constraintData;
void applyVertexOffset(const glm::vec3& offset);
void applyVertexWorldOffset(const glm::vec3& offset);
SoftBody& operator =(const SoftBody& other) = delete;
private:

@ -4,27 +4,45 @@
#include <stdexcept>
#include "vertex.hpp"
#include "vk_mem_alloc.h"
#include <memory>
#include <optional>
using std::unique_ptr;
using std::shared_ptr;
using std::make_shared;
using std::make_unique;
using std::optional;
class Image;
class Buffer {
public:
explicit Buffer(VkDeviceSize bufferSize, VkBufferUsageFlags bufferUsage,
Buffer(VkDeviceSize bufferSize, VkBufferUsageFlags bufferUsage,
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags vmaAllocationFlags);
explicit Buffer(VkDeviceSize bufferSize, void* initialData, VkDeviceSize initialDataSize, VkBufferUsageFlags bufferUsage,
Buffer(VkDeviceSize bufferSize, void* initialData, VkDeviceSize initialDataSize, VkBufferUsageFlags bufferUsage,
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags vmaAllocationFlags);
~Buffer();
static unique_ptr<Buffer> Append(const Buffer& old, void* data, VkDeviceSize size, VkCommandBuffer commandBuffer=VK_NULL_HANDLE);
static unique_ptr<Buffer> Replace(const Buffer& old, void* data, VkDeviceSize size, VkCommandBuffer commandBuffer=VK_NULL_HANDLE);
virtual ~Buffer();
VkBuffer handle = VK_NULL_HANDLE;
VmaAllocation allocation = VK_NULL_HANDLE;
VmaAllocationInfo allocationInfo {};
VkDeviceSize size;
void setName(const std::string& name);
void setName(const std::string& newName);
template <typename T>
T& access(){
return *reinterpret_cast<T*>(allocationInfo.pMappedData);
}
void copyTo(Buffer* buffer) const;
void copyTo(Image* image) const;
void setData(void* data, VkDeviceSize offset, VkDeviceSize size, VkCommandBuffer commandBuffer=VK_NULL_HANDLE);
shared_ptr<Buffer> getStagingBuffer();
Buffer(const Buffer& other) = delete;
Buffer& operator =(const Buffer& other) = delete;
void copyTo(Buffer* buffer);
void copyTo(Image* image);
private:
optional<shared_ptr<Buffer>> stagingBufferOptional;
std::string name;
VkBufferUsageFlags bufferUsageFlags;
VmaMemoryUsage memoryUsage;
VmaAllocationCreateFlags allocationCreateFlags;
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

@ -1,4 +1,3 @@
#!/usr/bin/env bash
glslc shader.vert -o vert.spv
glslc shader.frag -o frag.spv
glslc --target-env=vulkan1.1 pbd.comp -o pbd.spv

@ -20,6 +20,7 @@
#include "imgui.h"
#include "imgui/backends/imgui_impl_vulkan.h"
#include "imgui/backends/imgui_impl_glfw.h"
#include "fixed_list.hpp"
using namespace std::chrono;
@ -85,17 +86,15 @@ Application::Application() {
grabBuffer->setName("Grab");
grabber = make_unique<Grabber>();
createMeshBuffers();
SizesUniformData sizeInformation {};
sizeInformation.vertexCount = vertexBuffers[0]->size / sizeof(Vertex);
sizeInformation.faceCount = faceBuffer->size / sizeof(Face);
sizeInformationBuffer = make_unique<Buffer>(
sizeof(SizesUniformData), &sizeInformation, sizeof(sizeInformation),
sizeof(SizesUniformData),
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT);
sizeInformationBuffer->setName("Sizes");
sizeInformation = &sizeInformationBuffer->access<SizesUniformData>();
addSoftBody("models/bunny_medium.ply");
SimulationUniformData simulationUniformData {
.gravity = {0, -9.81, 0},
@ -126,7 +125,7 @@ Application::Application() {
descriptorPool->bindBuffer(*vertexBuffers[1 - currentDrawVertexBuffer], VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0);
descriptorPool->bindBuffer(*faceBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 1);
descriptorPool->bindBuffer(*edgeBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 2);
descriptorPool->bindBuffer(*triangleBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 3);
// descriptorPool->bindBuffer(*triangleBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 3);
descriptorPool->bindBuffer(*tetrahedronBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 4);
descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5);
@ -147,11 +146,12 @@ void Application::mainLoop() {
auto t2 = system_clock::now();
auto measuredUpdateDuration = duration<float>(t2 - t1);
auto requestedUpdateDuration = duration<float>(simulationPropertiesBuffer->access<SimulationUniformData>().dt);
auto requestedUpdateDuration = duration<float>(
simulationPropertiesBuffer->access<SimulationUniformData>().dt);
std::this_thread::sleep_for(requestedUpdateDuration - measuredUpdateDuration);
performanceInformation.updateDuration = measuredUpdateDuration.count();
performanceInformation.totalUpdateDuration = std::max(requestedUpdateDuration, measuredUpdateDuration).count();
performanceInformation.recentTotalUpdateDurations.push(std::max(requestedUpdateDuration, measuredUpdateDuration).count());
}
});
@ -162,7 +162,7 @@ void Application::mainLoop() {
auto t2 = system_clock::now();
float seconds = duration<float>(t2 - t1).count();
performanceInformation.frameDuration = seconds;
performanceInformation.recentFrameDurations.push(seconds);
t1 = system_clock::now();
drawFrame(seconds);
}
@ -178,132 +178,105 @@ void Application::createSyncObjects() {
computeSemaphore = make_unique<Semaphore>();
transferSemaphore = make_unique<Semaphore>();
renderFence = make_unique<Fence>(true);
computeFence = make_unique<Fence>(true);
transferFence = make_unique<Fence>(true);
computeFence = make_unique<Fence>(false);
transferFence = make_unique<Fence>(false);
}
void Application::createMeshBuffers() {
Mesh sphere("models/icosphere.ply");
Mesh bunny("models/bunny_medium.ply");
void Application::addSoftBody(const std::string &modelFile, size_t count) {
Mesh mesh(modelFile);
auto body = std::make_unique<SoftBody>(&sphere, 1.f / 60);
// Do SoftBody calculations once in constructor, will be copied from now on
auto original = std::make_unique<SoftBody>(&mesh, 1.f / 60);
for (size_t i = 0; i < 2; i++){
auto copy = std::make_unique<SoftBody>(*body.get());
copy->applyVertexOffset({i * 2, 0, 0});
softBodies.push_back(std::move(copy));
}
vector<Vertex> newVertices;
vector<Face> newFaces;
body = std::make_unique<SoftBody>(&bunny, 1.f / 10);
for (size_t i = 0; i < 2; i++){
auto copy = std::make_unique<SoftBody>(*body.get());
copy->applyVertexOffset({i * 2, 0, 2});
softBodies.push_back(std::move(copy));
}
for (size_t i = 0; i < count; i++){
// Local copy
auto softBody = std::make_unique<SoftBody>(*original.get());
vector<Vertex> vertices;
vector<Face> faces;
softBody->applyVertexWorldOffset({i * 2, 0, 0});
for (std::unique_ptr<SoftBody> &currentSoftBody : softBodies){
currentSoftBody->firstIndex = faces.size() * 3;
currentSoftBody->vertexOffset = static_cast<int32_t>(vertices.size());
// Position in face buffer
softBody->firstIndex = (sizeInformation->faceCount + newFaces.size()) * 3;
int32_t vertexOffset = currentSoftBody->vertexOffset;
// Position in vertex buffer
softBody->vertexOffset = static_cast<int32_t>(sizeInformation->vertexCount + newVertices.size());
for (auto &face : currentSoftBody->faces){
// Vertex offset added manually for easy access in Compute Shaders
{
auto vertexOffset = softBody->vertexOffset;
for (auto &face : softBody->faces){
face.a += vertexOffset;
face.b += vertexOffset;
face.c += vertexOffset;
}
for (auto &edge : currentSoftBody->constraintData.edges){
for (auto &edge : softBody->constraintData.edges){
edge.a += vertexOffset;
edge.b += vertexOffset;
}
for (auto &triangle : currentSoftBody->constraintData.triangles){
for (auto &triangle : softBody->constraintData.triangles){
triangle.a += vertexOffset;
triangle.b += vertexOffset;
triangle.c += vertexOffset;
}
for (auto &tetrahedron : currentSoftBody->constraintData.tetrahedra){
for (auto &tetrahedron : softBody->constraintData.tetrahedra){
tetrahedron.a += vertexOffset;
tetrahedron.b += vertexOffset;
tetrahedron.c += vertexOffset;
tetrahedron.d += vertexOffset;
}
vertices.insert(vertices.end(), currentSoftBody->vertices.begin(), currentSoftBody->vertices.end());
faces.insert(faces.end(), currentSoftBody->faces.begin(), currentSoftBody->faces.end());
constraintData.partitionCount = std::max(constraintData.partitionCount, currentSoftBody->constraintData.partitionCount);
auto combine = [&currentSoftBody, this] (
auto &globalIndices, auto &bodyIndices,
vector<ConstraintData::Partition> &globalPartitions, vector<ConstraintData::Partition> &bodyPartitions){
if (globalPartitions.size() < currentSoftBody->constraintData.partitionCount)
globalPartitions.resize(currentSoftBody->constraintData.partitionCount);
uint32_t offsetAdded = 0;
for (uint32_t partition = 0; partition < constraintData.partitionCount; partition++){
ConstraintData::Partition &globalPartition = globalPartitions[partition];
globalPartition.offset += offsetAdded;
if (partition < bodyPartitions.size()){
const ConstraintData::Partition &bodyPartition = bodyPartitions[partition];
auto dst = globalIndices.begin() + globalPartition.offset;
auto srcStart = bodyIndices.begin() + bodyPartition.offset;
uint32_t count = bodyPartition.size;
globalIndices.insert(dst, srcStart, srcStart + count);
globalPartition.size += count;
offsetAdded += count;
}
}
};
combine(constraintData.edges, currentSoftBody->constraintData.edges,
constraintData.edgePartitions, currentSoftBody->constraintData.edgePartitions);
// Append data to vertices and faces
newVertices.insert(newVertices.end(), softBody->vertices.begin(), softBody->vertices.end());
newFaces.insert(newFaces.end(), softBody->faces.begin(), softBody->faces.end());
combine(constraintData.tetrahedra, currentSoftBody->constraintData.tetrahedra,
constraintData.tetrahedronPartitions, currentSoftBody->constraintData.tetrahedronPartitions);
// Insert data at the right places in this->constraintData
constraintData.insert(softBody->constraintData);
constraintData.triangles.insert(constraintData.triangles.end(), currentSoftBody->constraintData.triangles.begin(), currentSoftBody->constraintData.triangles.end());
constraintData.tetrahedra.insert(constraintData.tetrahedra.end(), currentSoftBody->constraintData.tetrahedra.begin(), currentSoftBody->constraintData.tetrahedra.end());
softBodies.push_back(std::move(softBody));
}
printf("Vertices: %zu\nFaces: %zu\nEdges: %zu\nTriangles: %zu\nTetrahedra: %zu\nTotal Constraints: %zu\n",
vertices.size(), faces.size(), constraintData.edges.size(), constraintData.triangles.size(), constraintData.tetrahedra.size(),
constraintData.edges.size() + constraintData.tetrahedra.size());
sizeInformation->vertexCount += newVertices.size();
sizeInformation->faceCount += newFaces.size();
printf("Partitions: %u\n", constraintData.partitionCount);
auto commandBuffer = Instance::instance->renderingCommandPool->beginSingleTimeCommandBuffer();
vertexBuffers[0] = Buffer::Append(*vertexBuffers[0], newVertices.data(), newVertices.size() * sizeof(Vertex), commandBuffer);
vertexBuffers[1] = Buffer::Append(*vertexBuffers[1], newVertices.data(), newVertices.size() * sizeof(Vertex), commandBuffer);
faceBuffer = Buffer::Append(*faceBuffer, newFaces.data(), newFaces.size() * sizeof(Face), commandBuffer);
edgeBuffer = Buffer::Replace(*edgeBuffer, constraintData.edges.data(), constraintData.edges.size() * sizeof(Edge), commandBuffer);
// triangleBuffer = Buffer::Replace(*triangleBuffer, constraintData.triangles.data(), constraintData.triangles.size() * sizeof(Triangle), commandBuffer);
tetrahedronBuffer = Buffer::Replace(*tetrahedronBuffer, constraintData.tetrahedra.data(), constraintData.tetrahedra.size() * sizeof(Tetrahedron), commandBuffer);
class SimulationBuffer : public Buffer {
public:
SimulationBuffer(void* data, VkDeviceSize size, VkBufferUsageFlags additionalUsageFlags=0)
: Buffer(size, data, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | additionalUsageFlags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0) {}
};
vertexBuffers[0] = make_unique<SimulationBuffer>(vertices.data(), vertices.size() * sizeof(Vertex),
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
vertexBuffers[1] = make_unique<SimulationBuffer>(vertices.data(), vertices.size() * sizeof(Vertex),
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
faceBuffer = make_unique<SimulationBuffer>(faces.data(), faces.size() * sizeof(Face), VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
edgeBuffer = make_unique<SimulationBuffer>(constraintData.edges.data(), constraintData.edges.size() * sizeof(Edge));
triangleBuffer = make_unique<SimulationBuffer>(constraintData.triangles.data(), constraintData.triangles.size() * sizeof(Triangle));
tetrahedronBuffer = make_unique<SimulationBuffer>(constraintData.tetrahedra.data(), constraintData.tetrahedra.size() * sizeof(Tetrahedron));
vertexBuffers[0] = make_unique<SimulationBuffer>(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
vertexBuffers[1] = make_unique<SimulationBuffer>(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
faceBuffer = make_unique<SimulationBuffer>(VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
edgeBuffer = make_unique<SimulationBuffer>();
// triangleBuffer = make_unique<SimulationBuffer>();
tetrahedronBuffer = make_unique<SimulationBuffer>();
vertexBuffers[0]->setName("Vertices 0");
vertexBuffers[1]->setName("Vertices 1");
faceBuffer->setName("Faces");
edgeBuffer->setName("Edges");
triangleBuffer->setName("Triangles");
// triangleBuffer->setName("Triangles");
tetrahedronBuffer->setName("Tetrahedra");
VkQueue queue = Instance::instance->graphicsAndPresentQueue;
Instance::instance->renderingCommandPool->endSingleTimeCommandBuffer(commandBuffer, queue);
}
void Application::removeSoftBody(const unique_ptr<SoftBody> &softBody) {
// cpu: remove in constraintData, reduce partition sizes and offsets
// cpu: reduce firstIndex and vertexOffset in following bodies
// gpu: update constraintData
// gpu: update vertices and faces, take from remaining softbodies
// cpu: erase vector element
}
void Application::createComputePipelines() {
@ -387,7 +360,7 @@ void Application::drawFrame(float dt) {
VkBufferMemoryBarrier vertexBufferBarrier{};
vertexBufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
vertexBufferBarrier.size = vertexBuffers[currentDrawVertexBuffer]->size;
vertexBufferBarrier.size = vertexBuffers[currentDrawVertexBuffer]->allocationInfo.size;
vertexBufferBarrier.offset = 0;
vertexBufferBarrier.buffer = vertexBuffers[currentDrawVertexBuffer]->handle;
vertexBufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
@ -496,16 +469,6 @@ void Application::recordDrawCommands(VkCommandBuffer commandBuffer) {
}
void Application::update() {
vkWaitForFences(Instance::GetDevice(), 1, &computeFence->handle, VK_TRUE, UINT64_MAX);
vkResetFences(Instance::GetDevice(), 1, &computeFence->handle);
currentDrawVertexBuffer = 1 - currentDrawVertexBuffer;
vkWaitForFences(Instance::GetDevice(), 1, &transferFence->handle, VK_TRUE, UINT64_MAX);
vkResetFences(Instance::GetDevice(), 1, &transferFence->handle);
currentDrawVertexBuffer = 1 - currentDrawVertexBuffer;
VkCommandBufferBeginInfo beginInfo {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = 0;
@ -539,7 +502,7 @@ void Application::update() {
vkBeginCommandBuffer(cmdBuffer, &beginInfo);
VkBufferCopy copyRegion {};
copyRegion.size = vertexBuffers[1 - currentDrawVertexBuffer]->size;
copyRegion.size = vertexBuffers[1 - currentDrawVertexBuffer]->allocationInfo.size;
copyRegion.srcOffset = 0;
copyRegion.dstOffset = 0;
@ -561,6 +524,17 @@ void Application::update() {
vkQueueSubmit(Instance::instance->computeAndTransferQueue, 1, &submit, transferFence->handle);
submitMutex.unlock();
}
vkWaitForFences(Instance::GetDevice(), 1, &computeFence->handle, VK_TRUE, UINT64_MAX);
vkResetFences(Instance::GetDevice(), 1, &computeFence->handle);
currentDrawVertexBuffer = 1 - currentDrawVertexBuffer;
vkWaitForFences(Instance::GetDevice(), 1, &transferFence->handle, VK_TRUE, UINT64_MAX);
vkResetFences(Instance::GetDevice(), 1, &transferFence->handle);
currentDrawVertexBuffer = 1 - currentDrawVertexBuffer;
// descriptorPool->bindBuffer(*vertexBuffers[1 - currentDrawVertexBuffer], VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0);
}
uint32_t Application::GetGroupCount(uint32_t threads, uint32_t blockSize) {
@ -582,7 +556,7 @@ void Application::recordGrabCommands(VkCommandBuffer commandBuffer) {
pushConstants.screenPosition = grabber->previousCursorPosition;
vkCmdPushConstants(commandBuffer, grabPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(GrabPushData), &pushConstants);
uint32_t faceInvocations = GetGroupCount(faceBuffer->size / sizeof(Face), BLOCK_SIZE_GRAB);
uint32_t faceInvocations = GetGroupCount(sizeInformation->faceCount, BLOCK_SIZE_GRAB);
vkCmdDispatch(commandBuffer, faceInvocations, 1, 1);
computePipelineBarrier(commandBuffer);
@ -614,7 +588,7 @@ void Application::recordGrabCommands(VkCommandBuffer commandBuffer) {
}
void Application::recordPBDCommands(VkCommandBuffer commandBuffer) {
uint32_t vertexGroupCount = GetGroupCount(vertexBuffers[1 - currentDrawVertexBuffer]->size / sizeof(Vertex), BLOCK_SIZE_PBD);
uint32_t vertexGroupCount = GetGroupCount(sizeInformation->vertexCount, BLOCK_SIZE_PBD);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->handle);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr);
@ -659,8 +633,8 @@ void Application::recordPBDCommands(VkCommandBuffer commandBuffer) {
}
void Application::recordNormalCommands(VkCommandBuffer commandBuffer) {
uint32_t vertexGroupCount = GetGroupCount(vertexBuffers[1 - currentDrawVertexBuffer]->size / sizeof(Vertex), BLOCK_SIZE_NORMAL);
uint32_t faceGroupCount = GetGroupCount(faceBuffer->size / sizeof(Face), BLOCK_SIZE_NORMAL);
uint32_t vertexGroupCount = GetGroupCount(sizeInformation->vertexCount, BLOCK_SIZE_NORMAL);
uint32_t faceGroupCount = GetGroupCount(sizeInformation->faceCount, BLOCK_SIZE_NORMAL);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->handle);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr);
@ -691,7 +665,7 @@ void Application::computePipelineBarrier(VkCommandBuffer commandBuffer) {
VkBufferMemoryBarrier bufferMemoryBarrier {};
bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
bufferMemoryBarrier.buffer = buffer.handle;
bufferMemoryBarrier.size = buffer.size;
bufferMemoryBarrier.size = buffer.allocationInfo.size;
bufferMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
bufferMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
bufferMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
@ -710,10 +684,22 @@ void Application::imGuiWindows() {
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::Begin("Performance");
ImGui::Text("Update time: %f", performanceInformation.updateDuration);
ImGui::Text("Updates per second: %f", 1 / performanceInformation.totalUpdateDuration);
ImGui::Text("Frame time: %f", performanceInformation.frameDuration);
ImGui::Text("Frames per second: %f", 1 / performanceInformation.frameDuration);
ImGui::End();
ImGui::Begin("Performance"); {
float updateMS = performanceInformation.updateDuration * 1000.f;
float updateHZ = 1 / performanceInformation.recentTotalUpdateDurations.average();
ImGui::Text("Updates: %2.0fms | %.1fHz", updateMS, updateHZ);
float frameMS = performanceInformation.recentFrameDurations.average() * 1000.f;
float frameHZ = 1 / performanceInformation.recentFrameDurations.average();
ImGui::Text("Frames: %.2fms | %.1fHz", frameMS, frameHZ);
} ImGui::End();
ImGui::Begin("Scene"); {
if (ImGui::Button("Add")){
addSoftBody("models/bunny_medium.ply");
}
for (const auto &softBody: softBodies){
ImGui::Text("Some softbody");
}
} ImGui::End();
}

@ -10,6 +10,39 @@ void ConstraintData::writePartitionInformation() {
tetrahedronPartitions.emplace_back(prePartitionTetrahedronCount, tetrahedra.size() - prePartitionTetrahedronCount);
}
void ConstraintData::insert(const ConstraintData &other) {
if (other.partitionCount > partitionCount){
edgePartitions.resize(other.partitionCount);
tetrahedronPartitions.resize(other.partitionCount);
}
// insert constraints, increase partition offsets and sizes
for (size_t i = 0; i < other.partitionCount; i++){
edgePartitions[i].offset += other.edgePartitions[i].offset;
tetrahedronPartitions[i].offset += other.tetrahedronPartitions[i].offset;
auto baseEdgeInsert = other.edges.begin() + other.edgePartitions[i].offset;
edges.insert(edges.begin() + edgePartitions[i].offset + edgePartitions[i].size,
baseEdgeInsert, baseEdgeInsert + other.edgePartitions[i].size);
auto baseTetrahedronInsert = other.tetrahedra.begin() + other.tetrahedronPartitions[i].offset;
tetrahedra.insert(tetrahedra.begin() + tetrahedronPartitions[i].offset + tetrahedronPartitions[i].size,
baseTetrahedronInsert, baseTetrahedronInsert + other.tetrahedronPartitions[i].size);
edgePartitions[i].size += other.edgePartitions[i].size;
tetrahedronPartitions[i].size += other.tetrahedronPartitions[i].size;
}
// increase offsets for remaining partitions
for (size_t i = other.partitionCount; i < partitionCount; i++){
edgePartitions[i].offset += other.edgePartitions[other.partitionCount - 1].offset;
tetrahedronPartitions[i].offset += other.tetrahedronPartitions[other.partitionCount - 1].offset;
}
partitionCount = std::max(partitionCount, other.partitionCount);
}
void DistanceConstraint::writeData(ConstraintData &dataLists) const {
dataLists.edges.push_back(Edge(a, b, length, compliance));
}

@ -0,0 +1,17 @@
#include <numeric>
#include "fixed_list.hpp"
FixedList::FixedList(size_t maxSize) : std::list<float>(), maxSize(maxSize) {}
void FixedList::push(float value) {
push_back(value);
if (size() > maxSize)
erase(begin());
}
float FixedList::average() const {
if (empty())
return 0.0f;
return std::reduce(begin(), end(), 0.0f) / static_cast<float>(size());
}

@ -112,7 +112,7 @@ SoftBody::SoftBody(Mesh* mesh, float edgeCompliance, float triangleCompliance, f
splitConstraints();
}
void SoftBody::applyVertexOffset(const glm::vec3 &offset) {
void SoftBody::applyVertexWorldOffset(const glm::vec3 &offset) {
for (Vertex& vertex : vertices){
vertex.position += offset;
}

@ -6,23 +6,25 @@
#include "vulkan/image.hpp"
#include "vk_mem_alloc.h"
Buffer::Buffer(VkDeviceSize bufferSize, VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags vmaAllocationFlags) : size(bufferSize) {
Buffer::Buffer(VkDeviceSize bufferSize, VkBufferUsageFlags bufferUsageFlags, VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocationFlags)
: size(bufferSize), bufferUsageFlags(bufferUsageFlags), memoryUsage(memoryUsage), allocationCreateFlags(allocationFlags) {
VkBufferCreateInfo bufferCreateInfo {};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferCreateInfo.size = bufferSize;
bufferCreateInfo.usage = bufferUsage;
bufferCreateInfo.usage = bufferUsageFlags;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocationCreateInfo {};
allocationCreateInfo.usage = memoryUsage;
allocationCreateInfo.flags = vmaAllocationFlags;
allocationCreateInfo.flags = allocationFlags;
vmaCreateBuffer(Instance::GetAllocator(), &bufferCreateInfo, &allocationCreateInfo, &handle, &allocation, &allocationInfo);
}
Buffer::Buffer(VkDeviceSize bufferSize, void *initialData, VkDeviceSize initialDataSize, VkBufferUsageFlags bufferUsage,
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags vmaAllocationFlags)
: Buffer(bufferSize, bufferUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT, memoryUsage, vmaAllocationFlags){
Buffer::Buffer(VkDeviceSize bufferSize, void *initialData, VkDeviceSize initialDataSize, VkBufferUsageFlags bufferUsageFlags,
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocationFlags)
: Buffer(bufferSize, bufferUsageFlags | VK_BUFFER_USAGE_TRANSFER_DST_BIT, memoryUsage, allocationFlags){
Buffer stagingBuffer(
bufferSize,
@ -39,20 +41,20 @@ Buffer::~Buffer() {
vmaDestroyBuffer(Instance::GetAllocator(), handle, allocation);
}
void Buffer::copyTo(Buffer *buffer) {
void Buffer::copyTo(Buffer *buffer) const {
VkQueue queue = Instance::instance->graphicsAndPresentQueue;
CommandPool* commandPool = Instance::instance->renderingCommandPool;
VkCommandBuffer commandBuffer = commandPool->beginSingleTimeCommandBuffer();
VkBufferCopy copyRegion {};
copyRegion.size = size;
copyRegion.size = allocationInfo.size;
vkCmdCopyBuffer(commandBuffer, handle, buffer->handle, 1, &copyRegion);
commandPool->endSingleTimeCommandBuffer(commandBuffer, queue);
}
void Buffer::copyTo(Image *image) {
void Buffer::copyTo(Image *image) const {
VkQueue queue = Instance::instance->graphicsAndPresentQueue;
CommandPool* commandPool = Instance::instance->renderingCommandPool;
@ -74,6 +76,84 @@ void Buffer::copyTo(Image *image) {
commandPool->endSingleTimeCommandBuffer(commandBuffer, queue);
}
void Buffer::setName(const std::string &name) {
vmaSetAllocationName(Instance::GetAllocator(), allocation, name.data());
void Buffer::setData(void *data, VkDeviceSize offset, VkDeviceSize size, VkCommandBuffer commandBuffer) {
if (allocationInfo.pMappedData){
memcpy(allocationInfo.pMappedData, reinterpret_cast<u_char*>(data) + offset, size);
VkMemoryPropertyFlags flags;
vmaGetAllocationMemoryProperties(Instance::GetAllocator(), allocation, &flags);
assert(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
} else {
auto stagingBuffer = getStagingBuffer();
stagingBuffer->setData(data, offset, size);
VkBufferMemoryBarrier bufferMemoryBarrier {};
bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
bufferMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
bufferMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
bufferMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemoryBarrier.buffer = stagingBuffer->handle;
bufferMemoryBarrier.size = size;
bufferMemoryBarrier.offset = offset;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, nullptr,
1, &bufferMemoryBarrier,
0, nullptr);
VkBufferCopy region {};
region.srcOffset = offset;
region.dstOffset = offset;
region.size = size;
vkCmdCopyBuffer(commandBuffer, stagingBuffer->handle, handle, 1, &region);
}
}
void Buffer::setName(const std::string &newName) {
name = newName;
vmaSetAllocationName(Instance::GetAllocator(), allocation, newName.data());
}
unique_ptr<Buffer> Buffer::Append(const Buffer &old, void *data, VkDeviceSize size, VkCommandBuffer commandBuffer) {
auto buffer = make_unique<Buffer>(old.size + size,
old.bufferUsageFlags | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
old.memoryUsage,
old.allocationCreateFlags);
VkBufferCopy copyRegion {};
copyRegion.size = old.size;
vkCmdCopyBuffer(commandBuffer, old.handle, buffer->handle, 1, &copyRegion);
buffer->setData(data, old.size, size, commandBuffer);
return buffer;
}
unique_ptr<Buffer> Buffer::Replace(const Buffer &old, void *data, VkDeviceSize size, VkCommandBuffer commandBuffer) {
auto buffer = make_unique<Buffer>(size,
old.bufferUsageFlags | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
old.memoryUsage,
old.allocationCreateFlags);
buffer->setData(data, 0, size, commandBuffer);
return buffer;
}
shared_ptr<Buffer> Buffer::getStagingBuffer() {
if (stagingBufferOptional.has_value())
return stagingBufferOptional.value();
stagingBufferOptional = make_shared<Buffer>(
allocationInfo.size,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VMA_MEMORY_USAGE_AUTO,
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT);
return stagingBufferOptional.value();
}

Loading…
Cancel
Save