Code restructuring, cleanup and simplification
This commit is contained in:
parent
76bda56784
commit
15124e8232
2 changed files with 190 additions and 264 deletions
|
|
@ -1,83 +1,16 @@
|
||||||
/*
|
/*
|
||||||
* Vulkan Example - Passing vertex attributes using interleaved and separate buffers
|
* Vulkan Example - Passing vertex attributes using interleaved and separate buffers
|
||||||
*
|
*
|
||||||
* Copyright (C) 2021 by Sascha Willems - www.saschawillems.de
|
* Copyright (C) 2022 by Sascha Willems - www.saschawillems.de
|
||||||
*
|
*
|
||||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "vertexattributes.h"
|
#include "vertexattributes.h"
|
||||||
|
|
||||||
/*
|
void VulkanExample::loadSceneNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, Node* parent, std::vector<uint32_t>& indexBuffer, std::vector<Vertex>& vertexBuffer)
|
||||||
Vulkan glTF scene class
|
|
||||||
*/
|
|
||||||
|
|
||||||
VulkanglTFScene::~VulkanglTFScene()
|
|
||||||
{
|
{
|
||||||
// Release all Vulkan resources allocated for the model
|
Node node{};
|
||||||
vertices.destroy();
|
|
||||||
indices.destroy();
|
|
||||||
for (Image image : images) {
|
|
||||||
vkDestroyImageView(vulkanDevice->logicalDevice, image.texture.view, nullptr);
|
|
||||||
vkDestroyImage(vulkanDevice->logicalDevice, image.texture.image, nullptr);
|
|
||||||
vkDestroySampler(vulkanDevice->logicalDevice, image.texture.sampler, nullptr);
|
|
||||||
vkFreeMemory(vulkanDevice->logicalDevice, image.texture.deviceMemory, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
glTF loading functions
|
|
||||||
|
|
||||||
The following functions take a glTF input model loaded via tinyglTF and convert all required data into our own structure
|
|
||||||
*/
|
|
||||||
|
|
||||||
void VulkanglTFScene::loadImages(tinygltf::Model& input)
|
|
||||||
{
|
|
||||||
// POI: The textures for the glTF file used in this sample are stored as external ktx files, so we can directly load them from disk without the need for conversion
|
|
||||||
images.resize(input.images.size());
|
|
||||||
for (size_t i = 0; i < input.images.size(); i++) {
|
|
||||||
tinygltf::Image& glTFImage = input.images[i];
|
|
||||||
images[i].texture.loadFromFile(path + "/" + glTFImage.uri, VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, copyQueue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanglTFScene::loadTextures(tinygltf::Model& input)
|
|
||||||
{
|
|
||||||
textures.resize(input.textures.size());
|
|
||||||
for (size_t i = 0; i < input.textures.size(); i++) {
|
|
||||||
textures[i].imageIndex = input.textures[i].source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanglTFScene::loadMaterials(tinygltf::Model& input)
|
|
||||||
{
|
|
||||||
materials.resize(input.materials.size());
|
|
||||||
for (size_t i = 0; i < input.materials.size(); i++) {
|
|
||||||
// We only read the most basic properties required for our sample
|
|
||||||
tinygltf::Material glTFMaterial = input.materials[i];
|
|
||||||
// Get the base color factor
|
|
||||||
if (glTFMaterial.values.find("baseColorFactor") != glTFMaterial.values.end()) {
|
|
||||||
materials[i].baseColorFactor = glm::make_vec4(glTFMaterial.values["baseColorFactor"].ColorFactor().data());
|
|
||||||
}
|
|
||||||
// Get base color texture index
|
|
||||||
if (glTFMaterial.values.find("baseColorTexture") != glTFMaterial.values.end()) {
|
|
||||||
materials[i].baseColorTextureIndex = glTFMaterial.values["baseColorTexture"].TextureIndex();
|
|
||||||
}
|
|
||||||
// Get the normal map texture index
|
|
||||||
if (glTFMaterial.additionalValues.find("normalTexture") != glTFMaterial.additionalValues.end()) {
|
|
||||||
materials[i].normalTextureIndex = glTFMaterial.additionalValues["normalTexture"].TextureIndex();
|
|
||||||
}
|
|
||||||
// Get some additional material parameters that are used in this sample
|
|
||||||
materials[i].alphaMode = glTFMaterial.alphaMode;
|
|
||||||
materials[i].alphaCutOff = (float)glTFMaterial.alphaCutoff;
|
|
||||||
materials[i].doubleSided = glTFMaterial.doubleSided;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanglTFScene::loadNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, VulkanglTFScene::Node* parent, std::vector<uint32_t>& indexBuffer, std::vector<VulkanglTFScene::Vertex>& vertexBuffer)
|
|
||||||
{
|
|
||||||
VulkanglTFScene::Node node{};
|
|
||||||
node.name = inputNode.name;
|
|
||||||
|
|
||||||
// Get the local node matrix
|
// Get the local node matrix
|
||||||
// It's either made up from translation, rotation, scale or a 4x4 matrix
|
// It's either made up from translation, rotation, scale or a 4x4 matrix
|
||||||
|
|
@ -99,7 +32,7 @@ void VulkanglTFScene::loadNode(const tinygltf::Node& inputNode, const tinygltf::
|
||||||
// Load node's children
|
// Load node's children
|
||||||
if (inputNode.children.size() > 0) {
|
if (inputNode.children.size() > 0) {
|
||||||
for (size_t i = 0; i < inputNode.children.size(); i++) {
|
for (size_t i = 0; i < inputNode.children.size(); i++) {
|
||||||
loadNode(input.nodes[inputNode.children[i]], input, &node, indexBuffer, vertexBuffer);
|
loadSceneNode(input.nodes[inputNode.children[i]], input, &node, indexBuffer, vertexBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,54 +151,6 @@ void VulkanglTFScene::loadNode(const tinygltf::Node& inputNode, const tinygltf::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorImageInfo VulkanglTFScene::getTextureDescriptor(const size_t index)
|
|
||||||
{
|
|
||||||
return images[index].texture.descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
glTF rendering functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Draw a single node including child nodes (if present)
|
|
||||||
void VulkanglTFScene::drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFScene::Node node, bool separate)
|
|
||||||
{
|
|
||||||
if (!node.visible) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (node.mesh.primitives.size() > 0) {
|
|
||||||
// Pass the node's matrix via push constants
|
|
||||||
// Traverse the node hierarchy to the top-most parent to get the final matrix of the current node
|
|
||||||
|
|
||||||
PushConstBlock pushConstBlock;
|
|
||||||
|
|
||||||
glm::mat4 nodeMatrix = node.matrix;
|
|
||||||
VulkanglTFScene::Node* currentParent = node.parent;
|
|
||||||
while (currentParent) {
|
|
||||||
nodeMatrix = currentParent->matrix * nodeMatrix;
|
|
||||||
currentParent = currentParent->parent;
|
|
||||||
}
|
|
||||||
for (VulkanglTFScene::Primitive& primitive : node.mesh.primitives) {
|
|
||||||
if (primitive.indexCount > 0) {
|
|
||||||
VulkanglTFScene::Material& material = materials[primitive.materialIndex];
|
|
||||||
pushConstBlock.nodeMatrix = nodeMatrix;
|
|
||||||
pushConstBlock.alphaMask = (material.alphaMode == "MASK");
|
|
||||||
pushConstBlock.alphaMaskCutoff = material.alphaCutOff;
|
|
||||||
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlock), &pushConstBlock);
|
|
||||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &material.descriptorSet, 0, nullptr);
|
|
||||||
vkCmdDrawIndexed(commandBuffer, primitive.indexCount, 1, primitive.firstIndex, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto& child : node.children) {
|
|
||||||
drawNode(commandBuffer, pipelineLayout, child, separate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Vulkan Example class
|
|
||||||
*/
|
|
||||||
|
|
||||||
VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||||
{
|
{
|
||||||
title = "Separate vertex attribute buffers";
|
title = "Separate vertex attribute buffers";
|
||||||
|
|
@ -278,10 +163,23 @@ VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||||
|
|
||||||
VulkanExample::~VulkanExample()
|
VulkanExample::~VulkanExample()
|
||||||
{
|
{
|
||||||
|
vkDestroyPipeline(device, pipelines.vertexAttributesInterleaved, nullptr);
|
||||||
|
vkDestroyPipeline(device, pipelines.vertexAttributesSeparate, nullptr);
|
||||||
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||||
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.matrices, nullptr);
|
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.matrices, nullptr);
|
||||||
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.textures, nullptr);
|
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.textures, nullptr);
|
||||||
|
indices.destroy();
|
||||||
shaderData.buffer.destroy();
|
shaderData.buffer.destroy();
|
||||||
|
vertexAttibuteBuffers.normal.destroy();
|
||||||
|
vertexAttibuteBuffers.pos.destroy();
|
||||||
|
vertexAttibuteBuffers.tangent.destroy();
|
||||||
|
vertexAttibuteBuffers.uv.destroy();
|
||||||
|
for (Image image : scene.images) {
|
||||||
|
vkDestroyImageView(vulkanDevice->logicalDevice, image.texture.view, nullptr);
|
||||||
|
vkDestroyImage(vulkanDevice->logicalDevice, image.texture.image, nullptr);
|
||||||
|
vkDestroySampler(vulkanDevice->logicalDevice, image.texture.sampler, nullptr);
|
||||||
|
vkFreeMemory(vulkanDevice->logicalDevice, image.texture.deviceMemory, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanExample::getEnabledFeatures()
|
void VulkanExample::getEnabledFeatures()
|
||||||
|
|
@ -325,21 +223,21 @@ void VulkanExample::buildCommandBuffers()
|
||||||
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);
|
||||||
|
|
||||||
// Use the same index buffer, no matter how vertex attributes are passed
|
// Use the same index buffer, no matter how vertex attributes are passed
|
||||||
vkCmdBindIndexBuffer(drawCmdBuffers[i], glTFScene.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
|
vkCmdBindIndexBuffer(drawCmdBuffers[i], indices.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
|
||||||
if (vertexAttributeSettings == VertexAttributeSettings::separate) {
|
if (vertexAttributeSettings == VertexAttributeSettings::separate) {
|
||||||
// Using separate vertex attribute bindings requires binding all attribute buffers
|
// Using separate vertex attribute bindings requires binding multiple attribute buffers
|
||||||
VkDeviceSize offsets[4] = { 0, 0, 0, 0 };
|
VkDeviceSize offsets[4] = { 0, 0, 0, 0 };
|
||||||
std::array<VkBuffer, 4> buffers = { vertexAttibuteBuffers.pos.buffer, vertexAttibuteBuffers.normal.buffer, vertexAttibuteBuffers.uv.buffer, vertexAttibuteBuffers.tangent.buffer };
|
std::array<VkBuffer, 4> buffers = { vertexAttibuteBuffers.pos.buffer, vertexAttibuteBuffers.normal.buffer, vertexAttibuteBuffers.uv.buffer, vertexAttibuteBuffers.tangent.buffer };
|
||||||
vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, static_cast<uint32_t>(buffers.size()), buffers.data(), offsets);
|
vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, static_cast<uint32_t>(buffers.size()), buffers.data(), offsets);
|
||||||
} else {
|
} else {
|
||||||
// Using interleaved attribute bindings only requires one buffer bind
|
// Using interleaved attribute bindings only requires one buffer to be bound
|
||||||
VkDeviceSize offsets[1] = { 0 };
|
VkDeviceSize offsets[1] = { 0 };
|
||||||
vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &glTFScene.vertices.buffer, offsets);
|
vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &interleavedVertexBuffer.buffer, offsets);
|
||||||
}
|
}
|
||||||
// Render all nodes starting at top-level
|
// Render all nodes starting at top-level
|
||||||
for (auto& node : glTFScene.nodes) {
|
for (auto& node : nodes) {
|
||||||
glTFScene.drawNode(drawCmdBuffers[i], pipelineLayout, node, vertexAttributeSettings == VertexAttributeSettings::separate);
|
drawSceneNode(drawCmdBuffers[i], node);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawUI(drawCmdBuffers[i]);
|
drawUI(drawCmdBuffers[i]);
|
||||||
|
|
@ -363,42 +261,73 @@ void VulkanExample::loadglTFFile(std::string filename)
|
||||||
#endif
|
#endif
|
||||||
bool fileLoaded = gltfContext.LoadASCIIFromFile(&glTFInput, &error, &warning, filename);
|
bool fileLoaded = gltfContext.LoadASCIIFromFile(&glTFInput, &error, &warning, filename);
|
||||||
|
|
||||||
// Pass some Vulkan resources required for setup and rendering to the glTF model loading class
|
|
||||||
glTFScene.vulkanDevice = vulkanDevice;
|
|
||||||
glTFScene.copyQueue = queue;
|
|
||||||
|
|
||||||
size_t pos = filename.find_last_of('/');
|
size_t pos = filename.find_last_of('/');
|
||||||
glTFScene.path = filename.substr(0, pos);
|
std::string path = filename.substr(0, pos);
|
||||||
|
|
||||||
std::vector<uint32_t> indexBuffer;
|
|
||||||
std::vector<VulkanglTFScene::Vertex> vertexBuffer;
|
|
||||||
|
|
||||||
if (!fileLoaded) {
|
if (!fileLoaded) {
|
||||||
vks::tools::exitFatal("Could not open the glTF file.\n\nThe file is part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1);
|
vks::tools::exitFatal("Could not open the glTF file.\n\nThe file is part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
glTFScene.loadImages(glTFInput);
|
|
||||||
glTFScene.loadMaterials(glTFInput);
|
// Load images
|
||||||
glTFScene.loadTextures(glTFInput);
|
scene.images.resize(glTFInput.images.size());
|
||||||
|
for (size_t i = 0; i < glTFInput.images.size(); i++) {
|
||||||
|
tinygltf::Image& glTFImage = glTFInput.images[i];
|
||||||
|
scene.images[i].texture.loadFromFile(path + "/" + glTFImage.uri, VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
|
||||||
|
}
|
||||||
|
// Load textures
|
||||||
|
scene.textures.resize(glTFInput.textures.size());
|
||||||
|
for (size_t i = 0; i < glTFInput.textures.size(); i++) {
|
||||||
|
scene.textures[i].imageIndex = glTFInput.textures[i].source;
|
||||||
|
}
|
||||||
|
// Load materials
|
||||||
|
scene.materials.resize(glTFInput.materials.size());
|
||||||
|
for (size_t i = 0; i < glTFInput.materials.size(); i++) {
|
||||||
|
// We only read the most basic properties required for our sample
|
||||||
|
tinygltf::Material glTFMaterial = glTFInput.materials[i];
|
||||||
|
// Get the base color factor
|
||||||
|
if (glTFMaterial.values.find("baseColorFactor") != glTFMaterial.values.end()) {
|
||||||
|
scene.materials[i].baseColorFactor = glm::make_vec4(glTFMaterial.values["baseColorFactor"].ColorFactor().data());
|
||||||
|
}
|
||||||
|
// Get base color texture index
|
||||||
|
if (glTFMaterial.values.find("baseColorTexture") != glTFMaterial.values.end()) {
|
||||||
|
scene.materials[i].baseColorTextureIndex = glTFMaterial.values["baseColorTexture"].TextureIndex();
|
||||||
|
}
|
||||||
|
// Get the normal map texture index
|
||||||
|
if (glTFMaterial.additionalValues.find("normalTexture") != glTFMaterial.additionalValues.end()) {
|
||||||
|
scene.materials[i].normalTextureIndex = glTFMaterial.additionalValues["normalTexture"].TextureIndex();
|
||||||
|
}
|
||||||
|
// Get some additional material parameters that are used in this sample
|
||||||
|
scene.materials[i].alphaMode = glTFMaterial.alphaMode;
|
||||||
|
scene.materials[i].alphaCutOff = (float)glTFMaterial.alphaCutoff;
|
||||||
|
}
|
||||||
|
// Load nodes
|
||||||
const tinygltf::Scene& scene = glTFInput.scenes[0];
|
const tinygltf::Scene& scene = glTFInput.scenes[0];
|
||||||
for (size_t i = 0; i < scene.nodes.size(); i++) {
|
for (size_t i = 0; i < scene.nodes.size(); i++) {
|
||||||
const tinygltf::Node node = glTFInput.nodes[scene.nodes[i]];
|
const tinygltf::Node node = glTFInput.nodes[scene.nodes[i]];
|
||||||
glTFScene.loadNode(node, glTFInput, nullptr, indexBuffer, vertexBuffer);
|
loadSceneNode(node, glTFInput, nullptr, indexBuffer, vertexBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Upload vertex and index buffers */
|
uploadVertexData();
|
||||||
|
}
|
||||||
|
|
||||||
/* Anonymous functions to simplify buffer creation */
|
void VulkanExample::uploadVertexData()
|
||||||
/* Create a staging buffer used as a source for copies */
|
{
|
||||||
|
// Upload vertex and index buffers
|
||||||
|
|
||||||
|
// Anonymous functions to simplify buffer creation
|
||||||
|
|
||||||
|
// Create a staging buffer used as a source for copies
|
||||||
auto createStagingBuffer = [this](vks::Buffer& buffer, void* data, VkDeviceSize size) {
|
auto createStagingBuffer = [this](vks::Buffer& buffer, void* data, VkDeviceSize size) {
|
||||||
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &buffer, size, data));
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &buffer, size, data));
|
||||||
};
|
};
|
||||||
/* Create a device local buffer used as a target for copies*/
|
|
||||||
|
// Create a device local buffer used as a target for copies
|
||||||
auto createDeviceBuffer = [this](vks::Buffer& buffer, VkDeviceSize size, VkBufferUsageFlags usageFlags = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) {
|
auto createDeviceBuffer = [this](vks::Buffer& buffer, VkDeviceSize size, VkBufferUsageFlags usageFlags = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) {
|
||||||
VK_CHECK_RESULT(vulkanDevice->createBuffer(usageFlags | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &buffer, size));
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(usageFlags | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &buffer, size));
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t vertexBufferSize = vertexBuffer.size() * sizeof(VulkanglTFScene::Vertex);
|
size_t vertexBufferSize = vertexBuffer.size() * sizeof(Vertex);
|
||||||
size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t);
|
size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t);
|
||||||
|
|
||||||
vks::Buffer vertexStaging, indexStaging;
|
vks::Buffer vertexStaging, indexStaging;
|
||||||
|
|
@ -406,18 +335,18 @@ void VulkanExample::loadglTFFile(std::string filename)
|
||||||
createStagingBuffer(indexStaging, indexBuffer.data(), indexBufferSize);
|
createStagingBuffer(indexStaging, indexBuffer.data(), indexBufferSize);
|
||||||
createStagingBuffer(vertexStaging, vertexBuffer.data(), vertexBufferSize);
|
createStagingBuffer(vertexStaging, vertexBuffer.data(), vertexBufferSize);
|
||||||
|
|
||||||
createDeviceBuffer(glTFScene.indices, indexStaging.size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
createDeviceBuffer(indices, indexStaging.size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
||||||
createDeviceBuffer(glTFScene.vertices, vertexStaging.size);
|
createDeviceBuffer(interleavedVertexBuffer, vertexStaging.size);
|
||||||
|
|
||||||
// Copy data from staging buffers (host) do device local buffer (gpu)
|
// Copy data from staging buffers (host) do device local buffer (gpu)
|
||||||
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
VkBufferCopy copyRegion = {};
|
VkBufferCopy copyRegion = {};
|
||||||
|
|
||||||
copyRegion.size = vertexBufferSize;
|
copyRegion.size = vertexBufferSize;
|
||||||
vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, glTFScene.vertices.buffer, 1, ©Region);
|
vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, interleavedVertexBuffer.buffer, 1, ©Region);
|
||||||
|
|
||||||
copyRegion.size = indexBufferSize;
|
copyRegion.size = indexBufferSize;
|
||||||
vkCmdCopyBuffer(copyCmd, indexStaging.buffer, glTFScene.indices.buffer, 1, ©Region);
|
vkCmdCopyBuffer(copyCmd, indexStaging.buffer, indices.buffer, 1, ©Region);
|
||||||
|
|
||||||
vulkanDevice->flushCommandBuffer(copyCmd, queue, true);
|
vulkanDevice->flushCommandBuffer(copyCmd, queue, true);
|
||||||
|
|
||||||
|
|
@ -438,10 +367,10 @@ void VulkanExample::loadglTFFile(std::string filename)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::array<vks::Buffer, 4> stagingBuffers;
|
std::array<vks::Buffer, 4> stagingBuffers;
|
||||||
createStagingBuffer(stagingBuffers[0], glTFScene.vertexAttributes.pos.data(), glTFScene.vertexAttributes.pos.size() * sizeof(glTFScene.vertexAttributes.pos[0]));
|
createStagingBuffer(stagingBuffers[0], vertexAttributes.pos.data(), vertexAttributes.pos.size() * sizeof(vertexAttributes.pos[0]));
|
||||||
createStagingBuffer(stagingBuffers[1], glTFScene.vertexAttributes.normal.data(), glTFScene.vertexAttributes.normal.size() * sizeof(glTFScene.vertexAttributes.normal[0]));
|
createStagingBuffer(stagingBuffers[1], vertexAttributes.normal.data(), vertexAttributes.normal.size() * sizeof(vertexAttributes.normal[0]));
|
||||||
createStagingBuffer(stagingBuffers[2], glTFScene.vertexAttributes.uv.data(), glTFScene.vertexAttributes.uv.size() * sizeof(glTFScene.vertexAttributes.uv[0]));
|
createStagingBuffer(stagingBuffers[2], vertexAttributes.uv.data(), vertexAttributes.uv.size() * sizeof(vertexAttributes.uv[0]));
|
||||||
createStagingBuffer(stagingBuffers[3], glTFScene.vertexAttributes.tangent.data(), glTFScene.vertexAttributes.tangent.size() * sizeof(glTFScene.vertexAttributes.tangent[0]));
|
createStagingBuffer(stagingBuffers[3], vertexAttributes.tangent.data(), vertexAttributes.tangent.size() * sizeof(vertexAttributes.tangent[0]));
|
||||||
|
|
||||||
createDeviceBuffer(vertexAttibuteBuffers.pos, stagingBuffers[0].size);
|
createDeviceBuffer(vertexAttibuteBuffers.pos, stagingBuffers[0].size);
|
||||||
createDeviceBuffer(vertexAttibuteBuffers.normal, stagingBuffers[1].size);
|
createDeviceBuffer(vertexAttibuteBuffers.normal, stagingBuffers[1].size);
|
||||||
|
|
@ -470,8 +399,11 @@ void VulkanExample::loadglTFFile(std::string filename)
|
||||||
The index buffer is always the same, no matter how we pass the vertex attributes
|
The index buffer is always the same, no matter how we pass the vertex attributes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// @todo: clear
|
// @todo: clear
|
||||||
|
for (size_t i = 0; i < 4; i++) {
|
||||||
|
vkDestroyBuffer(device, stagingBuffers[i].buffer, nullptr);
|
||||||
|
vkFreeMemory(device, stagingBuffers[i].memory, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanExample::loadAssets()
|
void VulkanExample::loadAssets()
|
||||||
|
|
@ -485,10 +417,10 @@ void VulkanExample::setupDescriptors()
|
||||||
// Two combined image samplers per material as each material uses color and normal maps
|
// Two combined image samplers per material as each material uses color and normal maps
|
||||||
std::vector<VkDescriptorPoolSize> poolSizes = {
|
std::vector<VkDescriptorPoolSize> poolSizes = {
|
||||||
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
|
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
|
||||||
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, static_cast<uint32_t>(glTFScene.materials.size()) * 2),
|
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, static_cast<uint32_t>(scene.materials.size()) * 2),
|
||||||
};
|
};
|
||||||
// One set for matrices and one per model image/texture
|
// One set for matrices and one per model image/texture
|
||||||
const uint32_t maxSetCount = static_cast<uint32_t>(glTFScene.images.size()) + 1;
|
const uint32_t maxSetCount = static_cast<uint32_t>(scene.images.size()) + 1;
|
||||||
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, maxSetCount);
|
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, maxSetCount);
|
||||||
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
|
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
|
||||||
// Descriptor set layout for passing matrices
|
// Descriptor set layout for passing matrices
|
||||||
|
|
@ -525,11 +457,11 @@ void VulkanExample::setupDescriptors()
|
||||||
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
|
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
|
||||||
|
|
||||||
// Descriptor sets for the materials
|
// Descriptor sets for the materials
|
||||||
for (auto& material : glTFScene.materials) {
|
for (auto& material : scene.materials) {
|
||||||
const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.textures, 1);
|
const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.textures, 1);
|
||||||
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &material.descriptorSet));
|
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &material.descriptorSet));
|
||||||
VkDescriptorImageInfo colorMap = glTFScene.getTextureDescriptor(material.baseColorTextureIndex);
|
VkDescriptorImageInfo colorMap = scene.images[material.baseColorTextureIndex].texture.descriptor;
|
||||||
VkDescriptorImageInfo normalMap = glTFScene.getTextureDescriptor(material.normalTextureIndex);
|
VkDescriptorImageInfo normalMap = scene.images[material.normalTextureIndex].texture.descriptor;
|
||||||
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
|
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
|
||||||
vks::initializers::writeDescriptorSet(material.descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &colorMap),
|
vks::initializers::writeDescriptorSet(material.descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &colorMap),
|
||||||
vks::initializers::writeDescriptorSet(material.descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &normalMap),
|
vks::initializers::writeDescriptorSet(material.descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &normalMap),
|
||||||
|
|
@ -554,13 +486,13 @@ void VulkanExample::preparePipelines()
|
||||||
|
|
||||||
// @todo: comment
|
// @todo: comment
|
||||||
const std::vector<VkVertexInputBindingDescription> vertexInputBindingsInterleaved = {
|
const std::vector<VkVertexInputBindingDescription> vertexInputBindingsInterleaved = {
|
||||||
vks::initializers::vertexInputBindingDescription(0, sizeof(VulkanglTFScene::Vertex), VK_VERTEX_INPUT_RATE_VERTEX),
|
vks::initializers::vertexInputBindingDescription(0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX),
|
||||||
};
|
};
|
||||||
const std::vector<VkVertexInputAttributeDescription> vertexInputAttributesInterleaved = {
|
const std::vector<VkVertexInputAttributeDescription> vertexInputAttributesInterleaved = {
|
||||||
vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFScene::Vertex, pos)),
|
vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, pos)),
|
||||||
vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFScene::Vertex, normal)),
|
vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal)),
|
||||||
vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFScene::Vertex, uv)),
|
vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, uv)),
|
||||||
vks::initializers::vertexInputAttributeDescription(0, 3, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFScene::Vertex, tangent)),
|
vks::initializers::vertexInputAttributeDescription(0, 3, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, tangent)),
|
||||||
};
|
};
|
||||||
|
|
||||||
// @todo: comment
|
// @todo: comment
|
||||||
|
|
@ -592,7 +524,6 @@ void VulkanExample::preparePipelines()
|
||||||
shaderStages[0] = loadShader(getShadersPath() + "vertexattributes/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
shaderStages[0] = loadShader(getShadersPath() + "vertexattributes/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
shaderStages[1] = loadShader(getShadersPath() + "vertexattributes/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
shaderStages[1] = loadShader(getShadersPath() + "vertexattributes/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
|
||||||
//rasterizationStateCI.cullMode = material.doubleSided ? VK_CULL_MODE_NONE : VK_CULL_MODE_BACK_BIT;
|
|
||||||
vertexInputStateCI = vks::initializers::pipelineVertexInputStateCreateInfo(vertexInputBindingsInterleaved, vertexInputAttributesInterleaved);
|
vertexInputStateCI = vks::initializers::pipelineVertexInputStateCreateInfo(vertexInputBindingsInterleaved, vertexInputAttributesInterleaved);
|
||||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.vertexAttributesInterleaved));
|
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.vertexAttributesInterleaved));
|
||||||
|
|
||||||
|
|
@ -630,6 +561,33 @@ void VulkanExample::prepare()
|
||||||
prepared = true;
|
prepared = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VulkanExample::drawSceneNode(VkCommandBuffer commandBuffer, Node node)
|
||||||
|
{
|
||||||
|
if (node.mesh.primitives.size() > 0) {
|
||||||
|
PushConstBlock pushConstBlock;
|
||||||
|
glm::mat4 nodeMatrix = node.matrix;
|
||||||
|
Node* currentParent = node.parent;
|
||||||
|
while (currentParent) {
|
||||||
|
nodeMatrix = currentParent->matrix * nodeMatrix;
|
||||||
|
currentParent = currentParent->parent;
|
||||||
|
}
|
||||||
|
for (Primitive& primitive : node.mesh.primitives) {
|
||||||
|
if (primitive.indexCount > 0) {
|
||||||
|
Material& material = scene.materials[primitive.materialIndex];
|
||||||
|
pushConstBlock.nodeMatrix = nodeMatrix;
|
||||||
|
pushConstBlock.alphaMask = (material.alphaMode == "MASK");
|
||||||
|
pushConstBlock.alphaMaskCutoff = material.alphaCutOff;
|
||||||
|
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlock), &pushConstBlock);
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &material.descriptorSet, 0, nullptr);
|
||||||
|
vkCmdDrawIndexed(commandBuffer, primitive.indexCount, 1, primitive.firstIndex, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& child : node.children) {
|
||||||
|
drawSceneNode(commandBuffer, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VulkanExample::render()
|
void VulkanExample::render()
|
||||||
{
|
{
|
||||||
renderFrame();
|
renderFrame();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Vulkan Example - Passing vertex attributes using interleaved and separate buffers
|
* Vulkan Example - Passing vertex attributes using interleaved and separate buffers
|
||||||
*
|
*
|
||||||
* Copyright (C) 2021 by Sascha Willems - www.saschawillems.de
|
* Copyright (C) 2022 by Sascha Willems - www.saschawillems.de
|
||||||
*
|
*
|
||||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||||
*/
|
*/
|
||||||
|
|
@ -26,16 +26,24 @@ struct PushConstBlock {
|
||||||
float alphaMaskCutoff;
|
float alphaMaskCutoff;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Contains everything required to render a basic glTF scene in Vulkan
|
struct Material {
|
||||||
// This class is heavily simplified (compared to glTF's feature set) but retains the basic glTF structure
|
glm::vec4 baseColorFactor = glm::vec4(1.0f);
|
||||||
class VulkanglTFScene
|
uint32_t baseColorTextureIndex;
|
||||||
{
|
uint32_t normalTextureIndex;
|
||||||
public:
|
std::string alphaMode = "OPAQUE";
|
||||||
// The class requires some Vulkan objects so it can create it's own resources
|
float alphaCutOff;
|
||||||
vks::VulkanDevice* vulkanDevice;
|
VkDescriptorSet descriptorSet;
|
||||||
VkQueue copyQueue;
|
};
|
||||||
|
|
||||||
// The vertex layout for the samples' model
|
struct Image {
|
||||||
|
vks::Texture2D texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Texture {
|
||||||
|
int32_t imageIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Layout for the interleaved vertex attributes
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
glm::vec3 pos;
|
glm::vec3 pos;
|
||||||
glm::vec3 normal;
|
glm::vec3 normal;
|
||||||
|
|
@ -43,100 +51,52 @@ public:
|
||||||
glm::vec4 tangent;
|
glm::vec4 tangent;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Single vertex buffer for all primitives
|
struct Primitive {
|
||||||
vks::Buffer vertices;
|
uint32_t firstIndex;
|
||||||
|
uint32_t indexCount;
|
||||||
|
int32_t materialIndex;
|
||||||
|
};
|
||||||
|
struct Mesh {
|
||||||
|
std::vector<Primitive> primitives;
|
||||||
|
};
|
||||||
|
struct Node;
|
||||||
|
struct Node {
|
||||||
|
Node* parent;
|
||||||
|
std::vector<Node> children;
|
||||||
|
Mesh mesh;
|
||||||
|
glm::mat4 matrix;
|
||||||
|
};
|
||||||
|
|
||||||
// Used at loading time
|
// Only used at loading time
|
||||||
struct VertexAttributes {
|
struct VertexAttributes {
|
||||||
std::vector<glm::vec2> uv;
|
std::vector<glm::vec2> uv;
|
||||||
std::vector<glm::vec3> pos, normal;
|
std::vector<glm::vec3> pos, normal;
|
||||||
std::vector<glm::vec4> tangent;
|
std::vector<glm::vec4> tangent;
|
||||||
} vertexAttributes;
|
} vertexAttributes;
|
||||||
|
|
||||||
// Single index buffer for all primitives
|
|
||||||
vks::Buffer indices;
|
|
||||||
|
|
||||||
// The following structures roughly represent the glTF scene structure
|
|
||||||
// To keep things simple, they only contain those properties that are required for this sample
|
|
||||||
struct Node;
|
|
||||||
|
|
||||||
// A primitive contains the data for a single draw call
|
|
||||||
struct Primitive {
|
|
||||||
uint32_t firstIndex;
|
|
||||||
uint32_t indexCount;
|
|
||||||
int32_t materialIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Contains the node's (optional) geometry and can be made up of an arbitrary number of primitives
|
|
||||||
struct Mesh {
|
|
||||||
std::vector<Primitive> primitives;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A node represents an object in the glTF scene graph
|
|
||||||
struct Node {
|
|
||||||
Node* parent;
|
|
||||||
std::vector<Node> children;
|
|
||||||
Mesh mesh;
|
|
||||||
glm::mat4 matrix;
|
|
||||||
std::string name;
|
|
||||||
bool visible = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A glTF material stores information in e.g. the texture that is attached to it and colors
|
|
||||||
struct Material {
|
|
||||||
glm::vec4 baseColorFactor = glm::vec4(1.0f);
|
|
||||||
uint32_t baseColorTextureIndex;
|
|
||||||
uint32_t normalTextureIndex;
|
|
||||||
std::string alphaMode = "OPAQUE";
|
|
||||||
float alphaCutOff;
|
|
||||||
bool doubleSided = false;
|
|
||||||
VkDescriptorSet descriptorSet;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Contains the texture for a single glTF image
|
|
||||||
// Images may be reused by texture objects and are as such separated
|
|
||||||
struct Image {
|
|
||||||
vks::Texture2D texture;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A glTF texture stores a reference to the image and a sampler
|
|
||||||
// In this sample, we are only interested in the image
|
|
||||||
struct Texture {
|
|
||||||
int32_t imageIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Model data
|
|
||||||
*/
|
|
||||||
std::vector<Image> images;
|
|
||||||
std::vector<Texture> textures;
|
|
||||||
std::vector<Material> materials;
|
|
||||||
std::vector<Node> nodes;
|
std::vector<Node> nodes;
|
||||||
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
~VulkanglTFScene();
|
|
||||||
VkDescriptorImageInfo getTextureDescriptor(const size_t index);
|
|
||||||
void loadImages(tinygltf::Model& input);
|
|
||||||
void loadTextures(tinygltf::Model& input);
|
|
||||||
void loadMaterials(tinygltf::Model& input);
|
|
||||||
void loadNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, VulkanglTFScene::Node* parent, std::vector<uint32_t>& indexBuffer, std::vector<VulkanglTFScene::Vertex>& vertexBuffer);
|
|
||||||
void drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFScene::Node node, bool separate);
|
|
||||||
};
|
|
||||||
|
|
||||||
class VulkanExample : public VulkanExampleBase
|
class VulkanExample : public VulkanExampleBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VulkanglTFScene glTFScene;
|
|
||||||
|
|
||||||
enum VertexAttributeSettings { interleaved, separate };
|
enum VertexAttributeSettings { interleaved, separate };
|
||||||
VertexAttributeSettings vertexAttributeSettings = separate;
|
VertexAttributeSettings vertexAttributeSettings = separate;
|
||||||
|
|
||||||
|
std::vector<uint32_t> indexBuffer;
|
||||||
|
std::vector<Vertex> vertexBuffer;
|
||||||
|
|
||||||
// Buffers for the separate vertex attributes
|
// Buffers for the separate vertex attributes
|
||||||
|
// @todo: rename
|
||||||
struct VertexAttributeBuffers {
|
struct VertexAttributeBuffers {
|
||||||
vks::Buffer pos, normal, uv, tangent;
|
vks::Buffer pos, normal, uv, tangent;
|
||||||
} vertexAttibuteBuffers;
|
} vertexAttibuteBuffers;
|
||||||
|
|
||||||
|
// Single vertex buffer for all primitives
|
||||||
|
vks::Buffer interleavedVertexBuffer;
|
||||||
|
|
||||||
|
// Index buffer for all primitives of the scene
|
||||||
|
vks::Buffer indices;
|
||||||
|
|
||||||
struct ShaderData {
|
struct ShaderData {
|
||||||
vks::Buffer buffer;
|
vks::Buffer buffer;
|
||||||
struct Values {
|
struct Values {
|
||||||
|
|
@ -151,19 +111,25 @@ public:
|
||||||
VkPipeline vertexAttributesInterleaved;
|
VkPipeline vertexAttributesInterleaved;
|
||||||
VkPipeline vertexAttributesSeparate;
|
VkPipeline vertexAttributesSeparate;
|
||||||
} pipelines;
|
} pipelines;
|
||||||
|
|
||||||
VkPipelineLayout pipelineLayout;
|
VkPipelineLayout pipelineLayout;
|
||||||
VkDescriptorSet descriptorSet;
|
|
||||||
|
|
||||||
struct DescriptorSetLayouts {
|
struct DescriptorSetLayouts {
|
||||||
VkDescriptorSetLayout matrices;
|
VkDescriptorSetLayout matrices;
|
||||||
VkDescriptorSetLayout textures;
|
VkDescriptorSetLayout textures;
|
||||||
} descriptorSetLayouts;
|
} descriptorSetLayouts;
|
||||||
|
VkDescriptorSet descriptorSet;
|
||||||
|
|
||||||
|
struct Scene {
|
||||||
|
std::vector<Image> images;
|
||||||
|
std::vector<Texture> textures;
|
||||||
|
std::vector<Material> materials;
|
||||||
|
} scene;
|
||||||
|
|
||||||
VulkanExample();
|
VulkanExample();
|
||||||
~VulkanExample();
|
~VulkanExample();
|
||||||
virtual void getEnabledFeatures();
|
virtual void getEnabledFeatures();
|
||||||
void buildCommandBuffers();
|
void buildCommandBuffers();
|
||||||
|
void uploadVertexData();
|
||||||
void loadglTFFile(std::string filename);
|
void loadglTFFile(std::string filename);
|
||||||
void loadAssets();
|
void loadAssets();
|
||||||
void setupDescriptors();
|
void setupDescriptors();
|
||||||
|
|
@ -171,6 +137,8 @@ public:
|
||||||
void prepareUniformBuffers();
|
void prepareUniformBuffers();
|
||||||
void updateUniformBuffers();
|
void updateUniformBuffers();
|
||||||
void prepare();
|
void prepare();
|
||||||
|
void loadSceneNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, Node* parent, std::vector<uint32_t>& indexBuffer, std::vector<Vertex>& vertexBuffer);
|
||||||
|
void drawSceneNode(VkCommandBuffer commandBuffer, Node node);
|
||||||
virtual void render();
|
virtual void render();
|
||||||
virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay);
|
virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay);
|
||||||
};
|
};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue