start of runtime control for soft bodies

feature/softbody-runtime-control
Benjamin Kraft 3 months ago
parent 3dde0fee20
commit c51a9f6552
  1. 16
      imgui.ini
  2. 18
      include/application.hpp
  3. 1
      include/constraints.hpp
  4. 2
      include/soft_body.hpp
  5. 30
      include/vulkan/buffer.hpp
  6. 231
      src/application.cpp
  7. 33
      src/constraints.cpp
  8. 2
      src/soft_body.cpp
  9. 102
      src/vulkan/buffer.cpp

@ -30,16 +30,24 @@ Collapsed=0
[Window][Performance] [Window][Performance]
Pos=1716,2 Pos=1716,2
Size=203,1002 Size=203,345
Collapsed=0 Collapsed=0
DockId=0x00000001,0 DockId=0x00000002,0
[Window][Performance 2] [Window][Performance 2]
Pos=1617,2 Pos=1617,2
Size=302,1002 Size=302,1002
Collapsed=0 Collapsed=0
DockId=0x00000001,1 DockId=0x00000002,1
[Window][Scene]
Pos=1716,349
Size=203,655
Collapsed=0
DockId=0x00000004,0
[Docking][Data] [Docking][Data]
DockNode ID=0x00000001 Pos=1716,2 Size=203,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

