Move drawing into dedicated VulkanglTF class
Comments, code-cleanup
This commit is contained in:
parent
9fa9a4b46b
commit
2966d0ee5d
1 changed files with 45 additions and 40 deletions
|
|
@ -41,13 +41,13 @@
|
||||||
#define ENABLE_VALIDATION false
|
#define ENABLE_VALIDATION false
|
||||||
|
|
||||||
// Contains everything required to render a glTF model in Vulkan
|
// Contains everything required to render a glTF model in Vulkan
|
||||||
// This class is very simplified but retains the basic glTF structure
|
// This class is heavily simplified (compared to glTF's feature set) but retains the basic glTF structure
|
||||||
class VulkanglTFModel
|
class VulkanglTFModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// The class requires some Vulkan objects so it can create it's own resources
|
// The class requires some Vulkan objects so it can create it's own resources
|
||||||
vks::VulkanDevice* vulkanDevice;
|
vks::VulkanDevice* vulkanDevice;
|
||||||
VkQueue copyQueue;
|
VkQueue copyQueue;
|
||||||
|
|
||||||
// The vertex layout for the samples' model
|
// The vertex layout for the samples' model
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
|
|
@ -321,6 +321,40 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
glTF rendering functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Draw a single node including child nodes (if present)
|
||||||
|
void drawglTFNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node node)
|
||||||
|
{
|
||||||
|
if (node.mesh.primitives.size() > 0) {
|
||||||
|
for (VulkanglTFModel::Primitive& primitive : node.mesh.primitives) {
|
||||||
|
if (primitive.indexCount > 0) {
|
||||||
|
// Get the texture index for this primitive
|
||||||
|
VulkanglTFModel::Texture texture = textures[materials[primitive.materialIndex].baseColorTextureIndex];
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &images[texture.imageIndex].descriptorSet, 0, nullptr);
|
||||||
|
vkCmdDrawIndexed(commandBuffer, primitive.indexCount, 1, primitive.firstIndex, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& child : node.children) {
|
||||||
|
drawglTFNode(commandBuffer, pipelineLayout, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the glTF scene starting at the top-level-nodes
|
||||||
|
void draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout)
|
||||||
|
{
|
||||||
|
// All vertices and indices are stored in single buffers, so we only need to bind once
|
||||||
|
VkDeviceSize offsets[1] = { 0 };
|
||||||
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertices.buffer, offsets);
|
||||||
|
vkCmdBindIndexBuffer(commandBuffer, indices.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
// Render all nodes at top-level
|
||||||
|
for (auto& node : nodes) {
|
||||||
|
drawglTFNode(commandBuffer, pipelineLayout, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -423,44 +457,13 @@ public:
|
||||||
// Bind scene matrices descriptor to set 0
|
// Bind scene matrices descriptor to set 0
|
||||||
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
|
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
|
||||||
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, wireframe ? pipelines.wireframe : pipelines.solid);
|
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, wireframe ? pipelines.wireframe : pipelines.solid);
|
||||||
drawglTFModel(drawCmdBuffers[i]);
|
glTFModel.draw(drawCmdBuffers[i], pipelineLayout);
|
||||||
drawUI(drawCmdBuffers[i]);
|
drawUI(drawCmdBuffers[i]);
|
||||||
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
||||||
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
glTF rendering functions
|
|
||||||
*/
|
|
||||||
void drawglTFNode(VkCommandBuffer commandBuffer, VulkanglTFModel::Node node)
|
|
||||||
{
|
|
||||||
if (node.mesh.primitives.size() > 0) {
|
|
||||||
for (VulkanglTFModel::Primitive& primitive : node.mesh.primitives) {
|
|
||||||
if (primitive.indexCount > 0) {
|
|
||||||
// @todo: link mat to node
|
|
||||||
VulkanglTFModel::Texture texture = glTFModel.textures[glTFModel.materials[primitive.materialIndex].baseColorTextureIndex];
|
|
||||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &glTFModel.images[texture.imageIndex].descriptorSet, 0, nullptr);
|
|
||||||
vkCmdDrawIndexed(commandBuffer, primitive.indexCount, 1, primitive.firstIndex, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto& child : node.children) {
|
|
||||||
drawglTFNode(commandBuffer, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawglTFModel(VkCommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
// All vertices and indices are stored in single buffers, so we only need to bind once
|
|
||||||
VkDeviceSize offsets[1] = { 0 };
|
|
||||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &glTFModel.vertices.buffer, offsets);
|
|
||||||
vkCmdBindIndexBuffer(commandBuffer, glTFModel.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
|
|
||||||
for (auto& node : glTFModel.nodes) {
|
|
||||||
drawglTFNode(commandBuffer, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo
|
// @todo
|
||||||
void loadglTF(std::string filename)
|
void loadglTF(std::string filename)
|
||||||
{
|
{
|
||||||
|
|
@ -486,6 +489,7 @@ public:
|
||||||
bool fileLoaded = gltfContext.LoadASCIIFromFile(&glTFInput, &error, &warning, filename);
|
bool fileLoaded = gltfContext.LoadASCIIFromFile(&glTFInput, &error, &warning, filename);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Pass some Vulkan resources required for setup and rendering to the glTF model loading class
|
||||||
glTFModel.vulkanDevice = vulkanDevice;
|
glTFModel.vulkanDevice = vulkanDevice;
|
||||||
glTFModel.copyQueue = queue;
|
glTFModel.copyQueue = queue;
|
||||||
|
|
||||||
|
|
@ -508,6 +512,10 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create and upload vertex and index buffer
|
||||||
|
// We will be using one single vertex buffer and one single index buffer for the whole glTF scene
|
||||||
|
// Primitives (of the glTF model) will then index into these using index offsets
|
||||||
|
|
||||||
size_t vertexBufferSize = vertexBuffer.size() * sizeof(VulkanglTFModel::Vertex);
|
size_t vertexBufferSize = vertexBuffer.size() * sizeof(VulkanglTFModel::Vertex);
|
||||||
size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t);
|
size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t);
|
||||||
glTFModel.indices.count = static_cast<uint32_t>(indexBuffer.size());
|
glTFModel.indices.count = static_cast<uint32_t>(indexBuffer.size());
|
||||||
|
|
@ -517,8 +525,7 @@ public:
|
||||||
VkDeviceMemory memory;
|
VkDeviceMemory memory;
|
||||||
} vertexStaging, indexStaging;
|
} vertexStaging, indexStaging;
|
||||||
|
|
||||||
// Create staging buffers
|
// Create host visible staging buffers (source)
|
||||||
// Vertex data
|
|
||||||
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
|
@ -535,15 +542,13 @@ public:
|
||||||
&indexStaging.memory,
|
&indexStaging.memory,
|
||||||
indexBuffer.data()));
|
indexBuffer.data()));
|
||||||
|
|
||||||
// Create device local buffers
|
// Create device local buffers (targat)
|
||||||
// Vertex buffer
|
|
||||||
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
vertexBufferSize,
|
vertexBufferSize,
|
||||||
&glTFModel.vertices.buffer,
|
&glTFModel.vertices.buffer,
|
||||||
&glTFModel.vertices.memory));
|
&glTFModel.vertices.memory));
|
||||||
// Index buffer
|
|
||||||
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
|
|
@ -553,7 +558,6 @@ public:
|
||||||
|
|
||||||
// Copy data from staging buffers (host) do device local buffer (gpu)
|
// Copy data from staging buffers (host) do device local buffer (gpu)
|
||||||
VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
|
|
||||||
VkBufferCopy copyRegion = {};
|
VkBufferCopy copyRegion = {};
|
||||||
|
|
||||||
copyRegion.size = vertexBufferSize;
|
copyRegion.size = vertexBufferSize;
|
||||||
|
|
@ -574,6 +578,7 @@ public:
|
||||||
|
|
||||||
VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
|
VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
|
||||||
|
|
||||||
|
// Free staging resources
|
||||||
vkDestroyBuffer(device, vertexStaging.buffer, nullptr);
|
vkDestroyBuffer(device, vertexStaging.buffer, nullptr);
|
||||||
vkFreeMemory(device, vertexStaging.memory, nullptr);
|
vkFreeMemory(device, vertexStaging.memory, nullptr);
|
||||||
vkDestroyBuffer(device, indexStaging.buffer, nullptr);
|
vkDestroyBuffer(device, indexStaging.buffer, nullptr);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue