|
|
@ -9,70 +9,38 @@ |
|
|
|
#include "vulkan/descriptor_pool.hpp" |
|
|
|
#include "vulkan/descriptor_pool.hpp" |
|
|
|
|
|
|
|
|
|
|
|
Simulation::Simulation() { |
|
|
|
Simulation::Simulation() { |
|
|
|
Mesh sphere("models/sphere_high.ply"); |
|
|
|
createMeshBuffers(); |
|
|
|
Mesh bunny("models/bunny_high.ply"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto body = std::make_unique<SoftBody>(&sphere, 0.3f); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < 500; i++){ |
|
|
|
struct SizeInformation { |
|
|
|
auto copy = std::make_unique<SoftBody>(*body.get()); |
|
|
|
uint32_t vertexCount; |
|
|
|
copy->applyOffset({i / 2.f, 0, 0}); |
|
|
|
uint32_t faceCount; |
|
|
|
softBodies.push_back(std::move(copy)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vector<Vertex> vertices; |
|
|
|
|
|
|
|
vector<Edge> edges; |
|
|
|
|
|
|
|
vector<Triangle> triangles; |
|
|
|
|
|
|
|
vector<Face> faces; |
|
|
|
|
|
|
|
vector<Tetrahedron> tetrahedra; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const std::unique_ptr<SoftBody> &softBody : softBodies){ |
|
|
|
|
|
|
|
softBody->firstIndex = faces.size() * 3; |
|
|
|
|
|
|
|
softBody->vertexOffset = static_cast<int32_t>(vertices.size()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vertices.insert(vertices.end(), softBody->vertices.begin(), softBody->vertices.end()); |
|
|
|
|
|
|
|
edges.insert(edges.end(), softBody->edges.begin(), softBody->edges.end()); |
|
|
|
|
|
|
|
triangles.insert(triangles.end(), softBody->triangles.begin(), softBody->triangles.end()); |
|
|
|
|
|
|
|
faces.insert(faces.end(), softBody->faces.begin(), softBody->faces.end()); |
|
|
|
|
|
|
|
tetrahedra.insert(tetrahedra.end(), softBody->tetrahedra.begin(), softBody->tetrahedra.end()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (auto iter = faces.begin() + softBody->firstIndex / 3; iter != faces.end(); iter++){ |
|
|
|
uint32_t edgeCount; |
|
|
|
iter->a += softBody->vertexOffset; |
|
|
|
uint32_t triangleCount; |
|
|
|
iter->b += softBody->vertexOffset; |
|
|
|
uint32_t tetrahedronCount; |
|
|
|
iter->c += softBody->vertexOffset; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) {} |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
SizeInformation sizeInformation {}; |
|
|
|
vertexBuffer = new SimulationBuffer(vertices.data(), vertices.size() * sizeof(Vertex), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); |
|
|
|
sizeInformation.vertexCount = vertexBuffer->size / sizeof(Vertex); |
|
|
|
edgeBuffer = new SimulationBuffer(edges.data(), edges.size() * sizeof(Edge)); |
|
|
|
sizeInformation.faceCount = faceBuffer->size / sizeof(Face); |
|
|
|
triangleBuffer = new SimulationBuffer(triangles.data(), triangles.size() * sizeof(Triangle)); |
|
|
|
|
|
|
|
faceBuffer = new SimulationBuffer(faces.data(), faces.size() * sizeof(Face), VK_BUFFER_USAGE_INDEX_BUFFER_BIT); |
|
|
|
sizeInformationBuffer = make_unique<Buffer>( |
|
|
|
tetrahedronBuffer = new SimulationBuffer(tetrahedra.data(), tetrahedra.size() * sizeof(Tetrahedron)); |
|
|
|
sizeof(SizeInformation), &sizeInformation, sizeof(sizeInformation), |
|
|
|
|
|
|
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, |
|
|
|
descriptorPool->bindBuffer(vertexBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0); |
|
|
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); |
|
|
|
descriptorPool->bindBuffer(edgeBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 1); |
|
|
|
|
|
|
|
descriptorPool->bindBuffer(triangleBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 2); |
|
|
|
descriptorPool->bindBuffer(*vertexBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0); |
|
|
|
descriptorPool->bindBuffer(faceBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 3); |
|
|
|
descriptorPool->bindBuffer(*faceBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 1); |
|
|
|
descriptorPool->bindBuffer(tetrahedronBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 4); |
|
|
|
descriptorPool->bindBuffer(*edgeBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 2); |
|
|
|
|
|
|
|
descriptorPool->bindBuffer(*triangleBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 3); |
|
|
|
pbdPipeline = new ComputePipeline("shaders/pbd.spv", {descriptorPool->setLayouts[DescriptorSet::MESH]}); |
|
|
|
descriptorPool->bindBuffer(*tetrahedronBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 4); |
|
|
|
|
|
|
|
descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5); |
|
|
|
|
|
|
|
|
|
|
|
normalPipeline = new ComputePipeline("shaders/normal.spv", { |
|
|
|
createComputePipelines(); |
|
|
|
descriptorPool->setLayouts[DescriptorSet::MESH] |
|
|
|
|
|
|
|
},{ |
|
|
|
char* stats; |
|
|
|
{ |
|
|
|
vmaBuildStatsString(Instance::instance->allocator, &stats, VK_TRUE); |
|
|
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, |
|
|
|
// printf("%s", stats);
|
|
|
|
.offset = 0, |
|
|
|
vmaFreeStatsString(Instance::instance->allocator, stats); |
|
|
|
.size = sizeof(uint32_t) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Simulation::recordDrawCommands() { |
|
|
|
void Simulation::recordDrawCommands() { |
|
|
@ -88,6 +56,15 @@ void Simulation::recordDrawCommands() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Simulation::recordComputeCommands(VkCommandBuffer cmdBuffer) { |
|
|
|
void Simulation::recordComputeCommands(VkCommandBuffer cmdBuffer) { |
|
|
|
|
|
|
|
#define BlOCK_SIZE 256 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto getGroupCount = [](uint32_t threads, uint32_t blockSize){ |
|
|
|
|
|
|
|
return (threads - 1) / blockSize + 1; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t vertexGroupCount = getGroupCount(vertexBuffer->size / sizeof(Vertex), BlOCK_SIZE); |
|
|
|
|
|
|
|
uint32_t faceGroupCount = getGroupCount(faceBuffer->size / sizeof(Face), BlOCK_SIZE); |
|
|
|
|
|
|
|
|
|
|
|
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->handle); |
|
|
|
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->handle); |
|
|
|
|
|
|
|
|
|
|
|
VkMemoryBarrier barrier {}; |
|
|
|
VkMemoryBarrier barrier {}; |
|
|
@ -100,8 +77,7 @@ void Simulation::recordComputeCommands(VkCommandBuffer cmdBuffer) { |
|
|
|
size_t subSteps = 1; |
|
|
|
size_t subSteps = 1; |
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < subSteps; i++){ |
|
|
|
for (size_t i = 0; i < subSteps; i++){ |
|
|
|
uint32_t preSolveInvocations = 1; |
|
|
|
vkCmdDispatch(cmdBuffer, vertexGroupCount, 1, 1); |
|
|
|
vkCmdDispatch(cmdBuffer, preSolveInvocations, 1, 1); |
|
|
|
|
|
|
|
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); |
|
|
|
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); |
|
|
|
|
|
|
|
|
|
|
|
uint32_t partitionCount = 1; |
|
|
|
uint32_t partitionCount = 1; |
|
|
@ -110,22 +86,14 @@ void Simulation::recordComputeCommands(VkCommandBuffer cmdBuffer) { |
|
|
|
vkCmdDispatch(cmdBuffer, partitionSize, 1, 1); |
|
|
|
vkCmdDispatch(cmdBuffer, partitionSize, 1, 1); |
|
|
|
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); |
|
|
|
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); |
|
|
|
} |
|
|
|
} |
|
|
|
uint32_t postSolveInvocations = 1; |
|
|
|
|
|
|
|
vkCmdDispatch(cmdBuffer, postSolveInvocations, 1, 1); |
|
|
|
vkCmdDispatch(cmdBuffer, vertexGroupCount, 1, 1); |
|
|
|
|
|
|
|
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->handle); |
|
|
|
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->handle); |
|
|
|
vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr); |
|
|
|
vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr); |
|
|
|
|
|
|
|
|
|
|
|
#define BlOCK_SIZE 256 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto getGroupCount = [](uint32_t threads, uint32_t blockSize){ |
|
|
|
|
|
|
|
return (threads - 1) / blockSize + 1; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t vertexGroupCount = getGroupCount(vertexBuffer->size / sizeof(Vertex), BlOCK_SIZE); |
|
|
|
|
|
|
|
uint32_t faceGroupCount = getGroupCount(faceBuffer->size / sizeof(Face), BlOCK_SIZE); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t state = 0; |
|
|
|
uint32_t state = 0; |
|
|
|
vkCmdPushConstants(cmdBuffer, normalPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(uint32_t), &state); |
|
|
|
vkCmdPushConstants(cmdBuffer, normalPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(uint32_t), &state); |
|
|
|
vkCmdDispatch(cmdBuffer, vertexGroupCount, 1, 1); |
|
|
|
vkCmdDispatch(cmdBuffer, vertexGroupCount, 1, 1); |
|
|
@ -143,11 +111,77 @@ void Simulation::recordComputeCommands(VkCommandBuffer cmdBuffer) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Simulation::~Simulation() { |
|
|
|
Simulation::~Simulation() { |
|
|
|
delete vertexBuffer; |
|
|
|
|
|
|
|
delete edgeBuffer; |
|
|
|
} |
|
|
|
delete triangleBuffer; |
|
|
|
|
|
|
|
delete faceBuffer; |
|
|
|
void Simulation::createMeshBuffers() { |
|
|
|
delete tetrahedronBuffer; |
|
|
|
Mesh sphere("models/sphere_high.ply"); |
|
|
|
delete pbdPipeline; |
|
|
|
Mesh bunny("models/bunny_high.ply"); |
|
|
|
delete normalPipeline; |
|
|
|
|
|
|
|
|
|
|
|
auto body = std::make_unique<SoftBody>(&sphere, 0.3f); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < 500; i++){ |
|
|
|
|
|
|
|
auto copy = std::make_unique<SoftBody>(*body.get()); |
|
|
|
|
|
|
|
copy->applyOffset({i / 2.f, 0, 0}); |
|
|
|
|
|
|
|
softBodies.push_back(std::move(copy)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vector<Vertex> vertices; |
|
|
|
|
|
|
|
vector<Edge> edges; |
|
|
|
|
|
|
|
vector<Triangle> triangles; |
|
|
|
|
|
|
|
vector<Face> faces; |
|
|
|
|
|
|
|
vector<Tetrahedron> tetrahedra; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const std::unique_ptr<SoftBody> &softBody : softBodies){ |
|
|
|
|
|
|
|
softBody->firstIndex = faces.size() * 3; |
|
|
|
|
|
|
|
softBody->vertexOffset = static_cast<int32_t>(vertices.size()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vertices.insert(vertices.end(), softBody->vertices.begin(), softBody->vertices.end()); |
|
|
|
|
|
|
|
edges.insert(edges.end(), softBody->edges.begin(), softBody->edges.end()); |
|
|
|
|
|
|
|
triangles.insert(triangles.end(), softBody->triangles.begin(), softBody->triangles.end()); |
|
|
|
|
|
|
|
faces.insert(faces.end(), softBody->faces.begin(), softBody->faces.end()); |
|
|
|
|
|
|
|
tetrahedra.insert(tetrahedra.end(), softBody->tetrahedra.begin(), softBody->tetrahedra.end()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (auto face = faces.begin() + softBody->firstIndex / 3; face != faces.end(); face++){ |
|
|
|
|
|
|
|
face->a += softBody->vertexOffset; |
|
|
|
|
|
|
|
face->b += softBody->vertexOffset; |
|
|
|
|
|
|
|
face->c += softBody->vertexOffset; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) {} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vertexBuffer = make_unique<SimulationBuffer>(vertices.data(), vertices.size() * sizeof(Vertex), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); |
|
|
|
|
|
|
|
faceBuffer = make_unique<SimulationBuffer>(faces.data(), faces.size() * sizeof(Face), VK_BUFFER_USAGE_INDEX_BUFFER_BIT); |
|
|
|
|
|
|
|
edgeBuffer = make_unique<SimulationBuffer>(edges.data(), edges.size() * sizeof(Edge)); |
|
|
|
|
|
|
|
triangleBuffer = make_unique<SimulationBuffer>(triangles.data(), triangles.size() * sizeof(Triangle)); |
|
|
|
|
|
|
|
tetrahedronBuffer = make_unique<SimulationBuffer>(tetrahedra.data(), tetrahedra.size() * sizeof(Tetrahedron)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Simulation::createComputePipelines() { |
|
|
|
|
|
|
|
vector<VkDescriptorSetLayout> layouts; |
|
|
|
|
|
|
|
vector<VkPushConstantRange> pushRanges; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
layouts.push_back(descriptorPool->layouts[DescriptorSet::MESH]); |
|
|
|
|
|
|
|
pbdPipeline = unique_ptr<ComputePipeline>(new ComputePipeline("shaders/pbd.spv", layouts)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
layouts.clear(); |
|
|
|
|
|
|
|
pushRanges.clear(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
layouts.push_back(descriptorPool->layouts[DescriptorSet::MESH]); |
|
|
|
|
|
|
|
pushRanges.push_back({ |
|
|
|
|
|
|
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, |
|
|
|
|
|
|
|
.offset = 0, |
|
|
|
|
|
|
|
.size = sizeof(uint32_t) |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
normalPipeline = unique_ptr<ComputePipeline>(new ComputePipeline("shaders/normal.spv", layouts, pushRanges)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|