@ -23,6 +23,7 @@
using std::unique_ptr, std::make_unique; using std::unique_ptr, std::make_unique;
using std::vector; using std::vector;
using std::optional;
class SoftBody; class SoftBody;
class Instance; class Instance;
@ -37,6 +38,7 @@ class Semaphore;
class Camera; class Camera;
class DescriptorPool; class DescriptorPool;
class Grabber; class Grabber;
struct SizesUniformData;
class Application { class Application {
public: public:
@ -75,17 +77,21 @@ private:
unique_ptr<Grabber> grabber; unique_ptr<Grabber> grabber;
unique_ptr<Buffer> grabBuffer; 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; size_t currentDrawVertexBuffer = 0;
unique_ptr<Buffer> vertexBuffers[2]; optional<unique_ptr<Buffer>> vertexBuffers[2];
unique_ptr<Buffer> faceBuffer; optional<unique_ptr<Buffer>> faceBuffer;
unique_ptr<Buffer> edgeBuffer; optional<unique_ptr<Buffer>> edgeBuffer;
unique_ptr<Buffer> triangleBuffer; optional<unique_ptr<Buffer>> triangleBuffer;
unique_ptr<Buffer> tetrahedronBuffer; optional<unique_ptr<Buffer>> tetrahedronBuffer;
ConstraintData constraintData {}; ConstraintData constraintData {};
vector<unique_ptr<SoftBody>> softBodies; vector<unique_ptr<SoftBody>> softBodies;
unique_ptr<Buffer> sizeInformationBuffer; unique_ptr<Buffer> sizeInformationBuffer;
SizesUniformData *sizeInformation = nullptr;
unique_ptr<Buffer> simulationPropertiesBuffer; unique_ptr<Buffer> simulationPropertiesBuffer;

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

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

@ -4,27 +4,45 @@
#include <stdexcept> #include <stdexcept>
#include "vertex.hpp" #include "vertex.hpp"
#include "vk_mem_alloc.h" #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 Image;
class Buffer { class Buffer {
public: public:
explicit Buffer(VkDeviceSize bufferSize, VkBufferUsageFlags bufferUsage, Buffer(VkDeviceSize bufferSize, VkBufferUsageFlags bufferUsage,
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags vmaAllocationFlags); 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); 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; VkBuffer handle = VK_NULL_HANDLE;
VmaAllocation allocation = VK_NULL_HANDLE; VmaAllocation allocation = VK_NULL_HANDLE;
VmaAllocationInfo allocationInfo {}; VmaAllocationInfo allocationInfo {};
VkDeviceSize size; VkDeviceSize size;
void setName(const std::string& name); void setName(const std::string& newName);
template <typename T> template <typename T>
T& access(){ T& access(){
return *reinterpret_cast<T*>(allocationInfo.pMappedData); 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(const Buffer& other) = delete;
Buffer& operator =(const Buffer& other) = delete; Buffer& operator =(const Buffer& other) = delete;
void copyTo(Buffer* buffer); private:
void copyTo(Image* image); optional<shared_ptr<Buffer>> stagingBufferOptional;
std::string name;
VkBufferUsageFlags bufferUsageFlags;
VmaMemoryUsage memoryUsage;
VmaAllocationCreateFlags allocationCreateFlags;
}; };

@ -86,17 +86,15 @@ Application::Application() {
grabBuffer->setName("Grab"); grabBuffer->setName("Grab");
grabber = make_unique<Grabber>(); grabber = make_unique<Grabber>();
createMeshBuffers();
SizesUniformData sizeInformation {};
sizeInformation.vertexCount = vertexBuffers[0]->size / sizeof(Vertex);
sizeInformation.faceCount = faceBuffer->size / sizeof(Face);
sizeInformationBuffer = make_unique<Buffer>( sizeInformationBuffer = make_unique<Buffer>(
sizeof(SizesUniformData), &sizeInformation, sizeof(sizeInformation), sizeof(SizesUniformData),
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 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"); sizeInformationBuffer->setName("Sizes");
sizeInformation = &sizeInformationBuffer->access<SizesUniformData>();
addSoftBody("models/bunny_medium.ply");
SimulationUniformData simulationUniformData { SimulationUniformData simulationUniformData {
.gravity = {0, -9.81, 0}, .gravity = {0, -9.81, 0},
@ -127,7 +125,7 @@ Application::Application() {
descriptorPool->bindBuffer(*vertexBuffers[1 - currentDrawVertexBuffer], VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0); 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(*faceBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 1);
descriptorPool->bindBuffer(*edgeBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 2); 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(*tetrahedronBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 4);
descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5); descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5);
@ -148,7 +146,8 @@ void Application::mainLoop() {
auto t2 = system_clock::now(); auto t2 = system_clock::now();
auto measuredUpdateDuration = duration<float>(t2 - t1); 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); std::this_thread::sleep_for(requestedUpdateDuration - measuredUpdateDuration);
performanceInformation.updateDuration = measuredUpdateDuration.count(); performanceInformation.updateDuration = measuredUpdateDuration.count();
@ -183,128 +182,101 @@ void Application::createSyncObjects() {
transferFence = make_unique<Fence>(false); transferFence = make_unique<Fence>(false);
} }
void Application::createMeshBuffers() { void Application::addSoftBody(const std::string &modelFile, size_t count) {
Mesh sphere("models/icosphere_medium.ply"); Mesh mesh(modelFile);
Mesh bunny("models/bunny_medium.ply");
auto body = std::make_unique<SoftBody>(&sphere, 1.f / 60);
for (size_t i = 0; i < 10; i++){
auto copy = std::make_unique<SoftBody>(*body.get());
copy->applyVertexOffset({i * 2, 0, 0});
softBodies.push_back(std::move(copy));
}
body = std::make_unique<SoftBody>(&bunny, 1.f / 10);
for (size_t i = 0; i < 10; i++){
auto copy = std::make_unique<SoftBody>(*body.get());
copy->applyVertexOffset({i * 2, 0, 2});
softBodies.push_back(std::move(copy));
}
vector<Vertex> vertices;
vector<Face> faces;
for (std::unique_ptr<SoftBody> &currentSoftBody : softBodies){
currentSoftBody->firstIndex = faces.size() * 3;
currentSoftBody->vertexOffset = static_cast<int32_t>(vertices.size());
int32_t vertexOffset = currentSoftBody->vertexOffset;
for (auto &face : currentSoftBody->faces){
face.a += vertexOffset;
face.b += vertexOffset;
face.c += vertexOffset;
}
for (auto &edge : currentSoftBody->constraintData.edges){
edge.a += vertexOffset;
edge.b += vertexOffset;
}
for (auto &triangle : currentSoftBody->constraintData.triangles){
triangle.a += vertexOffset;
triangle.b += vertexOffset;
triangle.c += vertexOffset;
}
for (auto &tetrahedron : currentSoftBody->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); // Do SoftBody calculations once in constructor, will be copied from now on
auto original = std::make_unique<SoftBody>(&mesh, 1.f / 60);
auto combine = [&currentSoftBody, this] ( vector<Vertex> newVertices;
auto &globalIndices, auto &bodyIndices, vector<Face> newFaces;
vector<ConstraintData::Partition> &globalPartitions, vector<ConstraintData::Partition> &bodyPartitions){
if (globalPartitions.size() < currentSoftBody->constraintData.partitionCount)
globalPartitions.resize(currentSoftBody->constraintData.partitionCount);
uint32_t offsetAdded = 0; for (size_t i = 0; i < count; i++){
for (uint32_t partition = 0; partition < constraintData.partitionCount; partition++){ // Local copy
auto softBody = std::make_unique<SoftBody>(*original.get());
ConstraintData::Partition &globalPartition = globalPartitions[partition]; softBody->applyVertexWorldOffset({i * 2, 0, 0});
globalPartition.offset += offsetAdded;
if (partition < bodyPartitions.size()){ // Position in face buffer
const ConstraintData::Partition &bodyPartition = bodyPartitions[partition]; softBody->firstIndex = (sizeInformation->faceCount + newFaces.size()) * 3;
auto dst = globalIndices.begin() + globalPartition.offset; // Position in vertex buffer
auto srcStart = bodyIndices.begin() + bodyPartition.offset; softBody->vertexOffset = static_cast<int32_t>(sizeInformation->vertexCount + newVertices.size());
uint32_t count = bodyPartition.size;
globalIndices.insert(dst, srcStart, srcStart + count);
globalPartition.size += count; // Vertex offset added manually for easy access in Compute Shaders
{
offsetAdded += count; auto vertexOffset = softBody->vertexOffset;
} for (auto &face : softBody->faces){
face.a += vertexOffset;
face.b += vertexOffset;
face.c += vertexOffset;
}
for (auto &edge : softBody->constraintData.edges){
edge.a += vertexOffset;
edge.b += vertexOffset;
} }
}; for (auto &triangle : softBody->constraintData.triangles){
triangle.a += vertexOffset;
triangle.b += vertexOffset;
triangle.c += vertexOffset;
}
for (auto &tetrahedron : softBody->constraintData.tetrahedra){
tetrahedron.a += vertexOffset;
tetrahedron.b += vertexOffset;
tetrahedron.c += vertexOffset;
tetrahedron.d += vertexOffset;
}
}
combine(constraintData.edges, currentSoftBody->constraintData.edges, // Append data to vertices and faces
constraintData.edgePartitions, currentSoftBody->constraintData.edgePartitions); 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, // Insert data at the right places in this->constraintData
constraintData.tetrahedronPartitions, currentSoftBody->constraintData.tetrahedronPartitions); constraintData.insert(softBody->constraintData);
constraintData.triangles.insert(constraintData.triangles.end(), currentSoftBody->constraintData.triangles.begin(), currentSoftBody->constraintData.triangles.end()); softBodies.push_back(std::move(softBody));
constraintData.tetrahedra.insert(constraintData.tetrahedra.end(), currentSoftBody->constraintData.tetrahedra.begin(), currentSoftBody->constraintData.tetrahedra.end());
} }
printf("Vertices: %zu\nFaces: %zu\nEdges: %zu\nTriangles: %zu\nTetrahedra: %zu\nTotal Constraints: %zu\n", sizeInformation->vertexCount += newVertices.size();
vertices.size(), faces.size(), constraintData.edges.size(), constraintData.triangles.size(), constraintData.tetrahedra.size(), sizeInformation->faceCount += newFaces.size();
constraintData.edges.size() + constraintData.tetrahedra.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);
class SimulationBuffer : public Buffer { vertexBuffers[1] = Buffer::Append(*vertexBuffers[1], newVertices.data(), newVertices.size() * sizeof(Vertex), commandBuffer);
public: faceBuffer = Buffer::Append(*faceBuffer, newFaces.data(), newFaces.size() * sizeof(Face), commandBuffer);
SimulationBuffer(void* data, VkDeviceSize size, VkBufferUsageFlags additionalUsageFlags=0) edgeBuffer = Buffer::Replace(*edgeBuffer, constraintData.edges.data(), constraintData.edges.size() * sizeof(Edge), commandBuffer);
: Buffer(size, data, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | additionalUsageFlags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0) {} // 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);
vertexBuffers[0] = make_unique<SimulationBuffer>(vertices.data(), vertices.size() * sizeof(Vertex), vertexBuffers[0] = make_unique<SimulationBuffer>(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
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);
vertexBuffers[1] = make_unique<SimulationBuffer>(vertices.data(), vertices.size() * sizeof(Vertex), faceBuffer = make_unique<SimulationBuffer>(VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); edgeBuffer = make_unique<SimulationBuffer>();
faceBuffer = make_unique<SimulationBuffer>(faces.data(), faces.size() * sizeof(Face), VK_BUFFER_USAGE_INDEX_BUFFER_BIT); // triangleBuffer = make_unique<SimulationBuffer>();
edgeBuffer = make_unique<SimulationBuffer>(constraintData.edges.data(), constraintData.edges.size() * sizeof(Edge)); tetrahedronBuffer = make_unique<SimulationBuffer>();
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]->setName("Vertices 0"); vertexBuffers[0]->setName("Vertices 0");
vertexBuffers[1]->setName("Vertices 1"); vertexBuffers[1]->setName("Vertices 1");
faceBuffer->setName("Faces"); faceBuffer->setName("Faces");
edgeBuffer->setName("Edges"); edgeBuffer->setName("Edges");
triangleBuffer->setName("Triangles"); // triangleBuffer->setName("Triangles");
tetrahedronBuffer->setName("Tetrahedra"); 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() { void Application::createComputePipelines() {
@ -388,7 +360,7 @@ void Application::drawFrame(float dt) {
VkBufferMemoryBarrier vertexBufferBarrier{}; VkBufferMemoryBarrier vertexBufferBarrier{};
vertexBufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; vertexBufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
vertexBufferBarrier.size = vertexBuffers[currentDrawVertexBuffer]->size; vertexBufferBarrier.size = vertexBuffers[currentDrawVertexBuffer]->allocationInfo.size;
vertexBufferBarrier.offset = 0; vertexBufferBarrier.offset = 0;
vertexBufferBarrier.buffer = vertexBuffers[currentDrawVertexBuffer]->handle; vertexBufferBarrier.buffer = vertexBuffers[currentDrawVertexBuffer]->handle;
vertexBufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; vertexBufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
@ -530,7 +502,7 @@ void Application::update() {
vkBeginCommandBuffer(cmdBuffer, &beginInfo); vkBeginCommandBuffer(cmdBuffer, &beginInfo);
VkBufferCopy copyRegion {}; VkBufferCopy copyRegion {};
copyRegion.size = vertexBuffers[1 - currentDrawVertexBuffer]->size; copyRegion.size = vertexBuffers[1 - currentDrawVertexBuffer]->allocationInfo.size;
copyRegion.srcOffset = 0; copyRegion.srcOffset = 0;
copyRegion.dstOffset = 0; copyRegion.dstOffset = 0;
@ -584,7 +556,7 @@ void Application::recordGrabCommands(VkCommandBuffer commandBuffer) {
pushConstants.screenPosition = grabber->previousCursorPosition; pushConstants.screenPosition = grabber->previousCursorPosition;
vkCmdPushConstants(commandBuffer, grabPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(GrabPushData), &pushConstants); 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); vkCmdDispatch(commandBuffer, faceInvocations, 1, 1);
computePipelineBarrier(commandBuffer); computePipelineBarrier(commandBuffer);
@ -616,7 +588,7 @@ void Application::recordGrabCommands(VkCommandBuffer commandBuffer) {
} }
void Application::recordPBDCommands(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); 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); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr);
@ -661,8 +633,8 @@ void Application::recordPBDCommands(VkCommandBuffer commandBuffer) {
} }
void Application::recordNormalCommands(VkCommandBuffer commandBuffer) { void Application::recordNormalCommands(VkCommandBuffer commandBuffer) {
uint32_t vertexGroupCount = GetGroupCount(vertexBuffers[1 - currentDrawVertexBuffer]->size / sizeof(Vertex), BLOCK_SIZE_NORMAL); uint32_t vertexGroupCount = GetGroupCount(sizeInformation->vertexCount, BLOCK_SIZE_NORMAL);
uint32_t faceGroupCount = GetGroupCount(faceBuffer->size / sizeof(Face), BLOCK_SIZE_NORMAL); uint32_t faceGroupCount = GetGroupCount(sizeInformation->faceCount, BLOCK_SIZE_NORMAL);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->handle); 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); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr);
@ -693,7 +665,7 @@ void Application::computePipelineBarrier(VkCommandBuffer commandBuffer) {
VkBufferMemoryBarrier bufferMemoryBarrier {}; VkBufferMemoryBarrier bufferMemoryBarrier {};
bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
bufferMemoryBarrier.buffer = buffer.handle; bufferMemoryBarrier.buffer = buffer.handle;
bufferMemoryBarrier.size = buffer.size; bufferMemoryBarrier.size = buffer.allocationInfo.size;
bufferMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; bufferMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
bufferMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; bufferMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
bufferMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; bufferMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
@ -712,15 +684,22 @@ void Application::imGuiWindows() {
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
ImGui::Begin("Performance"); ImGui::Begin("Performance"); {
float updateMS = performanceInformation.updateDuration * 1000.f;
float updateMS = performanceInformation.updateDuration * 1000.f; float updateHZ = 1 / performanceInformation.recentTotalUpdateDurations.average();
float updateHZ = 1 / performanceInformation.recentTotalUpdateDurations.average(); ImGui::Text("Updates: %2.0fms | %.1fHz", updateMS, updateHZ);
ImGui::Text("Updates: %.0fms | %.1fHz", updateMS, updateHZ);
float frameMS = performanceInformation.recentFrameDurations.average() * 1000.f; float frameMS = performanceInformation.recentFrameDurations.average() * 1000.f;
float frameHZ = 1 / performanceInformation.recentFrameDurations.average(); float frameHZ = 1 / performanceInformation.recentFrameDurations.average();
ImGui::Text("Frames: %.2fms | %.1fHz", frameMS, frameHZ); ImGui::Text("Frames: %.2fms | %.1fHz", frameMS, frameHZ);
} ImGui::End();
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); 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 { void DistanceConstraint::writeData(ConstraintData &dataLists) const {
dataLists.edges.push_back(Edge(a, b, length, compliance)); dataLists.edges.push_back(Edge(a, b, length, compliance));
} }

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

@ -6,23 +6,25 @@
#include "vulkan/image.hpp" #include "vulkan/image.hpp"
#include "vk_mem_alloc.h" #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 {}; VkBufferCreateInfo bufferCreateInfo {};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferCreateInfo.size = bufferSize; bufferCreateInfo.size = bufferSize;
bufferCreateInfo.usage = bufferUsage; bufferCreateInfo.usage = bufferUsageFlags;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocationCreateInfo {}; VmaAllocationCreateInfo allocationCreateInfo {};
allocationCreateInfo.usage = memoryUsage; allocationCreateInfo.usage = memoryUsage;
allocationCreateInfo.flags = vmaAllocationFlags; allocationCreateInfo.flags = allocationFlags;
vmaCreateBuffer(Instance::GetAllocator(), &bufferCreateInfo, &allocationCreateInfo, &handle, &allocation, &allocationInfo); vmaCreateBuffer(Instance::GetAllocator(), &bufferCreateInfo, &allocationCreateInfo, &handle, &allocation, &allocationInfo);
} }
Buffer::Buffer(VkDeviceSize bufferSize, void *initialData, VkDeviceSize initialDataSize, VkBufferUsageFlags bufferUsage, Buffer::Buffer(VkDeviceSize bufferSize, void *initialData, VkDeviceSize initialDataSize, VkBufferUsageFlags bufferUsageFlags,
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags vmaAllocationFlags) VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocationFlags)
: Buffer(bufferSize, bufferUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT, memoryUsage, vmaAllocationFlags){ : Buffer(bufferSize, bufferUsageFlags | VK_BUFFER_USAGE_TRANSFER_DST_BIT, memoryUsage, allocationFlags){
Buffer stagingBuffer( Buffer stagingBuffer(
bufferSize, bufferSize,
@ -39,20 +41,20 @@ Buffer::~Buffer() {
vmaDestroyBuffer(Instance::GetAllocator(), handle, allocation); vmaDestroyBuffer(Instance::GetAllocator(), handle, allocation);
} }
void Buffer::copyTo(Buffer *buffer) { void Buffer::copyTo(Buffer *buffer) const {
VkQueue queue = Instance::instance->graphicsAndPresentQueue; VkQueue queue = Instance::instance->graphicsAndPresentQueue;
CommandPool* commandPool = Instance::instance->renderingCommandPool; CommandPool* commandPool = Instance::instance->renderingCommandPool;
VkCommandBuffer commandBuffer = commandPool->beginSingleTimeCommandBuffer(); VkCommandBuffer commandBuffer = commandPool->beginSingleTimeCommandBuffer();
VkBufferCopy copyRegion {}; VkBufferCopy copyRegion {};
copyRegion.size = size; copyRegion.size = allocationInfo.size;
vkCmdCopyBuffer(commandBuffer, handle, buffer->handle, 1, &copyRegion); vkCmdCopyBuffer(commandBuffer, handle, buffer->handle, 1, &copyRegion);
commandPool->endSingleTimeCommandBuffer(commandBuffer, queue); commandPool->endSingleTimeCommandBuffer(commandBuffer, queue);
} }
void Buffer::copyTo(Image *image) { void Buffer::copyTo(Image *image) const {
VkQueue queue = Instance::instance->graphicsAndPresentQueue; VkQueue queue = Instance::instance->graphicsAndPresentQueue;
CommandPool* commandPool = Instance::instance->renderingCommandPool; CommandPool* commandPool = Instance::instance->renderingCommandPool;
@ -74,6 +76,84 @@ void Buffer::copyTo(Image *image) {
commandPool->endSingleTimeCommandBuffer(commandBuffer, queue); commandPool->endSingleTimeCommandBuffer(commandBuffer, queue);
} }
void Buffer::setName(const std::string &name) { void Buffer::setData(void *data, VkDeviceSize offset, VkDeviceSize size, VkCommandBuffer commandBuffer) {
vmaSetAllocationName(Instance::GetAllocator(), allocation, name.data()); 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