|
|
|
@ -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> ¤tSoftBody : 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 = [¤tSoftBody, 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(); |
|
|
|
|
} |
|
|
|
|