From 14f0b51c752a7dd69768c3e092378f11553169b4 Mon Sep 17 00:00:00 2001 From: ink-soul Date: Tue, 6 Jun 2023 11:40:59 +0800 Subject: [PATCH] reconstruct dependency to device.hpp --- base/VulkanFrameBuffer.hpp | 2 +- base/VulkanHeightmap.hpp | 2 +- base/VulkanRaytracingSample.h | 2 +- base/VulkanTexture.h | 2 +- base/VulkanUIOverlay.h | 2 +- base/VulkanglTFModel.h | 2 +- base/vulkanexamplebase.h | 2 +- src/render/assetLoader.cpp | 36 + src/render/assetLoader.h | 19 + src/render/glTFModel.h | 2 +- src/render/render.cpp | 1956 +++++++++++++++++---------------- src/render/render.h | 54 +- 12 files changed, 1120 insertions(+), 961 deletions(-) create mode 100644 src/render/assetLoader.cpp create mode 100644 src/render/assetLoader.h diff --git a/base/VulkanFrameBuffer.hpp b/base/VulkanFrameBuffer.hpp index 4180a67..74324b1 100644 --- a/base/VulkanFrameBuffer.hpp +++ b/base/VulkanFrameBuffer.hpp @@ -12,7 +12,7 @@ #include #include #include "vulkan/vulkan.h" -#include "VulkanDevice.h" +#include "VulkanDevice.hpp" #include "VulkanTools.h" namespace vks diff --git a/base/VulkanHeightmap.hpp b/base/VulkanHeightmap.hpp index 08f66e3..37d11c6 100644 --- a/base/VulkanHeightmap.hpp +++ b/base/VulkanHeightmap.hpp @@ -10,7 +10,7 @@ #include #include "vulkan/vulkan.h" -#include "VulkanDevice.h" +#include "VulkanDevice.hpp" #include "VulkanBuffer.h" #include #include diff --git a/base/VulkanRaytracingSample.h b/base/VulkanRaytracingSample.h index 85bdc34..31ffeb3 100644 --- a/base/VulkanRaytracingSample.h +++ b/base/VulkanRaytracingSample.h @@ -11,7 +11,7 @@ #include "vulkan/vulkan.h" #include "vulkanexamplebase.h" #include "VulkanTools.h" -#include "VulkanDevice.h" +#include "VulkanDevice.hpp" class VulkanRaytracingSample : public VulkanExampleBase { diff --git a/base/VulkanTexture.h b/base/VulkanTexture.h index 09cf56f..fec0012 100644 --- a/base/VulkanTexture.h +++ b/base/VulkanTexture.h @@ -19,7 +19,7 @@ #include #include "VulkanBuffer.h" -#include "VulkanDevice.h" +#include "VulkanDevice.hpp" #include "VulkanTools.h" #if defined(__ANDROID__) diff --git a/base/VulkanUIOverlay.h b/base/VulkanUIOverlay.h index 94dc302..b50b770 100644 --- a/base/VulkanUIOverlay.h +++ b/base/VulkanUIOverlay.h @@ -20,7 +20,7 @@ #include "VulkanTools.h" #include "VulkanDebug.h" #include "VulkanBuffer.h" -#include "VulkanDevice.h" +#include "VulkanDevice.hpp" #include "../external/imgui/imgui.h" diff --git a/base/VulkanglTFModel.h b/base/VulkanglTFModel.h index 26a0a12..0ec4f6a 100644 --- a/base/VulkanglTFModel.h +++ b/base/VulkanglTFModel.h @@ -14,7 +14,7 @@ #include #include "vulkan/vulkan.h" -#include "VulkanDevice.h" +#include "VulkanDevice.hpp" #include #include diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h index 1e654bc..273c715 100644 --- a/base/vulkanexamplebase.h +++ b/base/vulkanexamplebase.h @@ -66,7 +66,7 @@ #include "VulkanUIOverlay.h" #include "VulkanSwapChain.h" #include "VulkanBuffer.h" -#include "VulkanDevice.h" +#include "VulkanDevice.hpp" #include "VulkanTexture.h" #include "VulkanInitializers.hpp" diff --git a/src/render/assetLoader.cpp b/src/render/assetLoader.cpp new file mode 100644 index 0000000..156f9a2 --- /dev/null +++ b/src/render/assetLoader.cpp @@ -0,0 +1,36 @@ +#include "assetLoader.h" + + + +void assetLoader::readDirectory(const std::string& directory, const std::string& pattern, std::map& filelist, bool recursive) +{ + std::string searchpattern(directory + "/" + pattern); + WIN32_FIND_DATA data; + HANDLE hFind; + if ((hFind = FindFirstFile(searchpattern.c_str(), &data)) != INVALID_HANDLE_VALUE) { + do { + std::string filename(data.cFileName); + filename.erase(filename.find_last_of("."), std::string::npos); + filelist[filename] = directory + "/" + data.cFileName; + } while (FindNextFile(hFind, &data) != 0); + FindClose(hFind); + } + if (recursive) { + std::string dirpattern = directory + "/*"; + if ((hFind = FindFirstFile(dirpattern.c_str(), &data)) != INVALID_HANDLE_VALUE) { + do { + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + char subdir[MAX_PATH]; + strcpy(subdir, directory.c_str()); + strcat(subdir, "/"); + strcat(subdir, data.cFileName); + if ((strcmp(data.cFileName, ".") != 0) && (strcmp(data.cFileName, "..") != 0)) { + readDirectory(subdir, pattern, filelist, recursive); + } + } + } while (FindNextFile(hFind, &data) != 0); + FindClose(hFind); + } + } + +} \ No newline at end of file diff --git a/src/render/assetLoader.h b/src/render/assetLoader.h new file mode 100644 index 0000000..5507854 --- /dev/null +++ b/src/render/assetLoader.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "vulkan/vulkan.h" +#include "VulkanDevice.hpp" + + +namespace assetLoader +{ + + void readDirectory(const std::string& directory, const std::string& pattern, std::map& filelist, bool recursive); + +}; + \ No newline at end of file diff --git a/src/render/glTFModel.h b/src/render/glTFModel.h index ffd0b8c..894a350 100644 --- a/src/render/glTFModel.h +++ b/src/render/glTFModel.h @@ -23,7 +23,7 @@ #include "tiny_gltf.h" -#include "VulkanDevice.h" +#include "VulkanDevice.hpp" #include "vulkan/vulkan.h" #define ENABLE_VALIDATION false diff --git a/src/render/render.cpp b/src/render/render.cpp index de3cb9a..69c7e08 100644 --- a/src/render/render.cpp +++ b/src/render/render.cpp @@ -31,7 +31,7 @@ #include "render.h" #include "GUIFunction.h" -#include "glTFModel.h" +#include "assetLoader.h" PlumageRender::PlumageRender(): @@ -239,23 +239,23 @@ PlumageRender::PlumageRender(): } - // TO DO:reconstruct with getting file path through struct + void PlumageRender::loadAssets() { - const std::string assetpath = "./../data/"; - struct stat info; - if (stat(assetpath.c_str(), &info) != 0) { + const std::string assetpath = getAssetPath(); + + if (_access(assetpath.c_str(),0) != 0) { std::string msg = "Could not locate asset path in \"" + assetpath + "\".\nMake sure binary is run from correct relative directory!"; std::cerr << msg << std::endl; exit(-1); } - readDirectory(assetpath + "environments", "*.ktx", environments, false); + assetLoader::readDirectory(assetpath + "environments", "*.ktx", environments, false); textures.empty.loadFromFile(assetpath + "textures/empty.ktx", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue); - std::string sceneFile = assetpath + "models/DamagedHelmet/glTF-Embedded/DamagedHelmet.gltf"; - std::string envMapFile = assetpath + "environments/papermill.ktx"; + std::string sceneFile = filePath.glTFModelFilePath; + std::string envMapFile = filePath.envMapFilePath; for (size_t i = 0; i < args.size(); i++) { if ((std::string(args[i]).find(".gltf") != std::string::npos) || (std::string(args[i]).find(".glb") != std::string::npos)) { std::ifstream file(args[i]); @@ -283,149 +283,352 @@ PlumageRender::PlumageRender(): loadEnvironment(envMapFile.c_str()); } - void PlumageRender::setupDescriptors() + + + void PlumageRender::setupNodeDescriptorSet(glTFModel::Node* node) { /* This sample uses separate descriptor sets (and layouts) for the matrices and materials (textures) */ - //Descriptor Pool Alloc - { - std::vector poolSizes = { - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 4), - // One combined image sampler per model image/texture - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, static_cast(glTFModel.images.size())), - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4), // Add aditional sampler descriptor - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1) - }; - // One set for matrices and one per model image/texture - const uint32_t maxSetCount = static_cast(glTFModel.images.size()) + 6; - VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, maxSetCount); - VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } + if (node->mesh) { + VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; + descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocInfo.descriptorPool = descriptorPool; + descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.node; + descriptorSetAllocInfo.descriptorSetCount = 1; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &node->mesh->uniformBuffer.descriptorSet)); + VkWriteDescriptorSet writeDescriptorSet{}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSet.descriptorCount = 1; + writeDescriptorSet.dstSet = node->mesh->uniformBuffer.descriptorSet; + writeDescriptorSet.dstBinding = 0; + writeDescriptorSet.pBufferInfo = &node->mesh->uniformBuffer.descriptor; - // Descriptor set layout for passing matrices ---and precompute texture add in this descriptor - std::vector setLayoutBindings = - { - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0), - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1), - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 2), - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 3), - }; - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.matrices)); - - VkDescriptorSetLayoutBinding materialBufferLayoutBinding = vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 0); - descriptorSetLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(&materialBufferLayoutBinding, 1); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.materialUniform)); - - // Descriptor set layout for passing material textures - VkDescriptorSetLayoutBinding setLayoutBinding = vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0); - descriptorSetLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(&setLayoutBinding, 1); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.textures)); - - setLayoutBinding = vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.ssbo)); - //Pbr pipeline layout - { - // Pipeline layout using both descriptor sets (set 0 = matrices, set 1 = material) - std::array setLayouts = - { descriptorSetLayouts.matrices, - descriptorSetLayouts.textures, - descriptorSetLayouts.textures, - descriptorSetLayouts.textures, - descriptorSetLayouts.textures, - descriptorSetLayouts.materialUniform, - descriptorSetLayouts.ssbo - }; - VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast(setLayouts.size())); - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayouts.pbrLayout)); - - // Descriptor set for scene matrices - VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.matrices, 1); - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); - std::vector writeDescriptorSets = - { - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &shaderData.buffer.descriptor), - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &ibltextures.irradianceCube.descriptor), - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, &ibltextures.lutBrdf.descriptor), - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3, &ibltextures.prefilteredCube.descriptor), - }; - vkUpdateDescriptorSets(device, 4, writeDescriptorSets.data(), 0, nullptr); - - for (auto& material : glTFModel.materials) - { - const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.materialUniform, 1); - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &material.materialData.descriptorSet)); - VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet( - material.materialData.descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &material.materialData.buffer.descriptor); - vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); - } - - // Descriptor sets for materials - for (auto& image : glTFModel.images) { - const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.textures, 1); - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &image.descriptorSet)); - VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(image.descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &image.texture.descriptor); - vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); - } - { - const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.ssbo, 1); - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &skinDescriptorSet)); - VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(skinDescriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, &shaderData.skinSSBO.descriptor); - vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); - } - } - //Tone Mapping pipeline layout - { - auto pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayouts.textures, 1); - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayouts.tonemappingLayout)); - - const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.textures, 1); - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &tonemappingDescriptorSet)); - - auto imageInfo = vks::initializers::descriptorImageInfo(colorSampler, pbrFrameBuffer.color.imageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(tonemappingDescriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &imageInfo); vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); } + for (auto& child : node->children) { + setupNodeDescriptorSet(child); + } + } + + void PlumageRender::setupDescriptors() + { + /* + Descriptor Pool + */ + uint32_t imageSamplerCount = 0; + uint32_t materialCount = 0; + uint32_t meshCount = 0; + + // Environment samplers (radiance, irradiance, brdf lut) + imageSamplerCount += 3; + + std::vector modellist = { &models.skybox, &models.scene }; + for (auto& model : modellist) { + for (auto& material : model->materials) { + imageSamplerCount += 5; + materialCount++; + } + for (auto node : model->linearNodes) { + if (node->mesh) { + meshCount++; + } + } + } + + std::vector poolSizes = { + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (4 + meshCount) * swapChain.imageCount }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageSamplerCount * swapChain.imageCount } + }; + VkDescriptorPoolCreateInfo descriptorPoolCI{}; + descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolCI.poolSizeCount = 2; + descriptorPoolCI.pPoolSizes = poolSizes.data(); + descriptorPoolCI.maxSets = (2 + materialCount + meshCount) * swapChain.imageCount; + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool)); + + /* + Descriptor sets + */ + + // Scene (matrices and environment maps) + { + std::vector setLayoutBindings = { + { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, + { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, + { 2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, + { 3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, + { 4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, + }; + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; + descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCI.pBindings = setLayoutBindings.data(); + descriptorSetLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.scene)); + + for (auto i = 0; i < descriptorSets.size(); i++) { + + VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; + descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocInfo.descriptorPool = descriptorPool; + descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.scene; + descriptorSetAllocInfo.descriptorSetCount = 1; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSets[i].scene)); + + std::array writeDescriptorSets{}; + + writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSets[0].descriptorCount = 1; + writeDescriptorSets[0].dstSet = descriptorSets[i].scene; + writeDescriptorSets[0].dstBinding = 0; + writeDescriptorSets[0].pBufferInfo = &uniformBuffers[i].scene.descriptor; + + writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSets[1].descriptorCount = 1; + writeDescriptorSets[1].dstSet = descriptorSets[i].scene; + writeDescriptorSets[1].dstBinding = 1; + writeDescriptorSets[1].pBufferInfo = &uniformBuffers[i].params.descriptor; + + writeDescriptorSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[2].descriptorCount = 1; + writeDescriptorSets[2].dstSet = descriptorSets[i].scene; + writeDescriptorSets[2].dstBinding = 2; + writeDescriptorSets[2].pImageInfo = &textures.irradianceCube.descriptor; + + writeDescriptorSets[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[3].descriptorCount = 1; + writeDescriptorSets[3].dstSet = descriptorSets[i].scene; + writeDescriptorSets[3].dstBinding = 3; + writeDescriptorSets[3].pImageInfo = &textures.prefilteredCube.descriptor; + + writeDescriptorSets[4].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[4].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[4].descriptorCount = 1; + writeDescriptorSets[4].dstSet = descriptorSets[i].scene; + writeDescriptorSets[4].dstBinding = 4; + writeDescriptorSets[4].pImageInfo = &textures.lutBrdf.descriptor; + + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + } + } + + // Material (samplers) + { + std::vector setLayoutBindings = { + { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, + { 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, + { 2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, + { 3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, + { 4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, + }; + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; + descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCI.pBindings = setLayoutBindings.data(); + descriptorSetLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.material)); + + // Per-Material descriptor sets + for (auto& material : models.scene.materials) { + VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; + descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocInfo.descriptorPool = descriptorPool; + descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.material; + descriptorSetAllocInfo.descriptorSetCount = 1; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &material.descriptorSet)); + + std::vector imageDescriptors = { + textures.empty.descriptor, + textures.empty.descriptor, + material.normalTexture ? material.normalTexture->descriptor : textures.empty.descriptor, + material.occlusionTexture ? material.occlusionTexture->descriptor : textures.empty.descriptor, + material.emissiveTexture ? material.emissiveTexture->descriptor : textures.empty.descriptor + }; + + if (material.pbrWorkflows.metallicRoughness) { + if (material.baseColorTexture) { + imageDescriptors[0] = material.baseColorTexture->descriptor; + } + if (material.metallicRoughnessTexture) { + imageDescriptors[1] = material.metallicRoughnessTexture->descriptor; + } + } + + if (material.pbrWorkflows.specularGlossiness) { + if (material.extension.diffuseTexture) { + imageDescriptors[0] = material.extension.diffuseTexture->descriptor; + } + if (material.extension.specularGlossinessTexture) { + imageDescriptors[1] = material.extension.specularGlossinessTexture->descriptor; + } + } + + std::array writeDescriptorSets{}; + for (size_t i = 0; i < imageDescriptors.size(); i++) { + writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[i].descriptorCount = 1; + writeDescriptorSets[i].dstSet = material.descriptorSet; + writeDescriptorSets[i].dstBinding = static_cast(i); + writeDescriptorSets[i].pImageInfo = &imageDescriptors[i]; + } + + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + } + + // Model node (matrices) + { + std::vector setLayoutBindings = { + { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr }, + }; + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; + descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCI.pBindings = setLayoutBindings.data(); + descriptorSetLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.node)); + + // Per-Node descriptor set + for (auto& node : models.scene.nodes) { + setupNodeDescriptorSet(node); + } + } + + } + + // Skybox (fixed set) + for (auto i = 0; i < uniformBuffers.size(); i++) { + VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; + descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocInfo.descriptorPool = descriptorPool; + descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.scene; + descriptorSetAllocInfo.descriptorSetCount = 1; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSets[i].skybox)); + + std::array writeDescriptorSets{}; + + writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSets[0].descriptorCount = 1; + writeDescriptorSets[0].dstSet = descriptorSets[i].skybox; + writeDescriptorSets[0].dstBinding = 0; + writeDescriptorSets[0].pBufferInfo = &uniformBuffers[i].skybox.descriptor; + + writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSets[1].descriptorCount = 1; + writeDescriptorSets[1].dstSet = descriptorSets[i].skybox; + writeDescriptorSets[1].dstBinding = 1; + writeDescriptorSets[1].pBufferInfo = &uniformBuffers[i].params.descriptor; + + writeDescriptorSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[2].descriptorCount = 1; + writeDescriptorSets[2].dstSet = descriptorSets[i].skybox; + writeDescriptorSets[2].dstBinding = 2; + writeDescriptorSets[2].pImageInfo = &textures.prefilteredCube.descriptor; + + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); + } } void PlumageRender::preparePipelines() { - VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); - VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0); - VkPipelineColorBlendAttachmentState blendAttachmentStateCI = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); - VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentStateCI); - VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); - VkPipelineViewportStateCreateInfo viewportStateCI = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); - VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0); - const std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; - VkPipelineDynamicStateCreateInfo dynamicStateCI = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables.data(), static_cast(dynamicStateEnables.size()), 0); - // Vertex input bindings and attributes - const std::vector vertexInputBindings = { - vks::initializers::vertexInputBindingDescription(0, sizeof(VulkanglTFModel::Vertex), VK_VERTEX_INPUT_RATE_VERTEX), + VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; + inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineRasterizationStateCreateInfo rasterizationStateCI{}; + rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL; + rasterizationStateCI.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizationStateCI.lineWidth = 1.0f; + + VkPipelineColorBlendAttachmentState blendAttachmentState{}; + blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendAttachmentState.blendEnable = VK_FALSE; + + VkPipelineColorBlendStateCreateInfo colorBlendStateCI{}; + colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlendStateCI.attachmentCount = 1; + colorBlendStateCI.pAttachments = &blendAttachmentState; + + VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{}; + depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencilStateCI.depthTestEnable = VK_FALSE; + depthStencilStateCI.depthWriteEnable = VK_FALSE; + depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + depthStencilStateCI.front = depthStencilStateCI.back; + depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS; + + VkPipelineViewportStateCreateInfo viewportStateCI{}; + viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportStateCI.viewportCount = 1; + viewportStateCI.scissorCount = 1; + + VkPipelineMultisampleStateCreateInfo multisampleStateCI{}; + multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + + if (settings.multiSampling) { + multisampleStateCI.rasterizationSamples = settings.sampleCount; + } + + std::vector dynamicStateEnables = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR }; - const std::vector vertexInputAttributes = { - vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, pos)), // Location 0: Position - vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, normal)),// Location 1: Normal - vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, uv)), // Location 2: Texture coordinates - vks::initializers::vertexInputAttributeDescription(0, 3, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, color)), // Location 3: Color - vks::initializers::vertexInputAttributeDescription(0, 4, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, tangent)), // Location 4 : Tangent + VkPipelineDynamicStateCreateInfo dynamicStateCI{}; + dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicStateCI.pDynamicStates = dynamicStateEnables.data(); + dynamicStateCI.dynamicStateCount = static_cast(dynamicStateEnables.size()); + + // Pipeline layout + const std::vector setLayouts = { + descriptorSetLayouts.scene, descriptorSetLayouts.material, descriptorSetLayouts.node }; - VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks::initializers::pipelineVertexInputStateCreateInfo(); - vertexInputStateCI.vertexBindingDescriptionCount = static_cast(vertexInputBindings.size()); - vertexInputStateCI.pVertexBindingDescriptions = vertexInputBindings.data(); + VkPipelineLayoutCreateInfo pipelineLayoutCI{}; + pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCI.setLayoutCount = static_cast(setLayouts.size()); + pipelineLayoutCI.pSetLayouts = setLayouts.data(); + VkPushConstantRange pushConstantRange{}; + pushConstantRange.size = sizeof(PushConstBlockMaterial); + pushConstantRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + pipelineLayoutCI.pushConstantRangeCount = 1; + pipelineLayoutCI.pPushConstantRanges = &pushConstantRange; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); + + // Vertex bindings an attributes + VkVertexInputBindingDescription vertexInputBinding = { 0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX }; + std::vector vertexInputAttributes = { + { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0 }, + { 1, 0, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3 }, + { 2, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6 }, + { 3, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 8 }, + { 4, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 10 }, + { 5, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 14 }, + { 6, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 18 } + }; + VkPipelineVertexInputStateCreateInfo vertexInputStateCI{}; + vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputStateCI.vertexBindingDescriptionCount = 1; + vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding; vertexInputStateCI.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); vertexInputStateCI.pVertexAttributeDescriptions = vertexInputAttributes.data(); - std::array shaderStages = { - loadShader(filePath.modelVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT), - loadShader(filePath.modelFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT) - }; + // Pipelines + std::array shaderStages; - VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelineLayouts.pbrLayout, pbrFrameBuffer.fbo.renderPass, 0); - pipelineCI.pVertexInputState = &vertexInputStateCI; + VkGraphicsPipelineCreateInfo pipelineCI{}; + pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineCI.layout = pipelineLayout; + pipelineCI.renderPass = renderPass; pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; + pipelineCI.pVertexInputState = &vertexInputStateCI; pipelineCI.pRasterizationState = &rasterizationStateCI; pipelineCI.pColorBlendState = &colorBlendStateCI; pipelineCI.pMultisampleState = &multisampleStateCI; @@ -435,17 +638,47 @@ PlumageRender::PlumageRender(): pipelineCI.stageCount = static_cast(shaderStages.size()); pipelineCI.pStages = shaderStages.data(); - // Solid rendering pipeline - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.solid)); + if (settings.multiSampling) { + multisampleStateCI.rasterizationSamples = settings.sampleCount; + } - // Wire frame rendering pipeline - if (deviceFeatures.fillModeNonSolid) { - rasterizationStateCI.polygonMode = VK_POLYGON_MODE_LINE; - rasterizationStateCI.lineWidth = 1.0f; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.wireframe)); + // Skybox pipeline (background cube) + shaderStages = { + loadShader(filePath.skyboxVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT), + loadShader(filePath.skyboxFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT) + }; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.skybox)); + for (auto shaderStage : shaderStages) { + vkDestroyShaderModule(device, shaderStage.module, nullptr); + } + + // PBR pipeline + shaderStages = { + loadShader(filePath.pbrVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT), + loadShader(filePath.pbrFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT) + }; + depthStencilStateCI.depthWriteEnable = VK_TRUE; + depthStencilStateCI.depthTestEnable = VK_TRUE; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbr)); + rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbrDoubleSided)); + + rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; + blendAttachmentState.blendEnable = VK_TRUE; + blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbrAlphaBlend)); + + for (auto shaderStage : shaderStages) { + vkDestroyShaderModule(device, shaderStage.module, nullptr); } //Create Tone Mapping render pipeline - CreateToneMappingPipeline(); + //CreateToneMappingPipeline(); } void PlumageRender::CreateToneMappingPipeline() @@ -491,756 +724,556 @@ PlumageRender::PlumageRender(): //----------------------------Prepare precompute Lighting or BRDF LUT-----------------------------------------------// //Irradiance map for diffuse lighting - void PlumageRender::GenerateIrradianceCubemap() - { - auto tStart = std::chrono::high_resolution_clock::now(); - - constexpr VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT; - constexpr int32_t dim = 64; - const uint32_t numMips = static_cast(floor(log2(dim))) + 1; - - VkImageCreateInfo imageCI = vks::initializers::imageCreateInfo(); - imageCI.imageType = VK_IMAGE_TYPE_2D; - imageCI.format = format; - imageCI.extent.width = dim; - imageCI.extent.height = dim; - imageCI.extent.depth = 1; - imageCI.mipLevels = numMips; - imageCI.arrayLayers = 6; - imageCI.samples = VK_SAMPLE_COUNT_1_BIT; - imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCI.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - imageCI.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &ibltextures.irradianceCube.image)) - VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo(); - VkMemoryRequirements memReqs; - vkGetImageMemoryRequirements(device, ibltextures.irradianceCube.image, &memReqs); - memAlloc.allocationSize = memReqs.size; - memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &ibltextures.irradianceCube.deviceMemory)) - VK_CHECK_RESULT(vkBindImageMemory(device, ibltextures.irradianceCube.image, ibltextures.irradianceCube.deviceMemory, 0)) - VkImageViewCreateInfo viewCI = vks::initializers::imageViewCreateInfo(); - viewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - viewCI.format = format; - viewCI.subresourceRange = {}; - viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewCI.subresourceRange.levelCount = numMips; - viewCI.subresourceRange.layerCount = 6; - viewCI.image = ibltextures.irradianceCube.image; - VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &ibltextures.irradianceCube.view)) - - VkSamplerCreateInfo samplerCI = vks::initializers::samplerCreateInfo(); - samplerCI.magFilter = VK_FILTER_LINEAR; - samplerCI.minFilter = VK_FILTER_LINEAR; - samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.minLod = 0.0f; - samplerCI.maxLod = static_cast(numMips); - samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &ibltextures.irradianceCube.sampler)) - - ibltextures.irradianceCube.descriptor.imageView = ibltextures.irradianceCube.view; - ibltextures.irradianceCube.descriptor.sampler = ibltextures.irradianceCube.sampler; - ibltextures.irradianceCube.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - ibltextures.irradianceCube.device = vulkanDevice; - - //Setup Framebuffer and so on - VkAttachmentDescription attDesc = {}; - attDesc.format = format; - attDesc.samples = VK_SAMPLE_COUNT_1_BIT; - attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkSubpassDescription subpassDescription = {}; - subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDescription.colorAttachmentCount = 1; - subpassDescription.pColorAttachments = &colorReference; - - std::array dependencies; - dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; - dependencies[0].dstSubpass = 0; - dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - dependencies[1].srcSubpass = 0; - dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; - dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - - VkRenderPassCreateInfo renderPassCI = vks::initializers::renderPassCreateInfo(); - renderPassCI.attachmentCount = 1; - renderPassCI.pAttachments = &attDesc; - renderPassCI.subpassCount = 1; - renderPassCI.pSubpasses = &subpassDescription; - renderPassCI.dependencyCount = 2; - renderPassCI.pDependencies = dependencies.data(); - VkRenderPass renderpass; - VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderpass)); - - { - VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo(); - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.format = format; - imageCreateInfo.extent.width = dim; - imageCreateInfo.extent.height = dim; - imageCreateInfo.extent.depth = 1; - imageCreateInfo.mipLevels = 1; - imageCreateInfo.arrayLayers = 1; - imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &offscreen.image)) - - VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo(); - VkMemoryRequirements memReqs; - vkGetImageMemoryRequirements(device, offscreen.image, &memReqs); - memAlloc.allocationSize = memReqs.size; - memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &offscreen.memory)) - VK_CHECK_RESULT(vkBindImageMemory(device, offscreen.image, offscreen.memory, 0)) - - VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo(); - colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D; - colorImageView.format = format; - colorImageView.flags = 0; - colorImageView.subresourceRange = {}; - colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - colorImageView.subresourceRange.baseMipLevel = 0; - colorImageView.subresourceRange.levelCount = 1; - colorImageView.subresourceRange.baseArrayLayer = 0; - colorImageView.subresourceRange.layerCount = 1; - colorImageView.image = offscreen.image; - VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &offscreen.view)) - - VkFramebufferCreateInfo fbufCreateInfo = vks::initializers::framebufferCreateInfo(); - fbufCreateInfo.renderPass = renderpass; - fbufCreateInfo.attachmentCount = 1; - fbufCreateInfo.pAttachments = &offscreen.view; - fbufCreateInfo.width = dim; - fbufCreateInfo.height = dim; - fbufCreateInfo.layers = 1; - VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offscreen.framebuffer)) - - VkCommandBuffer layoutCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vks::tools::setImageLayout( - layoutCmd, - offscreen.image, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - vulkanDevice->flushCommandBuffer(layoutCmd, queue, true); - } - VkDescriptorSetLayout descriptorsetlayout; - std::vector setLayoutBindings = - { - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0), - }; - VkDescriptorSetLayoutCreateInfo descriptorsetlayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorsetlayoutCI, nullptr, &descriptorsetlayout)); - - std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) }; - VkDescriptorPoolCreateInfo descriptorPoolCI = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); - VkDescriptorPool descriptorpool; - VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorpool)); - - VkDescriptorSet descriptorset; - VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorpool, &descriptorsetlayout, 1); - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorset)); - VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(descriptorset, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &ibltextures.skyboxCube.descriptor); - vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); - - - - VkPipelineLayout pipelinelayout; - std::vector pushConstantRanges = - { - vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(IrradiancePushBlock), 0) - }; - VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorsetlayout, 1); - pipelineLayoutCI.pushConstantRangeCount = 1; - pipelineLayoutCI.pPushConstantRanges = pushConstantRanges.data(); - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelinelayout)); - - //Pipeline Setting - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); - VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE); - VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); - VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); - VkPipelineDepthStencilStateCreateInfo depthStencilState = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_FALSE, VK_FALSE, VK_COMPARE_OP_LESS_OR_EQUAL); - VkPipelineViewportStateCreateInfo viewportState = vks::initializers::pipelineViewportStateCreateInfo(1, 1); - VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT); - std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; - VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); - std::array shaderStages; - - const std::vector vertexInputBindings = - { - vks::initializers::vertexInputBindingDescription(0, sizeof(VulkanglTFModel::Vertex), VK_VERTEX_INPUT_RATE_VERTEX), - }; - - const std::vector vertexInputAttributes = { - vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, pos)), // Location 0: Position - //vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, normal)),// Location 1: Normal - //vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, uv)), // Location 2: Texture coordinates - //vks::initializers::vertexInputAttributeDescription(0, 3, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, color)), // Location 3: Color - //vks::initializers::vertexInputAttributeDescription(0, 4, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, tangent)), // Location 4 : Tangent - }; - VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks::initializers::pipelineVertexInputStateCreateInfo(); - vertexInputStateCI.vertexBindingDescriptionCount = static_cast(vertexInputBindings.size()); - vertexInputStateCI.pVertexBindingDescriptions = vertexInputBindings.data(); - vertexInputStateCI.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); - vertexInputStateCI.pVertexAttributeDescriptions = vertexInputAttributes.data(); - - VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelinelayout, renderpass); - pipelineCI.pInputAssemblyState = &inputAssemblyState; - pipelineCI.pRasterizationState = &rasterizationState; - pipelineCI.pColorBlendState = &colorBlendState; - pipelineCI.pMultisampleState = &multisampleState; - pipelineCI.pViewportState = &viewportState; - pipelineCI.pDepthStencilState = &depthStencilState; - pipelineCI.pDynamicState = &dynamicState; - pipelineCI.stageCount = 2; - pipelineCI.pStages = shaderStages.data(); - pipelineCI.renderPass = renderpass; - - pipelineCI.pVertexInputState = &vertexInputStateCI; - shaderStages[0] = loadShader(filePath.irradianceVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(filePath.irradianceFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT); - VkPipeline pipeline; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); - - //Render - VkClearValue clearValues[1]; - clearValues[0].color = { { 0.0f, 0.0f, 0.2f, 0.0f } }; - VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); - renderPassBeginInfo.renderPass = renderpass; - renderPassBeginInfo.framebuffer = offscreen.framebuffer; - renderPassBeginInfo.renderArea.extent.width = dim; - renderPassBeginInfo.renderArea.extent.height = dim; - renderPassBeginInfo.clearValueCount = 1; - renderPassBeginInfo.pClearValues = clearValues; - - //six face in cube map - std::vector matrices = { - // POSITIVE_X - glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - // NEGATIVE_X - glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - // POSITIVE_Y - glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - // NEGATIVE_Y - glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - // POSITIVE_Z - glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - // NEGATIVE_Z - glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f)), - }; - VkCommandBuffer cmdBuf = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - VkViewport viewport = vks::initializers::viewport((float)dim, (float)dim, 0.0f, 1.0f); - VkRect2D scissor = vks::initializers::rect2D(dim, dim, 0, 0); - - vkCmdSetViewport(cmdBuf, 0, 1, &viewport); - vkCmdSetScissor(cmdBuf, 0, 1, &scissor); - - VkImageSubresourceRange subresourceRange = {}; - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresourceRange.baseMipLevel = 0; - subresourceRange.levelCount = numMips; - subresourceRange.layerCount = 6; - - vks::tools::setImageLayout( - cmdBuf, - ibltextures.irradianceCube.image, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - subresourceRange); - - for(uint32_t m = 0; m < numMips; ++m) - { - for(uint32_t f = 0; f < 6; ++f) - { - viewport.width = static_cast(dim * std::pow(0.5f, m)); - viewport.height = static_cast(dim * std::pow(0.5f, m)); - vkCmdSetViewport(cmdBuf, 0, 1, &viewport); - // Render scene from cube face's point of view - vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - irradiancePushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f]; - vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(IrradiancePushBlock), &irradiancePushBlock); - - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinelayout, 0, 1, &descriptorset, 0, NULL); - skyboxModel.draw(cmdBuf, pipelinelayout, false); - vkCmdEndRenderPass(cmdBuf); - - vks::tools::setImageLayout( - cmdBuf, - offscreen.image, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - - VkImageCopy copyRegion = {}; - copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyRegion.srcSubresource.layerCount = 1; - copyRegion.srcSubresource.mipLevel = 0; - copyRegion.srcSubresource.baseArrayLayer = 0; - - copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyRegion.dstSubresource.layerCount = 1; - copyRegion.dstSubresource.mipLevel = m; - copyRegion.dstSubresource.baseArrayLayer = f; - - copyRegion.extent.width = static_cast(viewport.width); - copyRegion.extent.height = static_cast(viewport.height); - copyRegion.extent.depth = 1; - - vkCmdCopyImage( - cmdBuf, - offscreen.image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - ibltextures.irradianceCube.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - ©Region); - vks::tools::setImageLayout(cmdBuf, - offscreen.image, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL - ); - } - } - - vks::tools::setImageLayout(cmdBuf, - ibltextures.irradianceCube.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - subresourceRange); - vulkanDevice->flushCommandBuffer(cmdBuf, queue); - - vkDestroyRenderPass(device, renderpass, nullptr); - vkDestroyFramebuffer(device, offscreen.framebuffer, nullptr); - vkFreeMemory(device, offscreen.memory, nullptr); - vkDestroyImageView(device, offscreen.view, nullptr); - vkDestroyImage(device, offscreen.image, nullptr); - vkDestroyDescriptorPool(device, descriptorpool, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorsetlayout, nullptr); - vkDestroyPipeline(device, pipeline, nullptr); - vkDestroyPipelineLayout(device, pipelinelayout, nullptr); - - auto tEnd = std::chrono::high_resolution_clock::now(); - auto tDiff = std::chrono::duration(tEnd - tStart).count(); - std::cout << "Generating irradiance cube with " << numMips << " mip levels took " << tDiff << " ms" << std::endl; - } - - void PlumageRender::GeneratePrefilteredCubemap() - { - auto tStart = std::chrono::high_resolution_clock::now(); - - constexpr VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT; - constexpr int32_t dim = 512; - const uint32_t numMips = static_cast(floor(log2(dim))) + 1; - - VkImageCreateInfo imageCI = vks::initializers::imageCreateInfo(); - imageCI.imageType = VK_IMAGE_TYPE_2D; - imageCI.format = format; - imageCI.extent.width = dim; - imageCI.extent.height = dim; - imageCI.extent.depth = 1; - imageCI.mipLevels = numMips; - imageCI.arrayLayers = 6; - imageCI.samples = VK_SAMPLE_COUNT_1_BIT; - imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCI.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - imageCI.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - - VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &ibltextures.prefilteredCube.image)); - VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo(); - VkMemoryRequirements memReqs; - vkGetImageMemoryRequirements(device, ibltextures.prefilteredCube.image, &memReqs); - memAlloc.allocationSize = memReqs.size; - memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &ibltextures.prefilteredCube.deviceMemory)); - VK_CHECK_RESULT(vkBindImageMemory(device, ibltextures.prefilteredCube.image, ibltextures.prefilteredCube.deviceMemory, 0)); - - // Image view - VkImageViewCreateInfo viewCI = vks::initializers::imageViewCreateInfo(); - viewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - viewCI.format = format; - viewCI.subresourceRange = {}; - viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewCI.subresourceRange.levelCount = numMips; - viewCI.subresourceRange.layerCount = 6; - viewCI.image = ibltextures.prefilteredCube.image; - VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &ibltextures.prefilteredCube.view)); - - // Sampler - VkSamplerCreateInfo samplerCI = vks::initializers::samplerCreateInfo(); - samplerCI.magFilter = VK_FILTER_LINEAR; - samplerCI.minFilter = VK_FILTER_LINEAR; - samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.minLod = 0.0f; - samplerCI.maxLod = static_cast(numMips); - samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &ibltextures.prefilteredCube.sampler)); - - ibltextures.prefilteredCube.descriptor.imageView = ibltextures.prefilteredCube.view; - ibltextures.prefilteredCube.descriptor.sampler = ibltextures.prefilteredCube.sampler; - ibltextures.prefilteredCube.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - ibltextures.prefilteredCube.device = vulkanDevice; - - // FB, Att, RP, Pipe, etc. - VkAttachmentDescription attDesc = {}; - // Color attachment - attDesc.format = format; - attDesc.samples = VK_SAMPLE_COUNT_1_BIT; - attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - - VkSubpassDescription subpassDescription = {}; - subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDescription.colorAttachmentCount = 1; - subpassDescription.pColorAttachments = &colorReference; - - // Use subpass dependencies for layout transitions - std::array dependencies; - dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; - dependencies[0].dstSubpass = 0; - dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - dependencies[1].srcSubpass = 0; - dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; - dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - - // Renderpass - VkRenderPassCreateInfo renderPassCI = vks::initializers::renderPassCreateInfo(); - renderPassCI.attachmentCount = 1; - renderPassCI.pAttachments = &attDesc; - renderPassCI.subpassCount = 1; - renderPassCI.pSubpasses = &subpassDescription; - renderPassCI.dependencyCount = 2; - renderPassCI.pDependencies = dependencies.data(); - VkRenderPass renderpass; - VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderpass)); - - struct { - VkImage image; - VkImageView view; - VkDeviceMemory memory; - VkFramebuffer framebuffer; - } offscreen; - //framebuffer - { - // Color attachment - VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo(); - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.format = format; - imageCreateInfo.extent.width = dim; - imageCreateInfo.extent.height = dim; - imageCreateInfo.extent.depth = 1; - imageCreateInfo.mipLevels = 1; - imageCreateInfo.arrayLayers = 1; - imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &offscreen.image)); - - VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo(); - VkMemoryRequirements memReqs; - vkGetImageMemoryRequirements(device, offscreen.image, &memReqs); - memAlloc.allocationSize = memReqs.size; - memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &offscreen.memory)); - VK_CHECK_RESULT(vkBindImageMemory(device, offscreen.image, offscreen.memory, 0)); - - VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo(); - colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D; - colorImageView.format = format; - colorImageView.flags = 0; - colorImageView.subresourceRange = {}; - colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - colorImageView.subresourceRange.baseMipLevel = 0; - colorImageView.subresourceRange.levelCount = 1; - colorImageView.subresourceRange.baseArrayLayer = 0; - colorImageView.subresourceRange.layerCount = 1; - colorImageView.image = offscreen.image; - VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &offscreen.view)); - - VkFramebufferCreateInfo fbufCreateInfo = vks::initializers::framebufferCreateInfo(); - fbufCreateInfo.renderPass = renderpass; - fbufCreateInfo.attachmentCount = 1; - fbufCreateInfo.pAttachments = &offscreen.view; - fbufCreateInfo.width = dim; - fbufCreateInfo.height = dim; - fbufCreateInfo.layers = 1; - VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offscreen.framebuffer)); - - VkCommandBuffer layoutCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vks::tools::setImageLayout( - layoutCmd, - offscreen.image, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - vulkanDevice->flushCommandBuffer(layoutCmd, queue, true); - } - - // Descriptors - VkDescriptorSetLayout descriptorsetlayout; - std::vector setLayoutBindings = { - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0), - }; - VkDescriptorSetLayoutCreateInfo descriptorsetlayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorsetlayoutCI, nullptr, &descriptorsetlayout)); - - // Descriptor Pool - std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) }; - VkDescriptorPoolCreateInfo descriptorPoolCI = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); - VkDescriptorPool descriptorpool; - VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorpool)); - - VkDescriptorSet descriptorset; - VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorpool, &descriptorsetlayout, 1); - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorset)); - VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(descriptorset, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &ibltextures.skyboxCube.descriptor); - vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); - - struct PushBlock { - glm::mat4 mvp; - float roughness; - uint32_t numSamples = 32u; - } pushBlock; - - std::vector pushConstantRanges = { - vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(PushBlock), 0), - }; - VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorsetlayout, 1); - pipelineLayoutCI.pushConstantRangeCount = 1; - pipelineLayoutCI.pPushConstantRanges = pushConstantRanges.data(); - VkPipelineLayout pipelinelayout; - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelinelayout)); - - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); - VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE); - VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); - VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); - VkPipelineDepthStencilStateCreateInfo depthStencilState = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_FALSE, VK_FALSE, VK_COMPARE_OP_LESS_OR_EQUAL); - VkPipelineViewportStateCreateInfo viewportState = vks::initializers::pipelineViewportStateCreateInfo(1, 1); - VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT); - std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; - VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); - std::array shaderStages; - - const std::vector vertexInputBindings = - { - vks::initializers::vertexInputBindingDescription(0, sizeof(VulkanglTFModel::Vertex), VK_VERTEX_INPUT_RATE_VERTEX), - }; - - const std::vector vertexInputAttributes = { - vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, pos)), // Location 0: Position - }; - VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks::initializers::pipelineVertexInputStateCreateInfo(); - vertexInputStateCI.vertexBindingDescriptionCount = static_cast(vertexInputBindings.size()); - vertexInputStateCI.pVertexBindingDescriptions = vertexInputBindings.data(); - vertexInputStateCI.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); - vertexInputStateCI.pVertexAttributeDescriptions = vertexInputAttributes.data(); - - VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelinelayout, renderpass); - pipelineCI.pInputAssemblyState = &inputAssemblyState; - pipelineCI.pRasterizationState = &rasterizationState; - pipelineCI.pColorBlendState = &colorBlendState; - pipelineCI.pMultisampleState = &multisampleState; - pipelineCI.pViewportState = &viewportState; - pipelineCI.pDepthStencilState = &depthStencilState; - pipelineCI.pDynamicState = &dynamicState; - pipelineCI.stageCount = 2; - pipelineCI.pStages = shaderStages.data(); - pipelineCI.renderPass = renderpass; - pipelineCI.pVertexInputState = &vertexInputStateCI; - - shaderStages[0] = loadShader(filePath.prefilterVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(filePath.prefilterFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT); - - VkPipeline pipeline; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); - - //Render & build cmd - VkClearValue clearValues[1]; - clearValues[0].color = { { 0.0f, 0.0f, 0.2f, 0.0f } }; - - VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); - // Reuse render pass from example pass - renderPassBeginInfo.renderPass = renderpass; - renderPassBeginInfo.framebuffer = offscreen.framebuffer; - renderPassBeginInfo.renderArea.extent.width = dim; - renderPassBeginInfo.renderArea.extent.height = dim; - renderPassBeginInfo.clearValueCount = 1; - renderPassBeginInfo.pClearValues = clearValues; - - std::vector matrices = { - // POSITIVE_X - glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - // NEGATIVE_X - glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - // POSITIVE_Y - glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - // NEGATIVE_Y - glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - // POSITIVE_Z - glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - // NEGATIVE_Z - glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f)), - }; - VkCommandBuffer cmdBuf = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - VkViewport viewport = vks::initializers::viewport((float)dim, (float)dim, 0.0f, 1.0f); - VkRect2D scissor = vks::initializers::rect2D(dim, dim, 0, 0); - - vkCmdSetViewport(cmdBuf, 0, 1, &viewport); - vkCmdSetScissor(cmdBuf, 0, 1, &scissor); - - VkImageSubresourceRange subresourceRange = {}; - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresourceRange.baseMipLevel = 0; - subresourceRange.levelCount = numMips; - subresourceRange.layerCount = 6; - - vks::tools::setImageLayout( - cmdBuf, - ibltextures.prefilteredCube.image, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - subresourceRange); - for (uint32_t m = 0; m < numMips; ++m) + + void PlumageRender::generateCubemaps() { - //mip level according to roughness - pushBlock.roughness = float(m) / float(numMips - 1); - for (uint32_t f = 0; f < 6; ++f) - { - viewport.width = static_cast(dim * std::pow(0.5f, m)); - viewport.height = static_cast(dim * std::pow(0.5f, m)); - vkCmdSetViewport(cmdBuf, 0, 1, &viewport); - // Render scene from cube face's point of view - vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + enum Target { IRRADIANCE = 0, PREFILTEREDENV = 1 }; - // Update shader push constant block - pushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f]; + for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++) { - vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushBlock), &pushBlock); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinelayout, 0, 1, &descriptorset, 0, nullptr); - skyboxModel.draw(cmdBuf, pipelinelayout, false); - vkCmdEndRenderPass(cmdBuf); + vks::TextureCubeMap cubemap; - vks::tools::setImageLayout( - cmdBuf, - offscreen.image, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + auto tStart = std::chrono::high_resolution_clock::now(); - VkImageCopy copyRegion{}; - copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyRegion.srcSubresource.baseArrayLayer = 0; - copyRegion.srcSubresource.mipLevel = 0; - copyRegion.srcSubresource.layerCount = 1; - copyRegion.srcOffset = { 0, 0, 0 }; + VkFormat format; + int32_t dim; - copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyRegion.dstSubresource.baseArrayLayer = f; - copyRegion.dstSubresource.mipLevel = m; - copyRegion.dstSubresource.layerCount = 1; - copyRegion.dstOffset = { 0, 0, 0 }; + switch (target) { + case IRRADIANCE: + format = VK_FORMAT_R32G32B32A32_SFLOAT; + dim = 64; + break; + case PREFILTEREDENV: + format = VK_FORMAT_R16G16B16A16_SFLOAT; + dim = 512; + break; + }; - copyRegion.extent.width = static_cast(viewport.width); - copyRegion.extent.height = static_cast(viewport.height); - copyRegion.extent.depth = 1; + const uint32_t numMips = static_cast(floor(log2(dim))) + 1; - vkCmdCopyImage( - cmdBuf, - offscreen.image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - ibltextures.prefilteredCube.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - ©Region); + // Create target cubemap + { + // Image + VkImageCreateInfo imageCI{}; + imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCI.imageType = VK_IMAGE_TYPE_2D; + imageCI.format = format; + imageCI.extent.width = dim; + imageCI.extent.height = dim; + imageCI.extent.depth = 1; + imageCI.mipLevels = numMips; + imageCI.arrayLayers = 6; + imageCI.samples = VK_SAMPLE_COUNT_1_BIT; + imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCI.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + imageCI.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &cubemap.image)); + VkMemoryRequirements memReqs; + vkGetImageMemoryRequirements(device, cubemap.image, &memReqs); + VkMemoryAllocateInfo memAllocInfo{}; + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &cubemap.deviceMemory)); + VK_CHECK_RESULT(vkBindImageMemory(device, cubemap.image, cubemap.deviceMemory, 0)); - //Reset frame buffer image layout - vks::tools::setImageLayout( - cmdBuf, - offscreen.image, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + // View + VkImageViewCreateInfo viewCI{}; + viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE; + viewCI.format = format; + viewCI.subresourceRange = {}; + viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewCI.subresourceRange.levelCount = numMips; + viewCI.subresourceRange.layerCount = 6; + viewCI.image = cubemap.image; + VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &cubemap.view)); + + // Sampler + VkSamplerCreateInfo samplerCI{}; + samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerCI.magFilter = VK_FILTER_LINEAR; + samplerCI.minFilter = VK_FILTER_LINEAR; + samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerCI.minLod = 0.0f; + samplerCI.maxLod = static_cast(numMips); + samplerCI.maxAnisotropy = 1.0f; + samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &cubemap.sampler)); + } + + // FB, Att, RP, Pipe, etc. + VkAttachmentDescription attDesc{}; + // Color attachment + attDesc.format = format; + attDesc.samples = VK_SAMPLE_COUNT_1_BIT; + attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkSubpassDescription subpassDescription{}; + subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDescription.colorAttachmentCount = 1; + subpassDescription.pColorAttachments = &colorReference; + + // Use subpass dependencies for layout transitions + std::array dependencies; + dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; + dependencies[0].dstSubpass = 0; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + dependencies[1].srcSubpass = 0; + dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; + dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + // Renderpass + VkRenderPassCreateInfo renderPassCI{}; + renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassCI.attachmentCount = 1; + renderPassCI.pAttachments = &attDesc; + renderPassCI.subpassCount = 1; + renderPassCI.pSubpasses = &subpassDescription; + renderPassCI.dependencyCount = 2; + renderPassCI.pDependencies = dependencies.data(); + VkRenderPass renderpass; + VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderpass)); + + + // Create offscreen framebuffer + { + // Image + VkImageCreateInfo imageCI{}; + imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCI.imageType = VK_IMAGE_TYPE_2D; + imageCI.format = format; + imageCI.extent.width = dim; + imageCI.extent.height = dim; + imageCI.extent.depth = 1; + imageCI.mipLevels = 1; + imageCI.arrayLayers = 1; + imageCI.samples = VK_SAMPLE_COUNT_1_BIT; + imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &offscreen.image)); + VkMemoryRequirements memReqs; + vkGetImageMemoryRequirements(device, offscreen.image, &memReqs); + VkMemoryAllocateInfo memAllocInfo{}; + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &offscreen.memory)); + VK_CHECK_RESULT(vkBindImageMemory(device, offscreen.image, offscreen.memory, 0)); + + // View + VkImageViewCreateInfo viewCI{}; + viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewCI.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewCI.format = format; + viewCI.flags = 0; + viewCI.subresourceRange = {}; + viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewCI.subresourceRange.baseMipLevel = 0; + viewCI.subresourceRange.levelCount = 1; + viewCI.subresourceRange.baseArrayLayer = 0; + viewCI.subresourceRange.layerCount = 1; + viewCI.image = offscreen.image; + VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &offscreen.view)); + + // Framebuffer + VkFramebufferCreateInfo framebufferCI{}; + framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferCI.renderPass = renderpass; + framebufferCI.attachmentCount = 1; + framebufferCI.pAttachments = &offscreen.view; + framebufferCI.width = dim; + framebufferCI.height = dim; + framebufferCI.layers = 1; + VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCI, nullptr, &offscreen.framebuffer)); + + VkCommandBuffer layoutCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.image = offscreen.image; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + vkCmdPipelineBarrier(layoutCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + vulkanDevice->flushCommandBuffer(layoutCmd, queue, true); + } + + // Descriptors + VkDescriptorSetLayout descriptorsetlayout; + VkDescriptorSetLayoutBinding setLayoutBinding = { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }; + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; + descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCI.pBindings = &setLayoutBinding; + descriptorSetLayoutCI.bindingCount = 1; + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorsetlayout)); + + // Descriptor Pool + VkDescriptorPoolSize poolSize = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }; + VkDescriptorPoolCreateInfo descriptorPoolCI{}; + descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolCI.poolSizeCount = 1; + descriptorPoolCI.pPoolSizes = &poolSize; + descriptorPoolCI.maxSets = 2; + VkDescriptorPool descriptorpool; + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorpool)); + + // Descriptor sets + VkDescriptorSet descriptorset; + VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; + descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocInfo.descriptorPool = descriptorpool; + descriptorSetAllocInfo.pSetLayouts = &descriptorsetlayout; + descriptorSetAllocInfo.descriptorSetCount = 1; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorset)); + VkWriteDescriptorSet writeDescriptorSet{}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSet.descriptorCount = 1; + writeDescriptorSet.dstSet = descriptorset; + writeDescriptorSet.dstBinding = 0; + writeDescriptorSet.pImageInfo = &textures.environmentCube.descriptor; + vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); + + // Pipeline layout + VkPipelineLayout pipelinelayout; + VkPushConstantRange pushConstantRange{}; + pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + + switch (target) { + case IRRADIANCE: + pushConstantRange.size = sizeof(IrradiancePushBlock); + break; + case PREFILTEREDENV: + pushConstantRange.size = sizeof(PrefilterPushBlock); + break; + }; + + VkPipelineLayoutCreateInfo pipelineLayoutCI{}; + pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCI.setLayoutCount = 1; + pipelineLayoutCI.pSetLayouts = &descriptorsetlayout; + pipelineLayoutCI.pushConstantRangeCount = 1; + pipelineLayoutCI.pPushConstantRanges = &pushConstantRange; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelinelayout)); + + // Pipeline + VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; + inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineRasterizationStateCreateInfo rasterizationStateCI{}; + rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL; + rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; + rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizationStateCI.lineWidth = 1.0f; + + VkPipelineColorBlendAttachmentState blendAttachmentState{}; + blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendAttachmentState.blendEnable = VK_FALSE; + + VkPipelineColorBlendStateCreateInfo colorBlendStateCI{}; + colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlendStateCI.attachmentCount = 1; + colorBlendStateCI.pAttachments = &blendAttachmentState; + + VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{}; + depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencilStateCI.depthTestEnable = VK_FALSE; + depthStencilStateCI.depthWriteEnable = VK_FALSE; + depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + depthStencilStateCI.front = depthStencilStateCI.back; + depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS; + + VkPipelineViewportStateCreateInfo viewportStateCI{}; + viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportStateCI.viewportCount = 1; + viewportStateCI.scissorCount = 1; + + VkPipelineMultisampleStateCreateInfo multisampleStateCI{}; + multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dynamicStateCI{}; + dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicStateCI.pDynamicStates = dynamicStateEnables.data(); + dynamicStateCI.dynamicStateCount = static_cast(dynamicStateEnables.size()); + + // Vertex input state + VkVertexInputBindingDescription vertexInputBinding = { 0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX }; + VkVertexInputAttributeDescription vertexInputAttribute = { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0 }; + + VkPipelineVertexInputStateCreateInfo vertexInputStateCI{}; + vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputStateCI.vertexBindingDescriptionCount = 1; + vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding; + vertexInputStateCI.vertexAttributeDescriptionCount = 1; + vertexInputStateCI.pVertexAttributeDescriptions = &vertexInputAttribute; + + std::array shaderStages; + + VkGraphicsPipelineCreateInfo pipelineCI{}; + pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineCI.layout = pipelinelayout; + pipelineCI.renderPass = renderpass; + pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; + pipelineCI.pVertexInputState = &vertexInputStateCI; + pipelineCI.pRasterizationState = &rasterizationStateCI; + pipelineCI.pColorBlendState = &colorBlendStateCI; + pipelineCI.pMultisampleState = &multisampleStateCI; + pipelineCI.pViewportState = &viewportStateCI; + pipelineCI.pDepthStencilState = &depthStencilStateCI; + pipelineCI.pDynamicState = &dynamicStateCI; + pipelineCI.stageCount = 2; + pipelineCI.pStages = shaderStages.data(); + pipelineCI.renderPass = renderpass; + + shaderStages[0] = loadShader(filePath.filterVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT); + switch (target) { + case IRRADIANCE: + shaderStages[1] = loadShader(filePath.irradianceFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT); + break; + case PREFILTEREDENV: + shaderStages[1] = loadShader(filePath.prefilterEnvmapFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT); + break; + }; + VkPipeline pipeline; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); + for (auto shaderStage : shaderStages) { + vkDestroyShaderModule(device, shaderStage.module, nullptr); + } + + // Render cubemap + VkClearValue clearValues[1]; + clearValues[0].color = { { 0.0f, 0.0f, 0.2f, 0.0f } }; + + VkRenderPassBeginInfo renderPassBeginInfo{}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassBeginInfo.renderPass = renderpass; + renderPassBeginInfo.framebuffer = offscreen.framebuffer; + renderPassBeginInfo.renderArea.extent.width = dim; + renderPassBeginInfo.renderArea.extent.height = dim; + renderPassBeginInfo.clearValueCount = 1; + renderPassBeginInfo.pClearValues = clearValues; + + std::vector matrices = { + glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), + glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), + glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), + glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), + glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), + glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f)), + }; + + VkCommandBuffer cmdBuf = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false); + + VkViewport viewport{}; + viewport.width = (float)dim; + viewport.height = (float)dim; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor{}; + scissor.extent.width = dim; + scissor.extent.height = dim; + + VkImageSubresourceRange subresourceRange{}; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = numMips; + subresourceRange.layerCount = 6; + + // Change image layout for all cubemap faces to transfer destination + { + vulkanDevice->beginCommandBuffer(cmdBuf); + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.image = cubemap.image; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.subresourceRange = subresourceRange; + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + vulkanDevice->flushCommandBuffer(cmdBuf, queue, false); + } + + for (uint32_t m = 0; m < numMips; m++) { + for (uint32_t f = 0; f < 6; f++) { + + vulkanDevice->beginCommandBuffer(cmdBuf); + + viewport.width = static_cast(dim * std::pow(0.5f, m)); + viewport.height = static_cast(dim * std::pow(0.5f, m)); + vkCmdSetViewport(cmdBuf, 0, 1, &viewport); + vkCmdSetScissor(cmdBuf, 0, 1, &scissor); + + // Render scene from cube face's point of view + vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + // Pass parameters for current pass using a push constant block + switch (target) { + case IRRADIANCE: + irradiancePushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f]; + vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushBlockIrradiance), &pushBlockIrradiance); + break; + case PREFILTEREDENV: + prefilterPushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f]; + prefilterPushBlock.roughness = (float)m / (float)(numMips - 1); + vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushBlockPrefilterEnv), &pushBlockPrefilterEnv); + break; + }; + + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinelayout, 0, 1, &descriptorset, 0, NULL); + + VkDeviceSize offsets[1] = { 0 }; + + models.skybox.draw(cmdBuf); + + vkCmdEndRenderPass(cmdBuf); + + VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = numMips; + subresourceRange.layerCount = 6; + + { + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.image = offscreen.image; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } + + // Copy region for transfer from framebuffer to cube face + VkImageCopy copyRegion{}; + + copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegion.srcSubresource.baseArrayLayer = 0; + copyRegion.srcSubresource.mipLevel = 0; + copyRegion.srcSubresource.layerCount = 1; + copyRegion.srcOffset = { 0, 0, 0 }; + + copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegion.dstSubresource.baseArrayLayer = f; + copyRegion.dstSubresource.mipLevel = m; + copyRegion.dstSubresource.layerCount = 1; + copyRegion.dstOffset = { 0, 0, 0 }; + + copyRegion.extent.width = static_cast(viewport.width); + copyRegion.extent.height = static_cast(viewport.height); + copyRegion.extent.depth = 1; + + vkCmdCopyImage( + cmdBuf, + offscreen.image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + cubemap.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ©Region); + + { + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.image = offscreen.image; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } + + vulkanDevice->flushCommandBuffer(cmdBuf, queue, false); + } + } + + { + vulkanDevice->beginCommandBuffer(cmdBuf); + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.image = cubemap.image; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.subresourceRange = subresourceRange; + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + vulkanDevice->flushCommandBuffer(cmdBuf, queue, false); + } + + + vkDestroyRenderPass(device, renderpass, nullptr); + vkDestroyFramebuffer(device, offscreen.framebuffer, nullptr); + vkFreeMemory(device, offscreen.memory, nullptr); + vkDestroyImageView(device, offscreen.view, nullptr); + vkDestroyImage(device, offscreen.image, nullptr); + vkDestroyDescriptorPool(device, descriptorpool, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorsetlayout, nullptr); + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelinelayout, nullptr); + + cubemap.descriptor.imageView = cubemap.view; + cubemap.descriptor.sampler = cubemap.sampler; + cubemap.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + cubemap.device = vulkanDevice; + + switch (target) { + case IRRADIANCE: + textures.irradianceCube = cubemap; + break; + case PREFILTEREDENV: + textures.prefilteredCube = cubemap; + shaderData.prefilteredCubeMipLevels = static_cast(numMips); + break; + }; + + auto tEnd = std::chrono::high_resolution_clock::now(); + auto tDiff = std::chrono::duration(tEnd - tStart).count(); + std::cout << "Generating cube map with " << numMips << " mip levels took " << tDiff << " ms" << std::endl; } } - //Set format shader read - vks::tools::setImageLayout( - cmdBuf, - ibltextures.prefilteredCube.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - subresourceRange); - - vulkanDevice->flushCommandBuffer(cmdBuf, queue); - - vkDestroyRenderPass(device, renderpass, nullptr); - vkDestroyFramebuffer(device, offscreen.framebuffer, nullptr); - vkFreeMemory(device, offscreen.memory, nullptr); - vkDestroyImageView(device, offscreen.view, nullptr); - vkDestroyImage(device, offscreen.image, nullptr); - vkDestroyDescriptorPool(device, descriptorpool, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorsetlayout, nullptr); - vkDestroyPipeline(device, pipeline, nullptr); - vkDestroyPipelineLayout(device, pipelinelayout, nullptr); - - auto tEnd = std::chrono::high_resolution_clock::now(); - auto tDiff = std::chrono::duration(tEnd - tStart).count(); - std::cout << "Generating pre-filtered environment cube with " << numMips << " mip levels took " << tDiff << " ms" << std::endl; -} - void PlumageRender::GenerateBRDFLUT() { auto tStart = std::chrono::high_resolution_clock::now(); - constexpr VkFormat format = VK_FORMAT_R16G16_SFLOAT; - constexpr int32_t dim = 512; + const VkFormat format = VK_FORMAT_R16G16_SFLOAT; + const int32_t dim = 512; // Image - VkImageCreateInfo imageCI = vks::initializers::imageCreateInfo(); + VkImageCreateInfo imageCI{}; + imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageCI.imageType = VK_IMAGE_TYPE_2D; imageCI.format = format; imageCI.extent.width = dim; @@ -1251,28 +1284,31 @@ PlumageRender::PlumageRender(): imageCI.samples = VK_SAMPLE_COUNT_1_BIT; imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &ibltextures.lutBrdf.image)); - VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo(); + VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &textures.lutBrdf.image)); VkMemoryRequirements memReqs; - vkGetImageMemoryRequirements(device, ibltextures.lutBrdf.image, &memReqs); - memAlloc.allocationSize = memReqs.size; - memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &ibltextures.lutBrdf.deviceMemory)); - VK_CHECK_RESULT(vkBindImageMemory(device, ibltextures.lutBrdf.image, ibltextures.lutBrdf.deviceMemory, 0)); + vkGetImageMemoryRequirements(device, textures.lutBrdf.image, &memReqs); + VkMemoryAllocateInfo memAllocInfo{}; + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &textures.lutBrdf.deviceMemory)); + VK_CHECK_RESULT(vkBindImageMemory(device, textures.lutBrdf.image, textures.lutBrdf.deviceMemory, 0)); - // Image view - VkImageViewCreateInfo viewCI = vks::initializers::imageViewCreateInfo(); + // View + VkImageViewCreateInfo viewCI{}; + viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewCI.viewType = VK_IMAGE_VIEW_TYPE_2D; viewCI.format = format; viewCI.subresourceRange = {}; viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewCI.subresourceRange.levelCount = 1; viewCI.subresourceRange.layerCount = 1; - viewCI.image = ibltextures.lutBrdf.image; - VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &ibltextures.lutBrdf.view)); + viewCI.image = textures.lutBrdf.image; + VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &textures.lutBrdf.view)); // Sampler - VkSamplerCreateInfo samplerCI = vks::initializers::samplerCreateInfo(); + VkSamplerCreateInfo samplerCI{}; + samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerCI.magFilter = VK_FILTER_LINEAR; samplerCI.minFilter = VK_FILTER_LINEAR; samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; @@ -1281,16 +1317,12 @@ PlumageRender::PlumageRender(): samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerCI.minLod = 0.0f; samplerCI.maxLod = 1.0f; + samplerCI.maxAnisotropy = 1.0f; samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &ibltextures.lutBrdf.sampler)); - - ibltextures.lutBrdf.descriptor.imageView = ibltextures.lutBrdf.view; - ibltextures.lutBrdf.descriptor.sampler = ibltextures.lutBrdf.sampler; - ibltextures.lutBrdf.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - ibltextures.lutBrdf.device = vulkanDevice; + VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &textures.lutBrdf.sampler)); // FB, Att, RP, Pipe, etc. - VkAttachmentDescription attDesc = {}; + VkAttachmentDescription attDesc{}; // Color attachment attDesc.format = format; attDesc.samples = VK_SAMPLE_COUNT_1_BIT; @@ -1302,7 +1334,7 @@ PlumageRender::PlumageRender(): attDesc.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkSubpassDescription subpassDescription = {}; + VkSubpassDescription subpassDescription{}; subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpassDescription.colorAttachmentCount = 1; subpassDescription.pColorAttachments = &colorReference; @@ -1324,8 +1356,9 @@ PlumageRender::PlumageRender(): dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - // Create the actual render pass - VkRenderPassCreateInfo renderPassCI = vks::initializers::renderPassCreateInfo(); + // Create the actual renderpass + VkRenderPassCreateInfo renderPassCI{}; + renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; renderPassCI.attachmentCount = 1; renderPassCI.pAttachments = &attDesc; renderPassCI.subpassCount = 1; @@ -1336,10 +1369,11 @@ PlumageRender::PlumageRender(): VkRenderPass renderpass; VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderpass)); - VkFramebufferCreateInfo framebufferCI = vks::initializers::framebufferCreateInfo(); + VkFramebufferCreateInfo framebufferCI{}; + framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferCI.renderPass = renderpass; framebufferCI.attachmentCount = 1; - framebufferCI.pAttachments = &ibltextures.lutBrdf.view; + framebufferCI.pAttachments = &textures.lutBrdf.view; framebufferCI.width = dim; framebufferCI.height = dim; framebufferCI.layers = 1; @@ -1347,64 +1381,101 @@ PlumageRender::PlumageRender(): VkFramebuffer framebuffer; VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCI, nullptr, &framebuffer)); - // Descriptors + // Desriptors VkDescriptorSetLayout descriptorsetlayout; - std::vector setLayoutBindings = {}; - VkDescriptorSetLayoutCreateInfo descriptorsetlayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorsetlayoutCI, nullptr, &descriptorsetlayout)); - - // Descriptor Pool - std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) }; - VkDescriptorPoolCreateInfo descriptorPoolCI = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); - VkDescriptorPool descriptorpool; - VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorpool)); - - // Descriptor sets - VkDescriptorSet descriptorset; - VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorpool, &descriptorsetlayout, 1); - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorset)); + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; + descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorsetlayout)); // Pipeline layout VkPipelineLayout pipelinelayout; - VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorsetlayout, 1); + VkPipelineLayoutCreateInfo pipelineLayoutCI{}; + pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCI.setLayoutCount = 1; + pipelineLayoutCI.pSetLayouts = &descriptorsetlayout; VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelinelayout)); // Pipeline - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); - VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE); - VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); - VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); - VkPipelineDepthStencilStateCreateInfo depthStencilState = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_FALSE, VK_FALSE, VK_COMPARE_OP_LESS_OR_EQUAL); - VkPipelineViewportStateCreateInfo viewportState = vks::initializers::pipelineViewportStateCreateInfo(1, 1); - VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT); + VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; + inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineRasterizationStateCreateInfo rasterizationStateCI{}; + rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL; + rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; + rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizationStateCI.lineWidth = 1.0f; + + VkPipelineColorBlendAttachmentState blendAttachmentState{}; + blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendAttachmentState.blendEnable = VK_FALSE; + + VkPipelineColorBlendStateCreateInfo colorBlendStateCI{}; + colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlendStateCI.attachmentCount = 1; + colorBlendStateCI.pAttachments = &blendAttachmentState; + + VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{}; + depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencilStateCI.depthTestEnable = VK_FALSE; + depthStencilStateCI.depthWriteEnable = VK_FALSE; + depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + depthStencilStateCI.front = depthStencilStateCI.back; + depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS; + + VkPipelineViewportStateCreateInfo viewportStateCI{}; + viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportStateCI.viewportCount = 1; + viewportStateCI.scissorCount = 1; + + VkPipelineMultisampleStateCreateInfo multisampleStateCI{}; + multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; - VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); - VkPipelineVertexInputStateCreateInfo emptyInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); + VkPipelineDynamicStateCreateInfo dynamicStateCI{}; + dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicStateCI.pDynamicStates = dynamicStateEnables.data(); + dynamicStateCI.dynamicStateCount = static_cast(dynamicStateEnables.size()); + + VkPipelineVertexInputStateCreateInfo emptyInputStateCI{}; + emptyInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + std::array shaderStages; - VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelinelayout, renderpass); - pipelineCI.pInputAssemblyState = &inputAssemblyState; - pipelineCI.pRasterizationState = &rasterizationState; - pipelineCI.pColorBlendState = &colorBlendState; - pipelineCI.pMultisampleState = &multisampleState; - pipelineCI.pViewportState = &viewportState; - pipelineCI.pDepthStencilState = &depthStencilState; - pipelineCI.pDynamicState = &dynamicState; + VkGraphicsPipelineCreateInfo pipelineCI{}; + pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineCI.layout = pipelinelayout; + pipelineCI.renderPass = renderpass; + pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; + pipelineCI.pVertexInputState = &emptyInputStateCI; + pipelineCI.pRasterizationState = &rasterizationStateCI; + pipelineCI.pColorBlendState = &colorBlendStateCI; + pipelineCI.pMultisampleState = &multisampleStateCI; + pipelineCI.pViewportState = &viewportStateCI; + pipelineCI.pDepthStencilState = &depthStencilStateCI; + pipelineCI.pDynamicState = &dynamicStateCI; pipelineCI.stageCount = 2; pipelineCI.pStages = shaderStages.data(); - pipelineCI.pVertexInputState = &emptyInputState; - // Look-up-table (from BRDF) pipeline - shaderStages[0] = loadShader(filePath.brdfVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(filePath.brdfFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT); + // Look-up-table (from BRDF) pipeline + shaderStages = { + loadShader(device, "genbrdflut.vert.spv", VK_SHADER_STAGE_VERTEX_BIT), + loadShader(device, "genbrdflut.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT) + }; VkPipeline pipeline; VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); + for (auto shaderStage : shaderStages) { + vkDestroyShaderModule(device, shaderStage.module, nullptr); + } // Render VkClearValue clearValues[1]; clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } }; - VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); + VkRenderPassBeginInfo renderPassBeginInfo{}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassBeginInfo.renderPass = renderpass; renderPassBeginInfo.renderArea.extent.width = dim; renderPassBeginInfo.renderArea.extent.height = dim; @@ -1414,8 +1485,17 @@ PlumageRender::PlumageRender(): VkCommandBuffer cmdBuf = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - VkViewport viewport = vks::initializers::viewport((float)dim, (float)dim, 0.0f, 1.0f); - VkRect2D scissor = vks::initializers::rect2D(dim, dim, 0, 0); + + VkViewport viewport{}; + viewport.width = (float)dim; + viewport.height = (float)dim; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor{}; + scissor.extent.width = dim; + scissor.extent.height = dim; + vkCmdSetViewport(cmdBuf, 0, 1, &viewport); vkCmdSetScissor(cmdBuf, 0, 1, &scissor); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); @@ -1430,7 +1510,11 @@ PlumageRender::PlumageRender(): vkDestroyRenderPass(device, renderpass, nullptr); vkDestroyFramebuffer(device, framebuffer, nullptr); vkDestroyDescriptorSetLayout(device, descriptorsetlayout, nullptr); - vkDestroyDescriptorPool(device, descriptorpool, nullptr); + + textures.lutBrdf.descriptor.imageView = textures.lutBrdf.view; + textures.lutBrdf.descriptor.sampler = textures.lutBrdf.sampler; + textures.lutBrdf.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + textures.lutBrdf.device = vulkanDevice; auto tEnd = std::chrono::high_resolution_clock::now(); auto tDiff = std::chrono::duration(tEnd - tStart).count(); diff --git a/src/render/render.h b/src/render/render.h index e6279c6..435d1cf 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -7,14 +7,14 @@ #include #include #include +#include #include "algorithm" - - #include -#include "vulkanexamplebase.h" +#include "VulkanExampleBase.h" #include "glTFModel.h" +//#include "VulkanDevice.hpp" #define ENABLE_VALIDATION false @@ -29,6 +29,12 @@ public: bool ToneMapping = true; bool pbrEnabled = true; + struct stat + { + + } info ; + + struct Models { glTFModel::Model scene; @@ -84,22 +90,36 @@ public: } pushConstBlockMaterial; struct FilePath - { - std::string glTFModelFilePath = getAssetPath() + "buster_drone/busterDrone.gltf"; - std::string skyboxModleFilePath = getAssetPath() + "models/cube.gltf"; - std::string iblTexturesFilePath = getAssetPath() + "textures/hdr/pisa_cube.ktx"; + { //model path + std::string glTFModelFilePath = getAssetPath() + "DamagedHelmet.gltf"; std::string modelVertShaderPath = getAssetPath() + "buster_drone/shaders/glsl/mesh.vert.spv"; std::string modelFragShaderPath = getAssetPath() + "buster_drone/shaders/glsl/mesh.frag.spv"; + + // skybox path + std::string skyboxModleFilePath = getAssetPath() + "models/cube.gltf"; + std::string skyboxVertShaderPath = getAssetPath() + "shaders/skybox.vert.spv"; + std::string skyboxFragShaderPath = getAssetPath() + "shaders/skybox.frag.spv"; + + std::string iblTexturesFilePath = getAssetPath() + "textures/hdr/pisa_cube.ktx"; + //tonemapping std::string tonemappingVertShaderPath = getAssetPath() + "buster_drone/shaders/glsl/genbrdflut.vert.spv"; std::string tonemappingEnableFragShaderPath = getAssetPath() + "buster_drone/shaders/glsl/tonemapping_enable.frag.spv"; std::string tonemappingDisableFragShaderPath = getAssetPath() + "buster_drone/shaders/glsl/tonemapping_disable.frag.spv"; - std::string irradianceVertShaderPath = getAssetPath() + "buster_drone/shaders/glsl/filtercube.vert.spv"; - std::string irradianceFragShaderPath = getAssetPath() + "buster_drone/shaders/glsl/irradiancecube.frag.spv"; - std::string prefilterVertShaderPath = getAssetPath() + "buster_drone/shaders/glsl/filtercube.vert.spv"; - std::string prefilterFragShaderPath = getAssetPath() + "buster_drone/shaders/glsl/prefilterenvmap.frag.spv"; + + + // cube map + std::string irradianceFragShaderPath = getAssetPath() + "shaders/irradiancecube.frag.spv"; + std::string filterVertShaderPath = getAssetPath() + "shaders/filtercube.vert.spv"; + std::string prefilterEnvmapFragShaderPath = getAssetPath() + "shaders/prefilterenvmap.frag.spv"; + //brdf cube map std::string brdfVertShaderPath = getAssetPath() + "buster_drone/shaders/glsl/genbrdflut.vert.spv"; std::string brdfFragShaderPath = getAssetPath() + "buster_drone/shaders/glsl/genbrdflut.frag.spv"; + // environment map texture + std::string envMapFilePath = getAssetPath() + "environments/papermill.ktx"; + // pbr shader + std::string pbrVertShaderPath = getAssetPath() + "shaders/pbr.vert.spv"; + std::string pbrFragShaderPath = getAssetPath() + "shaders/pbr_khr.frag.spv"; } filePath; @@ -188,8 +208,8 @@ public: } lightSource; - - /* + //cube map generation + struct OffScreen { VkImage image; @@ -197,7 +217,7 @@ public: VkDeviceMemory memory; VkFramebuffer framebuffer; } offscreen; - */ + struct IrradiancePushBlock { glm::mat4 mvp; @@ -259,11 +279,11 @@ public: void loadEnvironment(std::string filename); void buildCommandBuffers(); void loadAssets(); - void setupDescriptors(); + void setupNodeDescriptorSet(glTFModel::Node* node); + void setupDescriptors(); void preparePipelines(); void CreateToneMappingPipeline(); - void GenerateIrradianceCubemap(); - void GeneratePrefilteredCubemap(); + void generateCubemaps(); void GenerateBRDFLUT(); void prepareUniformBuffers(); void updateUniformBuffers();