|
|
@ -81,22 +81,23 @@ Application::Application() { |
|
|
|
bool grabbing; |
|
|
|
bool grabbing; |
|
|
|
} initialGrabInformation {}; |
|
|
|
} initialGrabInformation {}; |
|
|
|
initialGrabInformation.distanceToFace = 1e20; |
|
|
|
initialGrabInformation.distanceToFace = 1e20; |
|
|
|
grabBuffer = make_unique<Buffer>(sizeof(GrabInformation), &initialGrabInformation, sizeof(GrabInformation), |
|
|
|
grabBuffer = make_unique<Buffer>(sizeof(GrabInformation), |
|
|
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); |
|
|
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
|
|
|
|
|
|
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); |
|
|
|
grabBuffer->setName("Grab"); |
|
|
|
grabBuffer->setName("Grab"); |
|
|
|
|
|
|
|
grabBuffer->setData(&initialGrabInformation, 0, sizeof(initialGrabInformation)); |
|
|
|
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>(); |
|
|
|
|
|
|
|
*sizeInformation = {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
addSoftBody("models/bunny_medium.ply", 10); |
|
|
|
|
|
|
|
|
|
|
|
SimulationUniformData simulationUniformData { |
|
|
|
SimulationUniformData simulationUniformData { |
|
|
|
.gravity = {0, -9.81, 0}, |
|
|
|
.gravity = {0, -9.81, 0}, |
|
|
@ -124,13 +125,6 @@ Application::Application() { |
|
|
|
descriptorPool->bindBuffer(*cameraUniformBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::WORLD, 0); |
|
|
|
descriptorPool->bindBuffer(*cameraUniformBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::WORLD, 0); |
|
|
|
descriptorPool->bindImage(*firstImage, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, DescriptorSet::WORLD, 2); |
|
|
|
descriptorPool->bindImage(*firstImage, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, DescriptorSet::WORLD, 2); |
|
|
|
|
|
|
|
|
|
|
|
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(*tetrahedronBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 4); |
|
|
|
|
|
|
|
descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
descriptorPool->bindBuffer(*simulationPropertiesBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::SIMULATION, 0); |
|
|
|
descriptorPool->bindBuffer(*simulationPropertiesBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::SIMULATION, 0); |
|
|
|
descriptorPool->bindBuffer(*grabBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::SIMULATION, 1); |
|
|
|
descriptorPool->bindBuffer(*grabBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::SIMULATION, 1); |
|
|
|
|
|
|
|
|
|
|
@ -148,7 +142,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(); |
|
|
@ -180,131 +175,151 @@ void Application::createSyncObjects() { |
|
|
|
transferSemaphore = make_unique<Semaphore>(); |
|
|
|
transferSemaphore = make_unique<Semaphore>(); |
|
|
|
renderFence = make_unique<Fence>(true); |
|
|
|
renderFence = make_unique<Fence>(true); |
|
|
|
computeFence = make_unique<Fence>(false); |
|
|
|
computeFence = make_unique<Fence>(false); |
|
|
|
transferFence = make_unique<Fence>(false); |
|
|
|
computeTransferredFence = make_unique<Fence>(false); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Application::createMeshBuffers() { |
|
|
|
void Application::addSoftBody(const std::string &modelFile, size_t count) { |
|
|
|
Mesh sphere("models/icosphere_medium.ply"); |
|
|
|
bufferWriteMutex.lock(); |
|
|
|
Mesh bunny("models/bunny_medium.ply"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto body = std::make_unique<SoftBody>(&sphere, 1.f / 60); |
|
|
|
Mesh mesh(modelFile); |
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < 10; i++){ |
|
|
|
// Do SoftBody calculations once in constructor, will be copied from now on
|
|
|
|
auto copy = std::make_unique<SoftBody>(*body.get()); |
|
|
|
auto original = std::make_unique<SoftBody>(&mesh, 1.f / 60); |
|
|
|
copy->applyVertexOffset({i * 2, 0, 0}); |
|
|
|
|
|
|
|
softBodies.push_back(std::move(copy)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
body = std::make_unique<SoftBody>(&bunny, 1.f / 10); |
|
|
|
vector<Vertex> newVertices; |
|
|
|
for (size_t i = 0; i < 10; i++){ |
|
|
|
vector<Face> newFaces; |
|
|
|
auto copy = std::make_unique<SoftBody>(*body.get()); |
|
|
|
|
|
|
|
copy->applyVertexOffset({i * 2, 0, 2}); |
|
|
|
|
|
|
|
softBodies.push_back(std::move(copy)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vector<Vertex> vertices; |
|
|
|
for (size_t i = 0; i < count; i++){ |
|
|
|
vector<Face> faces; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (std::unique_ptr<SoftBody> ¤tSoftBody : softBodies){ |
|
|
|
// Local copy
|
|
|
|
currentSoftBody->firstIndex = faces.size() * 3; |
|
|
|
auto softBody = std::make_unique<SoftBody>(*original.get()); |
|
|
|
currentSoftBody->vertexOffset = static_cast<int32_t>(vertices.size()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int32_t vertexOffset = currentSoftBody->vertexOffset; |
|
|
|
softBody->applyVertexWorldOffset({i * 2, 0, 0}); |
|
|
|
|
|
|
|
|
|
|
|
for (auto &face : currentSoftBody->faces){ |
|
|
|
// Position in face buffer
|
|
|
|
face.a += vertexOffset; |
|
|
|
softBody->firstIndex = (sizeInformation->faceCount + newFaces.size()) * 3; |
|
|
|
face.b += vertexOffset; |
|
|
|
|
|
|
|
face.c += vertexOffset; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (auto &edge : currentSoftBody->constraintData.edges){ |
|
|
|
|
|
|
|
edge.a += vertexOffset; |
|
|
|
|
|
|
|
edge.b += vertexOffset; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (auto &triangle : currentSoftBody->constraintData.triangles){ |
|
|
|
// Position in vertex buffer
|
|
|
|
triangle.a += vertexOffset; |
|
|
|
softBody->vertexOffset = static_cast<int32_t>(sizeInformation->vertexCount + newVertices.size()); |
|
|
|
triangle.b += vertexOffset; |
|
|
|
|
|
|
|
triangle.c += vertexOffset; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (auto &tetrahedron : currentSoftBody->constraintData.tetrahedra){ |
|
|
|
// Vertex offset added manually for easy access in Compute Shaders
|
|
|
|
tetrahedron.a += vertexOffset; |
|
|
|
{ |
|
|
|
tetrahedron.b += vertexOffset; |
|
|
|
auto vertexOffset = softBody->vertexOffset; |
|
|
|
tetrahedron.c += vertexOffset; |
|
|
|
for (auto &face : softBody->faces){ |
|
|
|
tetrahedron.d += vertexOffset; |
|
|
|
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; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
vertices.insert(vertices.end(), currentSoftBody->vertices.begin(), currentSoftBody->vertices.end()); |
|
|
|
// Append data to vertices and faces
|
|
|
|
faces.insert(faces.end(), currentSoftBody->faces.begin(), currentSoftBody->faces.end()); |
|
|
|
newVertices.insert(newVertices.end(), softBody->vertices.begin(), softBody->vertices.end()); |
|
|
|
|
|
|
|
newFaces.insert(newFaces.end(), softBody->faces.begin(), softBody->faces.end()); |
|
|
|
|
|
|
|
|
|
|
|
constraintData.partitionCount = std::max(constraintData.partitionCount, currentSoftBody->constraintData.partitionCount); |
|
|
|
// Insert data at the right places in this->constraintData
|
|
|
|
|
|
|
|
constraintData.insert(softBody->constraintData); |
|
|
|
|
|
|
|
|
|
|
|
auto combine = [¤tSoftBody, this] ( |
|
|
|
softBodies.push_back(std::move(softBody)); |
|
|
|
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()){ |
|
|
|
sizeInformation->vertexCount += newVertices.size(); |
|
|
|
const ConstraintData::Partition &bodyPartition = bodyPartitions[partition]; |
|
|
|
sizeInformation->faceCount += newFaces.size(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unique_ptr<Buffer> newVertexBuffers[2]; |
|
|
|
|
|
|
|
unique_ptr<Buffer> newFaceBuffer; |
|
|
|
|
|
|
|
unique_ptr<Buffer> newEdgeBuffer; |
|
|
|
|
|
|
|
unique_ptr<Buffer> newTetrahedronBuffer; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto commandBuffer = Instance::instance->renderingCommandPool->beginSingleTimeCommandBuffer(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkBufferUsageFlags bufferUsageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT; |
|
|
|
|
|
|
|
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (vertexBuffers[0] == nullptr){ |
|
|
|
|
|
|
|
newVertexBuffers[0] = make_unique<Buffer>(newVertices.size() * sizeof(Vertex), |
|
|
|
|
|
|
|
bufferUsageFlags | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, |
|
|
|
|
|
|
|
memoryUsage, 0); |
|
|
|
|
|
|
|
newVertexBuffers[1] = make_unique<Buffer>(newVertices.size() * sizeof(Vertex), |
|
|
|
|
|
|
|
bufferUsageFlags | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, |
|
|
|
|
|
|
|
memoryUsage, 0); |
|
|
|
|
|
|
|
newFaceBuffer = make_unique<Buffer>(newFaces.size() * sizeof(Face), |
|
|
|
|
|
|
|
bufferUsageFlags | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, |
|
|
|
|
|
|
|
memoryUsage, 0); |
|
|
|
|
|
|
|
newEdgeBuffer = make_unique<Buffer>(constraintData.edges.size() * sizeof(Edge), bufferUsageFlags, memoryUsage, 0); |
|
|
|
|
|
|
|
newTetrahedronBuffer = make_unique<Buffer>(constraintData.tetrahedra.size() * sizeof(Tetrahedron), bufferUsageFlags, memoryUsage, 0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newVertexBuffers[0]->setName("Vertices 0"); |
|
|
|
|
|
|
|
newVertexBuffers[1]->setName("Vertices 1"); |
|
|
|
|
|
|
|
newFaceBuffer->setName("Faces"); |
|
|
|
|
|
|
|
newEdgeBuffer->setName("Edges"); |
|
|
|
|
|
|
|
newTetrahedronBuffer->setName("Tetrahedra"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newVertexBuffers[0]->setData(newVertices.data(), 0, newVertexBuffers[0]->size, commandBuffer); |
|
|
|
|
|
|
|
newVertexBuffers[1]->setData(newVertices.data(), 0, newVertexBuffers[1]->size, commandBuffer); |
|
|
|
|
|
|
|
newFaceBuffer->setData(newFaces.data(), 0, newFaceBuffer->size, commandBuffer); |
|
|
|
|
|
|
|
newEdgeBuffer->setData(constraintData.edges.data(), 0, newEdgeBuffer->size, commandBuffer); |
|
|
|
|
|
|
|
newTetrahedronBuffer->setData(constraintData.tetrahedra.data(), 0, newTetrahedronBuffer->size, commandBuffer); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
newVertexBuffers[0] = vertexBuffers[0]->appended(newVertices.data(), newVertices.size() * sizeof(Vertex), commandBuffer); |
|
|
|
|
|
|
|
newVertexBuffers[1] = vertexBuffers[1]->appended(newVertices.data(), newVertices.size() * sizeof(Vertex), commandBuffer); |
|
|
|
|
|
|
|
newFaceBuffer = faceBuffer->appended(newFaces.data(), newFaces.size() * sizeof(Face), commandBuffer); |
|
|
|
|
|
|
|
newEdgeBuffer = edgeBuffer->replaced(constraintData.edges.data(), constraintData.edges.size() * sizeof(Edge), commandBuffer); |
|
|
|
|
|
|
|
newTetrahedronBuffer = tetrahedronBuffer->replaced(constraintData.tetrahedra.data(), constraintData.tetrahedra.size() * sizeof(Tetrahedron), commandBuffer); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
auto dst = globalIndices.begin() + globalPartition.offset; |
|
|
|
VkQueue queue = Instance::instance->graphicsAndPresentQueue; |
|
|
|
auto srcStart = bodyIndices.begin() + bodyPartition.offset; |
|
|
|
Instance::instance->renderingCommandPool->endSingleTimeCommandBuffer(commandBuffer, queue); |
|
|
|
uint32_t count = bodyPartition.size; |
|
|
|
|
|
|
|
globalIndices.insert(dst, srcStart, srcStart + count); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
globalPartition.size += count; |
|
|
|
vertexBuffers[0] = std::move(newVertexBuffers[0]); |
|
|
|
|
|
|
|
vertexBuffers[1] = std::move(newVertexBuffers[1]); |
|
|
|
|
|
|
|
faceBuffer = std::move(newFaceBuffer); |
|
|
|
|
|
|
|
edgeBuffer = std::move(newEdgeBuffer); |
|
|
|
|
|
|
|
tetrahedronBuffer = std::move(newTetrahedronBuffer); |
|
|
|
|
|
|
|
|
|
|
|
offsetAdded += count; |
|
|
|
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(*tetrahedronBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 4); |
|
|
|
|
|
|
|
descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5); |
|
|
|
|
|
|
|
|
|
|
|
combine(constraintData.edges, currentSoftBody->constraintData.edges, |
|
|
|
bufferWriteMutex.unlock(); |
|
|
|
constraintData.edgePartitions, currentSoftBody->constraintData.edgePartitions); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
combine(constraintData.tetrahedra, currentSoftBody->constraintData.tetrahedra, |
|
|
|
void Application::removeSoftBody(const unique_ptr<SoftBody> &softBody) { |
|
|
|
constraintData.tetrahedronPartitions, currentSoftBody->constraintData.tetrahedronPartitions); |
|
|
|
// cpu: remove in constraintData, reduce partition sizes and offsets
|
|
|
|
|
|
|
|
// cpu: reduce firstIndex and vertexOffset in following bodies
|
|
|
|
|
|
|
|
|
|
|
|
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()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf("Vertices: %zu\nFaces: %zu\nEdges: %zu\nTriangles: %zu\nTetrahedra: %zu\nTotal Constraints: %zu\n", |
|
|
|
// gpu: update constraintData
|
|
|
|
vertices.size(), faces.size(), constraintData.edges.size(), constraintData.triangles.size(), constraintData.tetrahedra.size(), |
|
|
|
// gpu: update vertices and faces, take from remaining softbodies
|
|
|
|
constraintData.edges.size() + constraintData.tetrahedra.size()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf("Partitions: %u\n", constraintData.partitionCount); |
|
|
|
// cpu: erase vector element
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class SimulationBuffer : public Buffer { |
|
|
|
void Application::updateConstraintBuffers(VkCommandBuffer commandBuffer) { |
|
|
|
public: |
|
|
|
/*
|
|
|
|
SimulationBuffer(void* data, VkDeviceSize size, VkBufferUsageFlags additionalUsageFlags=0) |
|
|
|
edgeBuffer = make_unique<Buffer>(constraintData.edges.size() * sizeof(Edge), constraintData.edges.data()); |
|
|
|
: Buffer(size, data, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | additionalUsageFlags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0) {} |
|
|
|
tetrahedronBuffer = make_unique<Buffer>(constraintData.tetrahedra.size() * sizeof(Tetrahedron), constraintData.tetrahedra.data()); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vertexBuffers[0] = make_unique<SimulationBuffer>(vertices.data(), vertices.size() * sizeof(Vertex), |
|
|
|
edgeBuffer.value()->setName("Edges"); |
|
|
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
|
|
|
// triangleBuffer->setName("Triangles");
|
|
|
|
vertexBuffers[1] = make_unique<SimulationBuffer>(vertices.data(), vertices.size() * sizeof(Vertex), |
|
|
|
tetrahedronBuffer.value()->setName("Tetrahedra"); |
|
|
|
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]->setName("Vertices 0"); |
|
|
|
|
|
|
|
vertexBuffers[1]->setName("Vertices 1"); |
|
|
|
|
|
|
|
faceBuffer->setName("Faces"); |
|
|
|
|
|
|
|
edgeBuffer->setName("Edges"); |
|
|
|
|
|
|
|
triangleBuffer->setName("Triangles"); |
|
|
|
|
|
|
|
tetrahedronBuffer->setName("Tetrahedra"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Application::createComputePipelines() { |
|
|
|
void Application::createComputePipelines() { |
|
|
@ -497,6 +512,8 @@ void Application::recordDrawCommands(VkCommandBuffer commandBuffer) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Application::update() { |
|
|
|
void Application::update() { |
|
|
|
|
|
|
|
bufferWriteMutex.lock(); |
|
|
|
|
|
|
|
|
|
|
|
VkCommandBufferBeginInfo beginInfo {}; |
|
|
|
VkCommandBufferBeginInfo beginInfo {}; |
|
|
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
|
|
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
|
|
|
beginInfo.flags = 0; |
|
|
|
beginInfo.flags = 0; |
|
|
@ -549,7 +566,7 @@ void Application::update() { |
|
|
|
submit.pWaitDstStageMask = &waitStage; |
|
|
|
submit.pWaitDstStageMask = &waitStage; |
|
|
|
|
|
|
|
|
|
|
|
submitMutex.lock(); |
|
|
|
submitMutex.lock(); |
|
|
|
vkQueueSubmit(Instance::instance->computeAndTransferQueue, 1, &submit, transferFence->handle); |
|
|
|
vkQueueSubmit(Instance::instance->computeAndTransferQueue, 1, &submit, computeTransferredFence->handle); |
|
|
|
submitMutex.unlock(); |
|
|
|
submitMutex.unlock(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -558,11 +575,13 @@ void Application::update() { |
|
|
|
|
|
|
|
|
|
|
|
currentDrawVertexBuffer = 1 - currentDrawVertexBuffer; |
|
|
|
currentDrawVertexBuffer = 1 - currentDrawVertexBuffer; |
|
|
|
|
|
|
|
|
|
|
|
vkWaitForFences(Instance::GetDevice(), 1, &transferFence->handle, VK_TRUE, UINT64_MAX); |
|
|
|
vkWaitForFences(Instance::GetDevice(), 1, &computeTransferredFence->handle, VK_TRUE, UINT64_MAX); |
|
|
|
vkResetFences(Instance::GetDevice(), 1, &transferFence->handle); |
|
|
|
vkResetFences(Instance::GetDevice(), 1, &computeTransferredFence->handle); |
|
|
|
|
|
|
|
|
|
|
|
currentDrawVertexBuffer = 1 - currentDrawVertexBuffer; |
|
|
|
currentDrawVertexBuffer = 1 - currentDrawVertexBuffer; |
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bufferWriteMutex.unlock(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint32_t Application::GetGroupCount(uint32_t threads, uint32_t blockSize) { |
|
|
|
uint32_t Application::GetGroupCount(uint32_t threads, uint32_t blockSize) { |
|
|
@ -584,7 +603,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 +635,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 +680,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); |
|
|
@ -712,15 +731,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(); |
|
|
|
} |
|
|
|
} |
|
|
|