diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h index c21ac6e..0cfa246 100644 --- a/base/vulkanexamplebase.h +++ b/base/vulkanexamplebase.h @@ -104,7 +104,7 @@ public: uint32_t selectedPhysicalDeviceIndex = 0; bool prepared = false; - float frameTimer = 1.0f; + Camera camera; glm::vec2 mousePos; bool paused = false; @@ -118,16 +118,7 @@ public: VkImageView view; } depthStencil; - struct GamePadState { - glm::vec2 axisLeft = glm::vec2(0.0f); - glm::vec2 axisRight = glm::vec2(0.0f); - } gamePadState; - - struct MouseButtons { - bool left = false; - bool right = false; - bool middle = false; - } mouseButtons; + // OS specific #if defined(_WIN32) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 23ec7c7..312a31a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,7 +34,7 @@ function(buildHomework HOMEWORK_NAME) "render/glTFModel.h" "render/glTFModel.cpp" - "render/vulkanFoundation.h" "render/vulkanFoundation.cpp" "render/renderSetter.h" "render/renderSetter.cpp" "render/PBR.h" "render/PBR.cpp") + "render/vulkanFoundation.h" "render/vulkanFoundation.cpp" "render/renderSetter.h" "render/renderSetter.cpp" "render/PBR.h" "render/PBR.cpp" "render/renderUI.h" "render/renderUI.cpp" "render/renderIO.h" "render/renderIO.cpp") target_link_libraries(${HOMEWORK_NAME} base ${Vulkan_LIBRARY} ${WINLIBS}) else(WIN32) add_executable(${HOMEWORK_NAME} ${MAIN_CPP} ${SOURCE} ${MAIN_HEADER} ${SHADERS_GLSL} ${SHADERS_HLSL} ${README_FILES}) diff --git a/src/render/PBR.h b/src/render/PBR.h index 24f258c..8c1b429 100644 --- a/src/render/PBR.h +++ b/src/render/PBR.h @@ -1,5 +1,6 @@ #pragma once #include "glm/glm.hpp" +#include @@ -28,6 +29,16 @@ namespace PBR float alphaMaskCutoff; } pushConstBlockMaterial; + struct Textures { + vks::TextureCubeMap environmentCube; + vks::Texture2D empty; + vks::Texture2D lutBrdf; + vks::TextureCubeMap irradianceCube; + vks::TextureCubeMap prefilteredCube; + } textures; + + enum PBRWorkflows { PBR_WORKFLOW_METALLIC_ROUGHNESS = 0, PBR_WORKFLOW_SPECULAR_GLOSINESS = 1 }; + private: diff --git a/src/render/glTFModel.cpp b/src/render/glTFModel.cpp index 671fc70..5ff37d8 100644 --- a/src/render/glTFModel.cpp +++ b/src/render/glTFModel.cpp @@ -29,7 +29,7 @@ glTFModel::BoundingBox::BoundingBox(glm::vec3 min, glm::vec3 max) : min(min), max(max) { }; - //Axis-Aligned Bounding Box), AABB + //Axis-Aligned Bounding Box),简称 AABB glTFModel::BoundingBox glTFModel::BoundingBox::getAABB(glm::mat4 m) { glm::vec3 min = glm::vec3(m[3]); glm::vec3 max = min; diff --git a/src/render/glTFModel.h b/src/render/glTFModel.h index 65caf3f..c44545f 100644 --- a/src/render/glTFModel.h +++ b/src/render/glTFModel.h @@ -35,6 +35,7 @@ #include "VulkanDevice.hpp" //#include "VulkanUtils.hpp" #include "vulkan/vulkan.h" +#include "vulkanFoundation.h" #define ENABLE_VALIDATION false #define MAX_NUM_JOINTS 128u @@ -258,6 +259,7 @@ namespace glTFModel void loadFromFile(std::string filename, vks::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f); void drawNode(Node* node, VkCommandBuffer commandBuffer); void draw(VkCommandBuffer commandBuffer); + void createNodeCommandBuffer(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode); void calculateBoundingBox(Node* node, Node* parent); void getSceneDimensions(); void updateAnimation(uint32_t index, float time); diff --git a/src/render/render.cpp b/src/render/render.cpp index 11a5ca8..74cf2ff 100644 --- a/src/render/render.cpp +++ b/src/render/render.cpp @@ -18,112 +18,25 @@ //#include "assetLoader.h" - -PlumageRender::PlumageRender() - { - title = "plumage render"; - - } - - -void PlumageRender::initWindow(int Width, int Height) +void PlumageRender::renderMain::initWindow(int Width, int Height) { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + window = glfwCreateWindow(Width, Height, "vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); glfwSetFramebufferSizeCallback(window, framebufferResizeCallback); } -void PlumageRender::framebufferResizeCallback(GLFWwindow* window, int width, int height) +void PlumageRender::renderMain::framebufferResizeCallback(GLFWwindow* window, int width, int height) { - auto app = reinterpret_cast(glfwGetWindowUserPointer(window)); + auto app = reinterpret_cast(glfwGetWindowUserPointer(window)); app->framebufferResized = true; } -// 重构至gltfModel中 -void PlumageRender::renderNode(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode) { - if (node->mesh) { - // Render mesh primitives - for (glTFModel::Primitive* primitive : node->mesh->primitives) { - if (primitive->material.alphaMode == alphaMode) { - VkPipeline pipeline = VK_NULL_HANDLE; - switch (alphaMode) { - case glTFModel::Material::ALPHAMODE_OPAQUE: - case glTFModel::Material::ALPHAMODE_MASK: - pipeline = primitive->material.doubleSided ? pipelines.pbrDoubleSided : pipelines.pbr; - break; - case glTFModel::Material::ALPHAMODE_BLEND: - pipeline = pipelines.pbrAlphaBlend; - break; - } - - if (pipeline != boundPipeline) { - vkCmdBindPipeline(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - boundPipeline = pipeline; - } - - const std::vector descriptorsets = { - descriptorSets[cbIndex].scene, - primitive->material.descriptorSet, - node->mesh->uniformBuffer.descriptorSet, - }; - vkCmdBindDescriptorSets(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast(descriptorsets.size()), descriptorsets.data(), 0, NULL); - - // Pass material parameters as push constants - PushConstBlockMaterial pushConstBlockMaterial{}; - pushConstBlockMaterial.emissiveFactor = primitive->material.emissiveFactor; - // To save push constant space, availabilty and texture coordiante set are combined - // -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set - pushConstBlockMaterial.colorTextureSet = primitive->material.baseColorTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1; - pushConstBlockMaterial.normalTextureSet = primitive->material.normalTexture != nullptr ? primitive->material.texCoordSets.normal : -1; - pushConstBlockMaterial.occlusionTextureSet = primitive->material.occlusionTexture != nullptr ? primitive->material.texCoordSets.occlusion : -1; - pushConstBlockMaterial.emissiveTextureSet = primitive->material.emissiveTexture != nullptr ? primitive->material.texCoordSets.emissive : -1; - pushConstBlockMaterial.alphaMask = static_cast(primitive->material.alphaMode == glTFModel::Material::ALPHAMODE_MASK); - pushConstBlockMaterial.alphaMaskCutoff = primitive->material.alphaCutoff; - - // TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present - - if (primitive->material.pbrWorkflows.metallicRoughness) { - // Metallic roughness workflow - pushConstBlockMaterial.workflow = static_cast(PBR_WORKFLOW_METALLIC_ROUGHNESS); - pushConstBlockMaterial.baseColorFactor = primitive->material.baseColorFactor; - pushConstBlockMaterial.metallicFactor = primitive->material.metallicFactor; - pushConstBlockMaterial.roughnessFactor = primitive->material.roughnessFactor; - pushConstBlockMaterial.PhysicalDescriptorTextureSet = primitive->material.metallicRoughnessTexture != nullptr ? primitive->material.texCoordSets.metallicRoughness : -1; - pushConstBlockMaterial.colorTextureSet = primitive->material.baseColorTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1; - } - - if (primitive->material.pbrWorkflows.specularGlossiness) { - // Specular glossiness workflow - pushConstBlockMaterial.workflow = static_cast(PBR_WORKFLOW_SPECULAR_GLOSINESS); - pushConstBlockMaterial.PhysicalDescriptorTextureSet = primitive->material.extension.specularGlossinessTexture != nullptr ? primitive->material.texCoordSets.specularGlossiness : -1; - pushConstBlockMaterial.colorTextureSet = primitive->material.extension.diffuseTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1; - pushConstBlockMaterial.diffuseFactor = primitive->material.extension.diffuseFactor; - pushConstBlockMaterial.specularFactor = glm::vec4(primitive->material.extension.specularFactor, 1.0f); - } - - vkCmdPushConstants(commandBuffers[cbIndex], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlockMaterial), &pushConstBlockMaterial); - - if (primitive->hasIndices) { - vkCmdDrawIndexed(commandBuffers[cbIndex], primitive->indexCount, 1, primitive->firstIndex, 0, 0); - } - else { - vkCmdDraw(commandBuffers[cbIndex], primitive->vertexCount, 1, 0, 0); - } - } - } - - }; - for (auto child : node->children) { - renderNode(child, cbIndex, alphaMode); - } - } - -void PlumageRender::buildCommandBuffers() +void PlumageRender::renderMain::buildCommandBuffers() { VkCommandBufferBeginInfo cmdBufferBeginInfo{}; cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -171,7 +84,7 @@ void PlumageRender::buildCommandBuffers() vkCmdSetScissor(currentCB, 0, 1, &scissor); VkDeviceSize offsets[1] = { 0 }; - + if (displayBackground) { vkCmdBindDescriptorSets(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i].skybox, 0, nullptr); vkCmdBindPipeline(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skybox); @@ -215,7 +128,7 @@ void PlumageRender::buildCommandBuffers() } -void PlumageRender::loadScene(std::string filename) +void PlumageRender::renderMain::loadScene(std::string filename) { std::cout << "Loading scene from " << filename << std::endl; models.scene.destroy(device); @@ -229,7 +142,7 @@ void PlumageRender::loadScene(std::string filename) camera.setRotation({ 0.0f, 0.0f, 0.0f }); } -void PlumageRender::loadEnvironment(std::string filename) +void PlumageRender::renderMain::loadEnvironment(std::string filename) { std::cout << "Loading environment from " << filename << std::endl; if (textures.environmentCube.image) { @@ -241,7 +154,7 @@ void PlumageRender::loadEnvironment(std::string filename) generateCubemaps(); } -void PlumageRender::loadAssets() +void PlumageRender::renderMain::loadAssets() { const std::string assetpath = getAssetPath(); @@ -270,35 +183,15 @@ void PlumageRender::loadAssets() loadEnvironment(envMapFile.c_str()); } -void PlumageRender::setupNodeDescriptorSet(glTFModel::Node* node) +void PlumageRender::renderMain::setupNodeDescriptorSet(glTFModel::Node* node) { /* This sample uses separate descriptor sets (and layouts) for the matrices and materials (textures) */ - 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; - - vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); - } - for (auto& child : node->children) { - setupNodeDescriptorSet(child); - } + } -void PlumageRender::setupDescriptors() +void PlumageRender::renderMain::setupDescriptors() { @@ -362,101 +255,10 @@ void PlumageRender::setupDescriptors() // Material (samplers) { - - // 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) - { - - - // 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); } } @@ -464,7 +266,7 @@ void PlumageRender::setupDescriptors() // irradiance cube map // prefileter environment cube map // 重构到PBR中 -void PlumageRender::generateCubemaps() +void PlumageRender::renderMain::generateCubemaps() { enum Target { IRRADIANCE = 0, PREFILTEREDENV = 1 }; @@ -1003,7 +805,7 @@ void PlumageRender::generateCubemaps() } // generate BRDF integration map for roughness/NdotV // 重构到PBR -void PlumageRender::generateBRDFLUT() +void PlumageRender::renderMain::generateBRDFLUT() { auto tStart = std::chrono::high_resolution_clock::now(); @@ -1260,8 +1062,9 @@ void PlumageRender::generateBRDFLUT() std::cout << "Generating BRDF LUT took " << tDiff << " ms" << std::endl; } -// Prepare and initialize uniform buffer containing shader uniforms -void PlumageRender::prepareUniformBuffers() +// Prepare and initialize uniform buffer containing shader uniforms + +void PlumageRender::renderMain::prepareUniformBuffers() { for (auto& uniformBuffer : uniformBuffers) { uniformBuffer.scene.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderDataScene)); @@ -1270,37 +1073,38 @@ void PlumageRender::prepareUniformBuffers() } updateUniformBuffers(); } -// 更新统一缓冲区 -void PlumageRender::updateUniformBuffers() + +// 更新统一缓冲区 done +void PlumageRender::renderMain::updateUniformBuffers() { - // Scene - shaderDataScene.projection = camera.matrices.perspective; - shaderDataScene.view = camera.matrices.view; + // Scene + shaderDataScene.projection = camera.matrices.perspective; + shaderDataScene.view = camera.matrices.view; - // Center and scale model - float scale = (1.0f / std::max(models.scene.aabb[0][0], std::max(models.scene.aabb[1][1], models.scene.aabb[2][2]))) * 0.5f; - glm::vec3 translate = -glm::vec3(models.scene.aabb[3][0], models.scene.aabb[3][1], models.scene.aabb[3][2]); - translate += -0.5f * glm::vec3(models.scene.aabb[0][0], models.scene.aabb[1][1], models.scene.aabb[2][2]); + // Center and scale model + float scale = (1.0f / std::max(models.scene.aabb[0][0], std::max(models.scene.aabb[1][1], models.scene.aabb[2][2]))) * 0.5f; + glm::vec3 translate = -glm::vec3(models.scene.aabb[3][0], models.scene.aabb[3][1], models.scene.aabb[3][2]); + translate += -0.5f * glm::vec3(models.scene.aabb[0][0], models.scene.aabb[1][1], models.scene.aabb[2][2]); - shaderDataScene.model = glm::mat4(1.0f); - shaderDataScene.model[0][0] = scale; - shaderDataScene.model[1][1] = scale; - shaderDataScene.model[2][2] = scale; - shaderDataScene.model = glm::translate(shaderDataScene.model, translate); + shaderDataScene.model = glm::mat4(1.0f); + shaderDataScene.model[0][0] = scale; + shaderDataScene.model[1][1] = scale; + shaderDataScene.model[2][2] = scale; + shaderDataScene.model = glm::translate(shaderDataScene.model, translate); - shaderDataScene.camPos = glm::vec3( - -camera.position.z * sin(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)), - -camera.position.z * sin(glm::radians(camera.rotation.x)), - camera.position.z * cos(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)) - ); + shaderDataScene.camPos = glm::vec3( + -camera.position.z * sin(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)), + -camera.position.z * sin(glm::radians(camera.rotation.x)), + camera.position.z * cos(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)) + ); - // Skybox - shaderDataSkybox.projection = camera.matrices.perspective; - shaderDataSkybox.view = camera.matrices.view; - shaderDataSkybox.model = glm::mat4(glm::mat3(camera.matrices.view)); + // Skybox + shaderDataSkybox.projection = camera.matrices.perspective; + shaderDataSkybox.view = camera.matrices.view; + shaderDataSkybox.model = glm::mat4(glm::mat3(camera.matrices.view)); } -void PlumageRender::updateShaderData() +void PlumageRender::renderMain::updateShaderData() { shaderData.lightDir = glm::vec4( sin(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)), @@ -1309,7 +1113,7 @@ void PlumageRender::updateShaderData() 0.0f); } // todo:重写成glfw的 -void PlumageRender::windowResized() +void PlumageRender::renderMain::windowResized() { buildCommandBuffers(); vkDeviceWaitIdle(device); @@ -1318,71 +1122,40 @@ void PlumageRender::windowResized() updateUIOverlay(); } -void PlumageRender::prepare() +void PlumageRender::renderMain::prepare() +{ + //VulkanExampleBase::prepare(); + + setupCamera(); + + loadAssets(); + generateBRDFLUT(); + generateCubemaps(); + prepareUniformBuffers(); + setupDescriptors(); + preparePipelines(); + if (!setter.settings.headless) { - //VulkanExampleBase::prepare(); - - camera.type = Camera::CameraType::lookat; - - camera.setPerspective(45.0f, (float)setter.settings.width / (float)setter.settings.height, 0.1f, 256.0f); - camera.rotationSpeed = 0.25f; - camera.movementSpeed = 0.1f; - camera.setPosition({ 0.0f, 0.0f, -1.0f }); - camera.setRotation({ 0.0f, 0.0f, 0.0f }); - - waitFences.resize(renderAhead); - presentCompleteSemaphores.resize(renderAhead); - renderCompleteSemaphores.resize(renderAhead); - commandBuffers.resize(swapChain.imageCount); - uniformBuffers.resize(swapChain.imageCount); - descriptorSets.resize(swapChain.imageCount); - // Command buffer execution fences - for (auto& waitFence : waitFences) { - VkFenceCreateInfo fenceCI{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT }; - VK_CHECK_RESULT(vkCreateFence(device, &fenceCI, nullptr, &waitFence)); - } - if (!setter.settings.headless) - { - for (auto& semaphore : presentCompleteSemaphores) { - VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 }; - VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore)); - } - } - // Queue ordering semaphores - - for (auto& semaphore : renderCompleteSemaphores) { - VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 }; - VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore)); - } - // Command buffers - { - VkCommandBufferAllocateInfo cmdBufAllocateInfo{}; - cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - cmdBufAllocateInfo.commandPool = cmdPool; - cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - cmdBufAllocateInfo.commandBufferCount = static_cast(commandBuffers.size()); - VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commandBuffers.data())); - } - - loadAssets(); - generateBRDFLUT(); - generateCubemaps(); - prepareUniformBuffers(); - setupDescriptors(); - preparePipelines(); - if (!setter.settings.headless) - { - gui = new UI(vulkanDevice, renderPass, queue, pipelineCache, setter.settings.sampleCount); - updateUIOverlay(); - } - - - buildCommandBuffers(); - - prepared = true; + gui = new UI(vulkanDevice, renderPass, queue, pipelineCache, setter.settings.sampleCount); + updateUIOverlay(); } + buildCommandBuffers(); -void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue) + prepared = true; +} + +void PlumageRender::renderMain::setupCamera() +{ + camera.type = Camera::CameraType::lookat; + + camera.setPerspective(45.0f, (float)setter.settings.width / (float)setter.settings.height, 0.1f, 256.0f); + camera.rotationSpeed = 0.25f; + camera.movementSpeed = 0.1f; + camera.setPosition({ 0.0f, 0.0f, -1.0f }); + camera.setRotation({ 0.0f, 0.0f, 0.0f }); +} + +void PlumageRender::renderMain::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue) { VkSubmitInfo submitInfo = vks::initializers::submitInfo(); submitInfo.commandBufferCount = 1; @@ -1397,7 +1170,7 @@ void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue) // todo :根据physicalDeviceIndex确定子文件夹路径,frameIndex确定fileName // 移动到fileSystem里 -void PlumageRender::writeImageToFile(std::string filePath) +void PlumageRender::renderMain::writeImageToFile(std::string filePath) { bool screenshotSaved = false; @@ -1630,7 +1403,7 @@ void PlumageRender::writeImageToFile(std::string filePath) } -void PlumageRender::outputImageSequence() +void PlumageRender::renderMain::outputImageSequence() { // 比较已保存的帧数和设置里的开始帧数,在生成前清理上一次生成的图片序列 if (savedFrameCounter == setter.settings.startFrameCount) @@ -1641,7 +1414,7 @@ void PlumageRender::outputImageSequence() // 根据显卡编号设置输出路径(todo:提前到配置里) setter.filePath.deviceSpecFilePath = setter.filePath.imageOutputPath + "/device" + std::to_string(selectedPhysicalDeviceIndex); // 非第一次生成,生成结束的边界条件 - if (savedFrameCounter > setter.settings.outputFrameCount) + if (savedFrameCounter > setter.settings.endFrameIndex) { // 避免重复改变为true带来的无效性能开销 if (signal.imageSequenceOutputComplete) @@ -1670,7 +1443,7 @@ void PlumageRender::outputImageSequence() savedFrameCounter++; } -void PlumageRender::imageSequenceToVideo() +void PlumageRender::renderMain::imageSequenceToVideo() { // 边界条件,图片序列输出未完成 if (!signal.imageSequenceOutputComplete) @@ -1710,7 +1483,7 @@ void PlumageRender::imageSequenceToVideo() removeImageSequence(); } -void PlumageRender::removeImageSequence() +void PlumageRender::renderMain::removeImageSequence() { // 函数非第一次运行的边界条件 if (savedFrameCounter != setter.settings.startFrameCount) @@ -1745,7 +1518,7 @@ void PlumageRender::removeImageSequence() -void PlumageRender::render() +void PlumageRender::renderMain::render() { if (!prepared) { return; @@ -1780,7 +1553,7 @@ void PlumageRender::render() // Update UBOs updateUniformBuffers(); - UniformBufferSet currentUB = uniformBuffers[currentBuffer]; + UniformBufferSet[currentUB] = uniformBuffers[currentBuffer]; memcpy(currentUB.scene.mapped, &shaderDataScene, sizeof(shaderDataScene)); memcpy(currentUB.params.mapped, &shaderData, sizeof(shaderData)); memcpy(currentUB.skybox.mapped, &shaderDataSkybox, sizeof(shaderDataSkybox)); @@ -1838,7 +1611,7 @@ void PlumageRender::render() } -void PlumageRender::fileDropped(std::string filename) +void PlumageRender::renderMain::fileDropped(std::string filename) { vkDeviceWaitIdle(device); loadScene(filename); @@ -1847,216 +1620,9 @@ void PlumageRender::fileDropped(std::string filename) } // 重构到单独的UI里 -void PlumageRender::updateUIOverlay() +void PlumageRender::renderMain::updateUIOverlay() { - ImGuiIO& io = ImGui::GetIO(); - - ImVec2 lastDisplaySize = io.DisplaySize; - io.DisplaySize = ImVec2((float)setter.settings.width, (float)setter.settings.height); - io.DeltaTime = frameTimer; - - io.MousePos = ImVec2(mousePos.x, mousePos.y); - io.MouseDown[0] = mouseButtons.left; - io.MouseDown[1] = mouseButtons.right; - - gui->pushConstBlock.scale = glm::vec2(2.0f / io.DisplaySize.x, 2.0f / io.DisplaySize.y); - gui->pushConstBlock.translate = glm::vec2(-1.0f); - - bool updateShaderParams = false; - bool updateCBs = false; - float scale = 1.0f; - bool boolTitleWindowShow = false; - ImGui::NewFrame(); - - ImGui::SetNextWindowPos(ImVec2(10000, 10000)); - //ImGui::SetNextWindowSize(ImVec2(200 * scale, (models.scene.animations.size() > 0 ? 440 : 360) * scale), ImGuiSetCond_Always); - ImGui::Begin("", nullptr, ImGuiWindowFlags_NoFocusOnAppearing|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoBringToFrontOnFocus); - ImGui::PushItemWidth(100.0f * scale); - - - - - if(gui->beginMainMenuBar()) { - if (gui->beginMenu(chineseUI.menuFile)) - { - if (gui->menuItem(chineseUI.menuOpenNewModel)) - { - std::wstring filename = L""; - wchar_t buffer[MAX_PATH]; - OPENFILENAMEW ofn; - ZeroMemory(&buffer, sizeof(buffer)); - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.lpstrFilter = L"glTF files\0*.gltf;*.glb\0"; - ofn.lpstrFile = buffer; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrTitle = L"Select a glTF file to load"; - ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; - if (GetOpenFileNameW(&ofn)) { - filename = buffer; - - } - - if (!filename.empty()) { - vkDeviceWaitIdle(device); - std::wstring_convert> converter; - std::string stringFilename = converter.to_bytes(filename); - loadScene(stringFilename); - setupDescriptors(); - updateCBs = true; - signal.imageSequenceOutputComplete = false; - signal.imageSequenceToVideoComplete = false; - savedFrameCounter = 1; - } - } - gui->endMenu(); - } - if (gui->beginMenu(chineseUI.menuEnvironment)) - { - if (gui->beginMenu(chineseUI.menuEnvironmentConfig)) - { - if (gui->combo(chineseUI.environmentMap, selectedEnvironment, environments)) { - vkDeviceWaitIdle(device); - loadEnvironment(environments[selectedEnvironment]); - setupDescriptors(); - updateCBs = true; - } - if (gui->checkbox(chineseUI.environmentBackGround, &displayBackground)) { - updateShaderParams = true; - } - if (gui->slider("Exposure", &shaderData.exposure, 0.1f, 10.0f)) { - updateShaderParams = true; - } - if (gui->slider("Gamma", &shaderData.gamma, 0.1f, 4.0f)) { - updateShaderParams = true; - } - if (gui->slider("IBL", &shaderData.scaleIBLAmbient, 0.0f, 1.0f)) { - updateShaderParams = true; - } - gui->endMenu(); - } - gui->endMenu(); - } - if (gui->beginMenu("debug")) - { - if (gui->beginMenu(chineseUI.menuDebugInput)) - { - const std::vector debugNamesInputs = { - "none", "Base color", "Normal", "Occlusion", "Emissive", "Metallic", "Roughness" - }; - if (gui->combo(chineseUI.debugInput, &debugViewInputs, debugNamesInputs)) { - shaderData.debugViewInputs = static_cast(debugViewInputs); - updateShaderParams = true; - } - gui->endMenu(); - } - if (gui->beginMenu("PBR")) - { - const std::vector debugNamesEquation = { - "none", "Diff (l,n)", "F (l,h)", "G (l,v,h)", "D (h)", "Specular" - }; - if (gui->combo(chineseUI.debugPBREquation, &debugViewEquation, debugNamesEquation)) { - shaderData.debugViewEquation = static_cast(debugViewEquation); - updateShaderParams = true; - } - gui->endMenu(); - } - - if (gui->beginMenu(chineseUI.menuDebugFrameRate)) - { - gui->text("%.1d fps (%.2f ms)", lastFPS, (1000.0f / lastFPS)); - gui->endMenu(); - } - gui->endMenu(); - } - if (gui->beginMenu(chineseUI.menuAnimation)) - { - if (models.scene.animations.size() > 0) - { - if (gui->beginMenu(chineseUI.menuAnimationActivation)) - { - gui->checkbox(chineseUI.pauseAnimation, &animate); - gui->endMenu(); - } - if (gui->beginMenu(chineseUI.menuAnimationAnimationSequence)) - { - std::vector animationNames; - for (auto animation : models.scene.animations) { - animationNames.push_back(animation.name); - } - gui->combo(chineseUI.animationSeq, &animationIndex, animationNames); - gui->endMenu(); - } - } - else - { - gui->text(chineseUI.menuAnimationNoAnimation); - } - gui->endMenu(); - } - - gui->endMainMenuBar(); - } - - - ImGui::PopItemWidth(); - ImGui::End(); - ImGui::Render(); - - ImDrawData* imDrawData = ImGui::GetDrawData(); - - // Check if ui buffers need to be recreated - if (imDrawData) { - VkDeviceSize vertexBufferSize = imDrawData->TotalVtxCount * sizeof(ImDrawVert); - VkDeviceSize indexBufferSize = imDrawData->TotalIdxCount * sizeof(ImDrawIdx); - - bool updateBuffers = (gui->vertexBuffer.buffer == VK_NULL_HANDLE) || (gui->vertexBuffer.count != imDrawData->TotalVtxCount) || (gui->indexBuffer.buffer == VK_NULL_HANDLE) || (gui->indexBuffer.count != imDrawData->TotalIdxCount); - - if (updateBuffers) { - vkDeviceWaitIdle(device); - if (gui->vertexBuffer.buffer) { - gui->vertexBuffer.destroy(); - } - gui->vertexBuffer.create(vulkanDevice, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, vertexBufferSize); - gui->vertexBuffer.count = imDrawData->TotalVtxCount; - if (gui->indexBuffer.buffer) { - gui->indexBuffer.destroy(); - } - gui->indexBuffer.create(vulkanDevice, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, indexBufferSize); - gui->indexBuffer.count = imDrawData->TotalIdxCount; - } - - // Upload data - ImDrawVert* vtxDst = (ImDrawVert*)gui->vertexBuffer.mapped; - ImDrawIdx* idxDst = (ImDrawIdx*)gui->indexBuffer.mapped; - for (int n = 0; n < imDrawData->CmdListsCount; n++) { - const ImDrawList* cmd_list = imDrawData->CmdLists[n]; - memcpy(vtxDst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idxDst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtxDst += cmd_list->VtxBuffer.Size; - idxDst += cmd_list->IdxBuffer.Size; - } - - gui->vertexBuffer.flush(); - gui->indexBuffer.flush(); - - updateCBs = updateCBs || updateBuffers; - } - - if (lastDisplaySize.x != io.DisplaySize.x || lastDisplaySize.y != io.DisplaySize.y) { - updateCBs = true; - } - - if (updateCBs) { - vkDeviceWaitIdle(device); - buildCommandBuffers(); - vkDeviceWaitIdle(device); - } - - if (updateShaderParams) { - updateShaderData(); - } } @@ -2096,13 +1662,14 @@ PlumageRender* plumageRender; int main() { - PlumageRender* plumageRender; - VulkanBackend::Setter setter; + PlumageRender::renderMain* plumageRender; + PlumageRender::Setter setter; if (!setter.settings.headless) { plumageRender->initWindow(setter.settings.width, setter.settings.height); - plumageRender->initVulkan(); + } + plumageRender->initVulkan(); return 0; } diff --git a/src/render/render.h b/src/render/render.h index aabb9c5..2753713 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -27,260 +27,176 @@ #include "renderSetter.h" #include "vulkanFoundation.h" - - #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" #define ENABLE_VALIDATION false - - -class PlumageRender : public VulkanExampleBase +namespace PlumageRender { -public: - - GLFWwindow* window; - - VulkanBackend::Setter setter; - - bool wireframe = false; - bool normalMapping = true; - bool ToneMapping = true; - bool pbrEnabled = true; - - struct stat + class renderMain : public VulkanExampleBase { + public: - } info ; + GLFWwindow* window; + + + PlumageRender::Setter setter; + + bool wireframe = false; + bool normalMapping = true; + bool ToneMapping = true; + bool pbrEnabled = true; + + struct stat + { + + } info; + + struct Signal + { + bool imageSequenceOutputComplete = false; + bool imageSequenceToVideoComplete = false; + + }signal; - struct Signal - { - bool imageSequenceOutputComplete = false; - bool imageSequenceToVideoComplete = false; - }signal; - - + glm::vec3 modelrot = glm::vec3(0.0f); + glm::vec3 modelPos = glm::vec3(0.0f); - struct Textures { - vks::TextureCubeMap environmentCube; - vks::Texture2D empty; - vks::Texture2D lutBrdf; - vks::TextureCubeMap irradianceCube; - vks::TextureCubeMap prefilteredCube; - } textures; + std::map environments; + std::string selectedEnvironment = "papermill"; + std::map scenes; + std::string selectedScene = "DamagedHelmet"; - struct ShaderData { - glm::vec4 lightDir; - float exposure = 4.5f; - float gamma = 2.2f; - float prefilteredCubeMipLevels; - float scaleIBLAmbient = 1.0f; - float debugViewInputs = 0; - float debugViewEquation = 0; - } shaderData; - struct ChinesesUI - { - const char * model = "模型"; - - const char* environmentMap = "环境贴图"; - const char* environmentBackGround = "启用背景贴图"; - const char* debugInput = "输入"; - const char* debugPBREquation = "PBR计算参数"; - const char* animation = "动画"; - const char* pauseAnimation = "启用动画"; - const char* animationSeq = "动画序列"; -// menu item - const char* menuFile = "文件"; - const char* menuOpenNewModel = "新模型.."; - const char* menuEnvironment = "环境光照"; - const char* menuEnvironmentConfig = "设置"; - const char* menuAnimation = "动画"; - const char* menuDebugFrameRate = "fps"; - const char* menuDebugInput = "输入"; - const char* menuAnimationNoAnimation = "当前模型没有动画!"; - - const char* menuAnimationActivation = "开关"; - const char* menuAnimationAnimationSequence = "动画序列"; + int32_t debugViewInputs = 0; + int32_t debugViewEquation = 0; + struct StagingBuffer { + VkBuffer buffer; + VkDeviceMemory memory; + } vertexStaging, indexStaging; - }chineseUI; - struct UniformBufferSet { - Buffer scene; - Buffer skybox; - Buffer params; + std::vector commandBuffers; + + uint32_t frameIndex = 0; + + //VkImage swapChainImage; + + int32_t animationIndex = 0; + float animationTimer = 0.0f; + bool animate = true; + + bool displayBackground = true; + + struct LightSource { + glm::vec3 color = glm::vec3(1.0f); + glm::vec3 rotation = glm::vec3(75.0f, 40.0f, 0.0f); + } lightSource; + + //cube map generation + + struct OffScreen + { + VkImage image; + VkImageView view; + VkDeviceMemory memory; + VkFramebuffer framebuffer; + } offscreen; + + struct IrradiancePushBlock + { + glm::mat4 mvp; + // Sampling deltas + float deltaPhi = (2.0f * float(M_PI)) / 180.0f; + float deltaTheta = (0.5f * float(M_PI)) / 64.0f; + } irradiancePushBlock; + + struct PrefilterPushBlock { + glm::mat4 mvp; + float roughness; + uint32_t numSamples = 32u; + } prefilterPushBlock; + + UI* gui; + + uint64_t savedFrameCounter = setter.settings.startFrameCount; + + bool framebufferResized = false; + + renderMain(); + ~renderMain() + { + // Clean up used Vulkan resources + // Note : Inherited destructor cleans up resources stored in base class + vkDestroyPipeline(device, pipelines.skybox, nullptr); + vkDestroyPipeline(device, pipelines.pbr, nullptr); + vkDestroyPipeline(device, pipelines.pbrAlphaBlend, nullptr); + + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.scene, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.material, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.node, nullptr); + + models.scene.destroy(device); + models.skybox.destroy(device); + + for (auto buffer : uniformBuffers) { + buffer.params.destroy(); + buffer.scene.destroy(); + buffer.skybox.destroy(); + } + for (auto fence : waitFences) { + vkDestroyFence(device, fence, nullptr); + } + for (auto semaphore : renderCompleteSemaphores) { + vkDestroySemaphore(device, semaphore, nullptr); + } + for (auto semaphore : presentCompleteSemaphores) { + vkDestroySemaphore(device, semaphore, nullptr); + } + + textures.environmentCube.destroy(); + textures.irradianceCube.destroy(); + textures.prefilteredCube.destroy(); + textures.lutBrdf.destroy(); + textures.empty.destroy(); + delete gui; + } + + void initWindow(int width, int height); + + static void framebufferResizeCallback(GLFWwindow* window, int width, int height); + void renderNode(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode); + void loadScene(std::string filename); + void loadEnvironment(std::string filename); + void buildCommandBuffers(); + void loadAssets(); + void setupNodeDescriptorSet(glTFModel::Node* node); + void setupDescriptors(); + void preparePipelines(); + // void tonemappingPipelin(); + void generateCubemaps(); + void generateBRDFLUT(); + void prepareUniformBuffers(); + void updateUniformBuffers(); + void updateShaderData(); + void windowResized(); + void prepare(); + void setupCamera(); + void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue); + + void writeImageToFile(std::string filePath); + void outputImageSequence(); + void imageSequenceToVideo(); + void removeImageSequence(); + //void outputScreenShot(); + //uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties); + virtual void render(); + virtual void updateUIOverlay(); + virtual void fileDropped(std::string filename); }; - struct UBOMatrices { - glm::mat4 projection; - glm::mat4 model; - glm::mat4 view; - glm::vec3 camPos; - } shaderDataScene, shaderDataSkybox; +} - - - - - glm::vec3 modelrot = glm::vec3(0.0f); - glm::vec3 modelPos = glm::vec3(0.0f); - - - enum PBRWorkflows { PBR_WORKFLOW_METALLIC_ROUGHNESS = 0, PBR_WORKFLOW_SPECULAR_GLOSINESS = 1 }; - - - std::map environments; - std::string selectedEnvironment = "papermill"; - std::map scenes; - std::string selectedScene = "DamagedHelmet"; - - int32_t debugViewInputs = 0; - int32_t debugViewEquation = 0; - - struct StagingBuffer { - VkBuffer buffer; - VkDeviceMemory memory; - } vertexStaging, indexStaging; - - - - - - struct DescriptorSets { - VkDescriptorSet scene; - VkDescriptorSet skybox; - VkDescriptorSet tonemappingDescriptorSet = VK_NULL_HANDLE; - }; - - - std::vector descriptorSets; - - std::vector commandBuffers; - std::vector uniformBuffers; - - std::vector waitFences; - std::vector renderCompleteSemaphores; - std::vector presentCompleteSemaphores; - - const uint32_t renderAhead = 2; - uint32_t frameIndex = 0; - - //VkImage swapChainImage; - - int32_t animationIndex = 0; - float animationTimer = 0.0f; - bool animate = true; - - bool displayBackground = true; - - struct LightSource { - glm::vec3 color = glm::vec3(1.0f); - glm::vec3 rotation = glm::vec3(75.0f, 40.0f, 0.0f); - } lightSource; - - - //cube map generation - - struct OffScreen - { - VkImage image; - VkImageView view; - VkDeviceMemory memory; - VkFramebuffer framebuffer; - } offscreen; - - struct IrradiancePushBlock - { - glm::mat4 mvp; - // Sampling deltas - float deltaPhi = (2.0f * float(M_PI)) / 180.0f; - float deltaTheta = (0.5f * float(M_PI)) / 64.0f; - } irradiancePushBlock; - - struct PrefilterPushBlock { - glm::mat4 mvp; - float roughness; - uint32_t numSamples = 32u; - } prefilterPushBlock; - - UI* gui; - - uint64_t savedFrameCounter = setter.settings.startFrameCount; - - bool framebufferResized = false; - - PlumageRender(); - ~PlumageRender() - { - // Clean up used Vulkan resources - // Note : Inherited destructor cleans up resources stored in base class - vkDestroyPipeline(device, pipelines.skybox, nullptr); - vkDestroyPipeline(device, pipelines.pbr, nullptr); - vkDestroyPipeline(device, pipelines.pbrAlphaBlend, nullptr); - - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.scene, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.material, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.node, nullptr); - - models.scene.destroy(device); - models.skybox.destroy(device); - - for (auto buffer : uniformBuffers) { - buffer.params.destroy(); - buffer.scene.destroy(); - buffer.skybox.destroy(); - } - for (auto fence : waitFences) { - vkDestroyFence(device, fence, nullptr); - } - for (auto semaphore : renderCompleteSemaphores) { - vkDestroySemaphore(device, semaphore, nullptr); - } - for (auto semaphore : presentCompleteSemaphores) { - vkDestroySemaphore(device, semaphore, nullptr); - } - - textures.environmentCube.destroy(); - textures.irradianceCube.destroy(); - textures.prefilteredCube.destroy(); - textures.lutBrdf.destroy(); - textures.empty.destroy(); - delete gui; - } - - - - void initWindow(int width, int height); - - static void framebufferResizeCallback(GLFWwindow* window, int width, int height); - void renderNode(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode); - void loadScene(std::string filename); - void loadEnvironment(std::string filename); - void buildCommandBuffers(); - void loadAssets(); - void setupNodeDescriptorSet(glTFModel::Node* node); - void setupDescriptors(); - void preparePipelines(); - // void tonemappingPipelin(); - void generateCubemaps(); - void generateBRDFLUT(); - void prepareUniformBuffers(); - void updateUniformBuffers(); - void updateShaderData(); - void windowResized(); - void prepare(); - void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue); - - void writeImageToFile(std::string filePath); - void outputImageSequence(); - void imageSequenceToVideo(); - void removeImageSequence(); - //void outputScreenShot(); - //uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties); - virtual void render(); - virtual void updateUIOverlay(); - virtual void fileDropped(std::string filename); -}; \ No newline at end of file diff --git a/src/render/renderIO.cpp b/src/render/renderIO.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/render/renderIO.h b/src/render/renderIO.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/src/render/renderIO.h @@ -0,0 +1 @@ +#pragma once diff --git a/src/render/renderSetter.cpp b/src/render/renderSetter.cpp index bab3b85..ad7b417 100644 --- a/src/render/renderSetter.cpp +++ b/src/render/renderSetter.cpp @@ -1,6 +1,6 @@ #include "renderSetter.h" - void VulkanBackend::Setter::getSettingFromCommandLine() + void PlumageRender::Setter::getSettingFromCommandLine() { // 暂定 char* numConvPtr; diff --git a/src/render/renderSetter.h b/src/render/renderSetter.h index 0eb2a47..295aeb7 100644 --- a/src/render/renderSetter.h +++ b/src/render/renderSetter.h @@ -10,7 +10,7 @@ #include "VulkanTools.h" -namespace VulkanBackend +namespace PlumageRender { class Setter { @@ -27,11 +27,13 @@ namespace VulkanBackend bool fullscreen = false; // 全屏开关 bool vsync = false; // 垂直同步开关 bool multiSampling = true; // 多重采样 + bool displayBackground = true; // IBL显示背景图 bool rotateModel = true; // 模型自旋转(暂时失效) bool headless = true; // 无头开关 bool outputPNGimage = false; // 输出图片序列格式为PNG(四通道) bool enableSaveToImageSequeue = false; // 图片序列开关(暂时弃用) - uint32_t outputFrameCount = 75; // 图片序列结束帧 + uint32_t MaxFrameInFlight = 2; // 最大并行渲染帧数(通常为2,此时CPU和GPU并行处理) + uint32_t endFrameIndex = 75; // 图片序列结束帧 bool enableIMGUI = false; // gui使用imgui uint32_t startFrameCount = 1; // 图片序列开始帧 uint32_t videoFrameRate = 25; // 视频帧率 diff --git a/src/render/renderUI.cpp b/src/render/renderUI.cpp new file mode 100644 index 0000000..73b1a54 --- /dev/null +++ b/src/render/renderUI.cpp @@ -0,0 +1,215 @@ +#include "renderUI.h" +#include + + +void PlumageRender::PlumageGUI::updateUIOverlay() +{ + ImGuiIO& io = ImGui::GetIO(); + + ImVec2 lastDisplaySize = io.DisplaySize; + io.DisplaySize = ImVec2((float)setter.settings.width, (float)setter.settings.height); + io.DeltaTime = frameTimer; + + io.MousePos = ImVec2(mousePos.x, mousePos.y); + io.MouseDown[0] = mouseButtons.left; + io.MouseDown[1] = mouseButtons.right; + + gui->pushConstBlock.scale = glm::vec2(2.0f / io.DisplaySize.x, 2.0f / io.DisplaySize.y); + gui->pushConstBlock.translate = glm::vec2(-1.0f); + + bool updateShaderParams = false; + bool updateCBs = false; + float scale = 1.0f; + bool boolTitleWindowShow = false; + ImGui::NewFrame(); + + ImGui::SetNextWindowPos(ImVec2(10000, 10000)); + //ImGui::SetNextWindowSize(ImVec2(200 * scale, (models.scene.animations.size() > 0 ? 440 : 360) * scale), ImGuiSetCond_Always); + ImGui::Begin("", nullptr, ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoBringToFrontOnFocus); + + ImGui::PushItemWidth(100.0f * scale); + + + + + if (gui->beginMainMenuBar()) { + if (gui->beginMenu(chineseUI.menuFile)) + { + if (gui->menuItem(chineseUI.menuOpenNewModel)) + { + std::wstring filename = L""; + wchar_t buffer[MAX_PATH]; + OPENFILENAMEW ofn; + ZeroMemory(&buffer, sizeof(buffer)); + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.lpstrFilter = L"glTF files\0*.gltf;*.glb\0"; + ofn.lpstrFile = buffer; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrTitle = L"Select a glTF/glb file to load"; + ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; + if (GetOpenFileNameW(&ofn)) { + filename = buffer; + + } + + if (!filename.empty()) { + vkDeviceWaitIdle(vulkanBasic.device); + std::wstring_convert> converter; + std::string stringFilename = converter.to_bytes(filename); + loadScene(stringFilename); + setupDescriptors(); + updateCBs = true; + signal.imageSequenceOutputComplete = false; + signal.imageSequenceToVideoComplete = false; + savedFrameCounter = 1; + } + } + gui->endMenu(); + } + if (gui->beginMenu(chineseUI.menuEnvironment)) + { + if (gui->beginMenu(chineseUI.menuEnvironmentConfig)) + { + if (gui->combo(chineseUI.environmentMap, selectedEnvironment, environments)) { + vkDeviceWaitIdle(device); + loadEnvironment(environments[selectedEnvironment]); + setupDescriptors(); + updateCBs = true; + } + if (gui->checkbox(chineseUI.environmentBackGround, &setter.settings.displayBackground)) { + updateShaderParams = true; + } + if (gui->slider("Exposure", &shaderData.exposure, 0.1f, 10.0f)) { + updateShaderParams = true; + } + if (gui->slider("Gamma", &shaderData.gamma, 0.1f, 4.0f)) { + updateShaderParams = true; + } + if (gui->slider("IBL", &shaderData.scaleIBLAmbient, 0.0f, 1.0f)) { + updateShaderParams = true; + } + gui->endMenu(); + } + gui->endMenu(); + } + if (gui->beginMenu("debug")) + { + if (gui->beginMenu(chineseUI.menuDebugInput)) + { + const std::vector debugNamesInputs = { + "none", "Base color", "Normal", "Occlusion", "Emissive", "Metallic", "Roughness" + }; + if (gui->combo(chineseUI.debugInput, &debugViewInputs, debugNamesInputs)) { + shaderData.debugViewInputs = static_cast(debugViewInputs); + updateShaderParams = true; + } + gui->endMenu(); + } + if (gui->beginMenu("PBR")) + { + const std::vector debugNamesEquation = { + "none", "Diff (l,n)", "F (l,h)", "G (l,v,h)", "D (h)", "Specular" + }; + if (gui->combo(chineseUI.debugPBREquation, &debugViewEquation, debugNamesEquation)) { + shaderData.debugViewEquation = static_cast(debugViewEquation); + updateShaderParams = true; + } + gui->endMenu(); + } + + if (gui->beginMenu(chineseUI.menuDebugFrameRate)) + { + gui->text("%.1d fps (%.2f ms)", lastFPS, (1000.0f / lastFPS)); + gui->endMenu(); + } + gui->endMenu(); + } + if (gui->beginMenu(chineseUI.menuAnimation)) + { + if (models.scene.animations.size() > 0) + { + if (gui->beginMenu(chineseUI.menuAnimationActivation)) + { + gui->checkbox(chineseUI.pauseAnimation, &animate); + gui->endMenu(); + } + if (gui->beginMenu(chineseUI.menuAnimationAnimationSequence)) + { + std::vector animationNames; + for (auto animation : models.scene.animations) { + animationNames.push_back(animation.name); + } + gui->combo(chineseUI.animationSeq, &animationIndex, animationNames); + gui->endMenu(); + } + } + else + { + gui->text(chineseUI.menuAnimationNoAnimation); + } + gui->endMenu(); + } + + gui->endMainMenuBar(); + } + + + ImGui::PopItemWidth(); + ImGui::End(); + ImGui::Render(); + + ImDrawData* imDrawData = ImGui::GetDrawData(); + + // Check if ui buffers need to be recreated + if (imDrawData) { + VkDeviceSize vertexBufferSize = imDrawData->TotalVtxCount * sizeof(ImDrawVert); + VkDeviceSize indexBufferSize = imDrawData->TotalIdxCount * sizeof(ImDrawIdx); + + bool updateBuffers = (gui->vertexBuffer.buffer == VK_NULL_HANDLE) || (gui->vertexBuffer.count != imDrawData->TotalVtxCount) || (gui->indexBuffer.buffer == VK_NULL_HANDLE) || (gui->indexBuffer.count != imDrawData->TotalIdxCount); + + if (updateBuffers) { + vkDeviceWaitIdle(device); + if (gui->vertexBuffer.buffer) { + gui->vertexBuffer.destroy(); + } + gui->vertexBuffer.create(vulkanDevice, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, vertexBufferSize); + gui->vertexBuffer.count = imDrawData->TotalVtxCount; + if (gui->indexBuffer.buffer) { + gui->indexBuffer.destroy(); + } + gui->indexBuffer.create(vulkanDevice, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, indexBufferSize); + gui->indexBuffer.count = imDrawData->TotalIdxCount; + } + + // Upload data + ImDrawVert* vtxDst = (ImDrawVert*)gui->vertexBuffer.mapped; + ImDrawIdx* idxDst = (ImDrawIdx*)gui->indexBuffer.mapped; + for (int n = 0; n < imDrawData->CmdListsCount; n++) { + const ImDrawList* cmd_list = imDrawData->CmdLists[n]; + memcpy(vtxDst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idxDst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtxDst += cmd_list->VtxBuffer.Size; + idxDst += cmd_list->IdxBuffer.Size; + } + + gui->vertexBuffer.flush(); + gui->indexBuffer.flush(); + + updateCBs = updateCBs || updateBuffers; + } + + if (lastDisplaySize.x != io.DisplaySize.x || lastDisplaySize.y != io.DisplaySize.y) { + updateCBs = true; + } + + if (updateCBs) { + vkDeviceWaitIdle(device); + buildCommandBuffers(); + vkDeviceWaitIdle(device); + } + + if (updateShaderParams) { + updateShaderData(); + } +} \ No newline at end of file diff --git a/src/render/renderUI.h b/src/render/renderUI.h new file mode 100644 index 0000000..61778fe --- /dev/null +++ b/src/render/renderUI.h @@ -0,0 +1,81 @@ +#pragma once + + +#include "ui.hpp" +#include "VulkanDevice.hpp" +#include "vulkanFoundation.h" +#include "renderSetter.h" + +namespace PlumageRender +{ + class PlumageGUI + { + public: + PlumageGUI(); + ~PlumageGUI(); + + UI* gui; + + void updateUIOverlay(); + + private: + + PlumageRender::Setter setter; + VulkanBackend::VulkanFoundation vulkanBasic; + + float frameTimer = 1.0f; + + struct GamePadState { + glm::vec2 axisLeft = glm::vec2(0.0f); + glm::vec2 axisRight = glm::vec2(0.0f); + } gamePadState; + + struct MouseButtons { + bool left = false; + bool right = false; + bool middle = false; + } mouseButtons; + + glm::vec2 mousePos; + + struct ChinesesUI + { + const char* model = "模型"; + + const char* environmentMap = "环境贴图"; + const char* environmentBackGround = "启用背景贴图"; + const char* debugInput = "输入"; + const char* debugPBREquation = "PBR计算参数"; + const char* animation = "动画"; + const char* pauseAnimation = "启用动画"; + const char* animationSeq = "动画序列"; + // menu item + const char* menuFile = "文件"; + const char* menuOpenNewModel = "新模型.."; + const char* menuEnvironment = "环境光照"; + const char* menuEnvironmentConfig = "设置"; + const char* menuAnimation = "动画"; + const char* menuDebugFrameRate = "fps"; + const char* menuDebugInput = "输入"; + const char* menuAnimationNoAnimation = "当前模型没有动画!"; + + const char* menuAnimationActivation = "开关"; + const char* menuAnimationAnimationSequence = "动画序列"; + + + }chineseUI; + + }; + + PlumageGUI::PlumageGUI() + { + + } + + PlumageGUI::~PlumageGUI() + { + } + +} + + diff --git a/src/render/vulkanFoundation.cpp b/src/render/vulkanFoundation.cpp index a399d89..e65c2a9 100644 --- a/src/render/vulkanFoundation.cpp +++ b/src/render/vulkanFoundation.cpp @@ -1,7 +1,7 @@ #include "vulkanFoundation.h" -void VulkanBackend::VulkanFondation::initVulkan() +void VulkanBackend::VulkanFoundation::initVulkan() { // 创建instance createInstance(); @@ -42,11 +42,6 @@ void VulkanBackend::VulkanFondation::initVulkan() // 创建命令缓冲池 createCommandPool(); - // 创建顶点缓存 - createVertexBuffer(); - - // 创建索引缓存区 - createIndexBuffer(); // 创建统一缓存区 createUniformBuffer(); @@ -57,6 +52,9 @@ void VulkanBackend::VulkanFondation::initVulkan() // 创建资源描述符集 createDescriptorSets(); + // 分配命令缓存区 + allocateCommandBuffers(); + // 创建命令缓存区 createCommandBuffer(); } @@ -64,7 +62,7 @@ void VulkanBackend::VulkanFondation::initVulkan() -void VulkanBackend::VulkanFondation::createInstance() +void VulkanBackend::VulkanFoundation::createInstance() { // check validation layers if (setter.settings.validation && !checkValidationLayerSupport()) @@ -115,7 +113,7 @@ void VulkanBackend::VulkanFondation::createInstance() } } -bool VulkanBackend::VulkanFondation::checkValidationLayerSupport() +bool VulkanBackend::VulkanFoundation::checkValidationLayerSupport() { uint32_t layerCount; vkEnumerateInstanceLayerProperties(&layerCount, nullptr); @@ -142,7 +140,7 @@ bool VulkanBackend::VulkanFondation::checkValidationLayerSupport() return true; } -std::vector VulkanBackend::VulkanFondation::getRequiredExtensions() +std::vector VulkanBackend::VulkanFoundation::getRequiredExtensions() { std::vector extensions; if (!setter.settings.headless) @@ -165,7 +163,7 @@ std::vector VulkanBackend::VulkanFondation::getRequiredExtensions() -void VulkanBackend::VulkanFondation::setupDebugMessager() +void VulkanBackend::VulkanFoundation::setupDebugMessager() { if (!setter.settings.validation) { @@ -182,7 +180,7 @@ void VulkanBackend::VulkanFondation::setupDebugMessager() } } -void VulkanBackend::VulkanFondation::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& debugCreateInfo) +void VulkanBackend::VulkanFoundation::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& debugCreateInfo) { debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; @@ -196,7 +194,7 @@ void VulkanBackend::VulkanFondation::populateDebugMessengerCreateInfo(VkDebugUti debugCreateInfo.pUserData = nullptr; } // debugCallback用于校验层 -VKAPI_ATTR VkBool32 VKAPI_CALL VulkanBackend::VulkanFondation::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) +VKAPI_ATTR VkBool32 VKAPI_CALL VulkanBackend::VulkanFoundation::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { { std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl; @@ -205,7 +203,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanBackend::VulkanFondation::debugCallback(VkD } } -VkResult VulkanBackend::VulkanFondation::CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) +VkResult VulkanBackend::VulkanFoundation::CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) { auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); @@ -221,7 +219,7 @@ VkResult VulkanBackend::VulkanFondation::CreateDebugUtilsMessengerEXT(VkInstance -void VulkanBackend::VulkanFondation::createSurface() +void VulkanBackend::VulkanFoundation::createSurface() { if (setter.settings.headless) @@ -237,7 +235,7 @@ void VulkanBackend::VulkanFondation::createSurface() -void VulkanBackend::VulkanFondation::pickPhysicalDevice() +void VulkanBackend::VulkanFoundation::pickPhysicalDevice() { uint32_t deviceCount = 0; @@ -269,7 +267,7 @@ void VulkanBackend::VulkanFondation::pickPhysicalDevice() } } -bool VulkanBackend::VulkanFondation::isDeviceSuitable(VkPhysicalDevice device) +bool VulkanBackend::VulkanFoundation::isDeviceSuitable(VkPhysicalDevice device) { if (setter.settings.headless) { @@ -289,7 +287,7 @@ bool VulkanBackend::VulkanFondation::isDeviceSuitable(VkPhysicalDevice device) } } -bool VulkanBackend::VulkanFondation::checkDeviceExtensionSupport(VkPhysicalDevice device) +bool VulkanBackend::VulkanFoundation::checkDeviceExtensionSupport(VkPhysicalDevice device) { uint32_t extensionCount; vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); @@ -308,7 +306,7 @@ bool VulkanBackend::VulkanFondation::checkDeviceExtensionSupport(VkPhysicalDevic } -VulkanBackend::VulkanFondation::QueueFamilyIndices VulkanBackend::VulkanFondation::findQueueFamilies(VkPhysicalDevice device) +VulkanBackend::VulkanFoundation::QueueFamilyIndices VulkanBackend::VulkanFoundation::findQueueFamilies(VkPhysicalDevice device) { QueueFamilyIndices indices; @@ -357,7 +355,7 @@ VulkanBackend::VulkanFondation::QueueFamilyIndices VulkanBackend::VulkanFondatio return indices; } -VulkanBackend::VulkanFondation::SwapChainSupportDetails VulkanBackend::VulkanFondation::querySwapChainSupport(VkPhysicalDevice device) +VulkanBackend::VulkanFoundation::SwapChainSupportDetails VulkanBackend::VulkanFoundation::querySwapChainSupport(VkPhysicalDevice device) { // 获得surface细节 SwapChainSupportDetails details; @@ -387,7 +385,7 @@ VulkanBackend::VulkanFondation::SwapChainSupportDetails VulkanBackend::VulkanFon -void VulkanBackend::VulkanFondation::createLogicalDevice() +void VulkanBackend::VulkanFoundation::createLogicalDevice() { QueueFamilyIndices indices = findQueueFamilies(physicalDevice); std::vector queueCreateInfos; @@ -467,7 +465,7 @@ void VulkanBackend::VulkanFondation::createLogicalDevice() -void VulkanBackend::VulkanFondation::createSwapChain() +void VulkanBackend::VulkanFoundation::createSwapChain() { if (setter.settings.headless) @@ -535,7 +533,7 @@ void VulkanBackend::VulkanFondation::createSwapChain() swapChainExtent = extent; } -VkSurfaceFormatKHR VulkanBackend::VulkanFondation::chooseSwapSurfaceFormat(const std::vector& availableFormats) +VkSurfaceFormatKHR VulkanBackend::VulkanFoundation::chooseSwapSurfaceFormat(const std::vector& availableFormats) { for (const auto& availableFormat : availableFormats) { if (availableFormat.format == VK_FORMAT_B8G8R8_SRGB && availableFormat.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR) @@ -547,7 +545,7 @@ VkSurfaceFormatKHR VulkanBackend::VulkanFondation::chooseSwapSurfaceFormat(const return availableFormats[0]; } -VkPresentModeKHR VulkanBackend::VulkanFondation::chooseSwapPresentMode(const std::vector& availablePresentModes) +VkPresentModeKHR VulkanBackend::VulkanFoundation::chooseSwapPresentMode(const std::vector& availablePresentModes) { // Get available present modes uint32_t presentModeCount; @@ -580,7 +578,7 @@ VkPresentModeKHR VulkanBackend::VulkanFondation::chooseSwapPresentMode(const std } } -VkExtent2D VulkanBackend::VulkanFondation::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) +VkExtent2D VulkanBackend::VulkanFoundation::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) { if (capabilities.currentExtent.width != std::numeric_limits::max()) { @@ -604,8 +602,8 @@ VkExtent2D VulkanBackend::VulkanFondation::chooseSwapExtent(const VkSurfaceCapab } -// toDo 重写 -void VulkanBackend::VulkanFondation::createImageView() + +void VulkanBackend::VulkanFoundation::createImageView() { VkFormat colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM; VkFormat depthFormat = findDepthFormat(); @@ -833,7 +831,7 @@ void VulkanBackend::VulkanFondation::createImageView() -void VulkanBackend::VulkanFondation::createRenderPass() +void VulkanBackend::VulkanFoundation::createRenderPass() { VkFormat colorAttachmentFormat; VkFormat depthAttachmentFormat = findDepthFormat(); @@ -1013,7 +1011,7 @@ void VulkanBackend::VulkanFondation::createRenderPass() } } -VkFormat VulkanBackend::VulkanFondation::findDepthFormat() +VkFormat VulkanBackend::VulkanFoundation::findDepthFormat() { return findSupportedFormat( { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, @@ -1022,7 +1020,7 @@ VkFormat VulkanBackend::VulkanFondation::findDepthFormat() ); } -VkFormat VulkanBackend::VulkanFondation::findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) +VkFormat VulkanBackend::VulkanFoundation::findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) { for (VkFormat format : candidates) { @@ -1041,14 +1039,14 @@ VkFormat VulkanBackend::VulkanFondation::findSupportedFormat(const std::vector setLayoutBindings = { @@ -1091,7 +1089,7 @@ void VulkanBackend::VulkanFondation::createDescriptorSetLayout() -void VulkanBackend::VulkanFondation::createPipelineCache() +void VulkanBackend::VulkanFoundation::createPipelineCache() { VkPipelineCacheCreateInfo pipelineCacheCreateInfo{}; pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; @@ -1100,7 +1098,7 @@ void VulkanBackend::VulkanFondation::createPipelineCache() -void VulkanBackend::VulkanFondation::createGraphicPipeline() +void VulkanBackend::VulkanFoundation::createGraphicPipeline() { VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; @@ -1248,43 +1246,50 @@ void VulkanBackend::VulkanFondation::createGraphicPipeline() -void VulkanBackend::VulkanFondation::createFramebuffer() +void VulkanBackend::VulkanFoundation::createFramebuffer() { if (setter.settings.headless) { if (setter.settings.multiSampling) { - VkImageView attachments[4]; - attachments[0] = multisampleTarget.colorAttachment.view; - attachments[1] = multisampleTarget.depthAttachment.view; - attachments[2] = depthAttachment.view; - attachments[3] = colorAttachment.view; + for (int i = 0; i < frameRange; i++) + { + VkImageView attachments[4]; + attachments[0] = multisampleTarget.colorAttachment.view; + attachments[1] = multisampleTarget.depthAttachment.view; + attachments[2] = depthAttachment.view; + attachments[3] = colorAttachment.view; - VkFramebufferCreateInfo framebufferCreateInfo = vks::initializers::framebufferCreateInfo(); - framebufferCreateInfo.renderPass = renderPass; - framebufferCreateInfo.attachmentCount = 4; - framebufferCreateInfo.pAttachments = attachments; - framebufferCreateInfo.width = setter.settings.width; - framebufferCreateInfo.height = setter.settings.height; - framebufferCreateInfo.layers = 1; - - VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffer)); + VkFramebufferCreateInfo framebufferCreateInfo = vks::initializers::framebufferCreateInfo(); + framebufferCreateInfo.renderPass = renderPass; + framebufferCreateInfo.attachmentCount = 4; + framebufferCreateInfo.pAttachments = attachments; + framebufferCreateInfo.width = setter.settings.width; + framebufferCreateInfo.height = setter.settings.height; + framebufferCreateInfo.layers = 1; + + VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i])); + } } else { - VkImageView attachments[2]; - attachments[0] = colorAttachment.view; - attachments[1] = depthAttachment.view; + for (int i = 0; i < frameRange; i++) + { + VkImageView attachments[2]; + attachments[0] = colorAttachment.view; + attachments[1] = depthAttachment.view; - VkFramebufferCreateInfo framebufferCreateInfo = vks::initializers::framebufferCreateInfo(); - framebufferCreateInfo.renderPass = renderPass; - framebufferCreateInfo.attachmentCount = 2; - framebufferCreateInfo.pAttachments = attachments; - framebufferCreateInfo.width = setter.settings.width; - framebufferCreateInfo.height = setter.settings.height; - framebufferCreateInfo.layers = 1; - VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffer)); + VkFramebufferCreateInfo framebufferCreateInfo = vks::initializers::framebufferCreateInfo(); + framebufferCreateInfo.renderPass = renderPass; + framebufferCreateInfo.attachmentCount = 2; + framebufferCreateInfo.pAttachments = attachments; + framebufferCreateInfo.width = setter.settings.width; + framebufferCreateInfo.height = setter.settings.height; + framebufferCreateInfo.layers = 1; + VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i])); + + } } @@ -1292,11 +1297,10 @@ void VulkanBackend::VulkanFondation::createFramebuffer() else { createSwapChainFramebuffer(); - } } -void VulkanBackend::VulkanFondation::createSwapChainFramebuffer() +void VulkanBackend::VulkanFoundation::createSwapChainFramebuffer() { uint32_t attachmentCount; VkImageView attachments[attachmentCount]; @@ -1326,7 +1330,7 @@ void VulkanBackend::VulkanFondation::createSwapChainFramebuffer() // Create frame buffers for every swap chain image - swapChainFramebuffers.resize(swapChainImageViews.size()); + framebuffers.resize(swapChainImageViews.size()); for (uint32_t i = 0; i < swapChainImageViews.size(); i++) { if (setter.settings.multiSampling) { attachments[3] = swapChainImageViews[i]; @@ -1334,13 +1338,13 @@ void VulkanBackend::VulkanFondation::createSwapChainFramebuffer() else { attachments[0] = swapChainImageViews[i]; } - VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &swapChainFramebuffers[i])); + VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &framebuffers[i])); } } -void VulkanBackend::VulkanFondation::createCommandPool() +void VulkanBackend::VulkanFoundation::createCommandPool() { QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice); @@ -1355,39 +1359,59 @@ void VulkanBackend::VulkanFondation::createCommandPool() } } -void VulkanBackend::VulkanFondation::createVertexBuffer() + + + + +void VulkanBackend::VulkanFoundation::createUniformBuffer() { - VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VkBuffer stagingBuffer; - VkDeviceMemory stagingBufferMemory; - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); - - void* data; - vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data); - memcpy(data, vertices.data(), (size_t)bufferSize); - vkUnmapMemory(device, stagingBufferMemory); - - // host visible buffer as temp buffer - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); - - // move the vertex data to the device local buffer - copyBuffer(stagingBuffer, vertexBuffer, bufferSize); - - vkDestroyBuffer(device, stagingBuffer, nullptr); - vkFreeMemory(device, stagingBufferMemory, nullptr); + if (setter.settings.headless) + { + uniformBuffers.resize(frameRange); + } + else + { + uniformBuffers.resize(swapChainImages.size()); + } + + for (auto& uniformBuffer : uniformBuffers) { + uniformBuffer.scene.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderDataScene)); + uniformBuffer.skybox.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderDataSkybox)); + uniformBuffer.params.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderData)); + } + updateUniformBuffers(); } -void VulkanBackend::VulkanFondation::createIndexBuffer() +void VulkanBackend::VulkanFoundation::updateUniformBuffers() { + // Scene + shaderDataScene.projection = camera.matrices.perspective; + shaderDataScene.view = camera.matrices.view; + // Center and scale model + float scale = (1.0f / std::max(models.scene.aabb[0][0], std::max(models.scene.aabb[1][1], models.scene.aabb[2][2]))) * 0.5f; + glm::vec3 translate = -glm::vec3(models.scene.aabb[3][0], models.scene.aabb[3][1], models.scene.aabb[3][2]); + translate += -0.5f * glm::vec3(models.scene.aabb[0][0], models.scene.aabb[1][1], models.scene.aabb[2][2]); + + shaderDataScene.model = glm::mat4(1.0f); + shaderDataScene.model[0][0] = scale; + shaderDataScene.model[1][1] = scale; + shaderDataScene.model[2][2] = scale; + shaderDataScene.model = glm::translate(shaderDataScene.model, translate); + + shaderDataScene.camPos = glm::vec3( + -camera.position.z * sin(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)), + -camera.position.z * sin(glm::radians(camera.rotation.x)), + camera.position.z * cos(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)) + ); + + // Skybox + shaderDataSkybox.projection = camera.matrices.perspective; + shaderDataSkybox.view = camera.matrices.view; + shaderDataSkybox.model = glm::mat4(glm::mat3(camera.matrices.view)); } -void VulkanBackend::VulkanFondation::createUniformBuffer() -{ - -} - -void VulkanBackend::VulkanFondation::createDescriptorPool() +void VulkanBackend::VulkanFoundation::createDescriptorPool() { /* Descriptor Pool @@ -1424,14 +1448,430 @@ void VulkanBackend::VulkanFondation::createDescriptorPool() VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool)); } -void VulkanBackend::VulkanFondation::createDescriptorSets() +void VulkanBackend::VulkanFoundation::createDescriptorSets() { - + if (setter.settings.headless) + { + descriptorSets.resize(frameRange); + } + else + { + descriptorSets.resize(swapChainImages.size()); + } + createSceneDescriptorSets(); + createMaterialDescriptorSets(); + createModelNodeDescriptorSets(); + createSkyboxDescriptorSets(); + } -void VulkanBackend::VulkanFondation::createCommandBuffer() +// Scene (matrices and environment maps) +void VulkanBackend::VulkanFoundation::createSceneDescriptorSets() { + + 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 = &pbrMaterial.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 = &pbrMaterial.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 = &pbrMaterial.textures.lutBrdf.descriptor; + + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + + } +} + +// Per-Material descriptor sets +void VulkanBackend::VulkanFoundation::createMaterialDescriptorSets() +{ + + 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 = + { + pbrMaterial.textures.empty.descriptor, + pbrMaterial.textures.empty.descriptor, + material.normalTexture ? material.normalTexture->descriptor : pbrMaterial.textures.empty.descriptor, + material.occlusionTexture ? material.occlusionTexture->descriptor : pbrMaterial.textures.empty.descriptor, + material.emissiveTexture ? material.emissiveTexture->descriptor : pbrMaterial.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) +void VulkanBackend::VulkanFoundation::createModelNodeDescriptorSets() +{ + + // Per-Node descriptor set + for (auto& node : models.scene.nodes) + { + setupglTFNodeDescriptorSet(node); + } + +} + + +// attention: gltf-spec +void VulkanBackend::VulkanFoundation::setupglTFNodeDescriptorSet(glTFModel::Node* node) +{ + 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; + + vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); + } + for (auto& child : node->children) { + setupglTFNodeDescriptorSet(child); + } +} + +void VulkanBackend::VulkanFoundation::createSkyboxDescriptorSets() +{ + // 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 = &pbrMaterial.textures.prefilteredCube.descriptor; + + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); + } +} + + + +void VulkanBackend::VulkanFoundation::allocateCommandBuffers() +{ + // resize + if (setter.settings.headless) + { + commandbuffers.resize(frameRange); + } + else + { + commandbuffers.resize(swapChainImages.size()); + } + // allocate + VkCommandBufferAllocateInfo cmdBufAllocateInfo{}; + cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdBufAllocateInfo.commandPool = commandPool; + cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + cmdBufAllocateInfo.commandBufferCount = static_cast(commandbuffers.size()); + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commandbuffers.data())); +} + +void VulkanBackend::VulkanFoundation::createCommandBuffer() +{ + + VkCommandBufferBeginInfo cmdBufferBeginInfo{}; + cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + VkClearValue clearValues[3]; + if (setter.settings.multiSampling) { + clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } }; + clearValues[1].color = { { 0.0f, 0.0f, 0.0f, 1.0f } }; + clearValues[2].depthStencil = { 1.0f, 0 }; + } + else { + clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } }; + clearValues[1].depthStencil = { 1.0f, 0 }; + } + + VkRenderPassBeginInfo renderPassBeginInfo{}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassBeginInfo.renderPass = renderPass; + renderPassBeginInfo.renderArea.offset.x = 0; + renderPassBeginInfo.renderArea.offset.y = 0; + renderPassBeginInfo.renderArea.extent.width = setter.settings.width; + renderPassBeginInfo.renderArea.extent.height = setter.settings.height; + renderPassBeginInfo.clearValueCount = setter.settings.multiSampling ? 3 : 2; + renderPassBeginInfo.pClearValues = clearValues; + + for (uint32_t i = 0; i < commandbuffers.size(); ++i) + { + renderPassBeginInfo.framebuffer = framebuffers[i]; + + VkCommandBuffer currentCB = commandbuffers[i]; + + VK_CHECK_RESULT(vkBeginCommandBuffer(currentCB, &cmdBufferBeginInfo)); + vkCmdBeginRenderPass(currentCB, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport{}; + viewport.width = (float)setter.settings.width; + viewport.height = (float)setter.settings.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(currentCB, 0, 1, &viewport); + + VkRect2D scissor{}; + scissor.extent = { setter.settings.width, setter.settings.height }; + vkCmdSetScissor(currentCB, 0, 1, &scissor); + + VkDeviceSize offsets[1] = { 0 }; + + if (setter.settings.displayBackground) { + vkCmdBindDescriptorSets(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i].skybox, 0, nullptr); + vkCmdBindPipeline(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skybox); + models.skybox.draw(currentCB); + } + + glTFModel::Model& model = models.scene; + + vkCmdBindVertexBuffers(currentCB, 0, 1, &model.vertices.buffer, offsets); + if (model.indices.buffer != VK_NULL_HANDLE) { + vkCmdBindIndexBuffer(currentCB, model.indices.buffer, 0, VK_INDEX_TYPE_UINT32); + } + + boundPipeline = VK_NULL_HANDLE; + + // Opaque primitives first + for (auto node : model.nodes) { + createglTFNodeCommandBuffer(node, i, glTFModel::Material::ALPHAMODE_OPAQUE); + } + // Alpha masked primitives + for (auto node : model.nodes) { + createglTFNodeCommandBuffer(node, i, glTFModel::Material::ALPHAMODE_MASK); + } + // Transparent primitives + // TODO: Correct depth sorting + for (auto node : model.nodes) { + createglTFNodeCommandBuffer(node, i, glTFModel::Material::ALPHAMODE_BLEND); + } + + // User interface + if (!setter.settings.headless) + { + gui->draw(currentCB); + } + + vkCmdEndRenderPass(currentCB); + VK_CHECK_RESULT(vkEndCommandBuffer(currentCB)); + } + +} + +void VulkanBackend::VulkanFoundation::createglTFNodeCommandBuffer(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode) +{ + if (node->mesh) { + // Render mesh primitives + for (glTFModel::Primitive* primitive : node->mesh->primitives) { + if (primitive->material.alphaMode == alphaMode) { + VkPipeline pipeline = VK_NULL_HANDLE; + switch (alphaMode) { + case glTFModel::Material::ALPHAMODE_OPAQUE: + case glTFModel::Material::ALPHAMODE_MASK: + pipeline = primitive->material.doubleSided ? pipelines.pbrDoubleSided : pipelines.pbr; + break; + case glTFModel::Material::ALPHAMODE_BLEND: + pipeline = pipelines.pbrAlphaBlend; + break; + } + + if (pipeline != boundPipeline) { + vkCmdBindPipeline(commandbuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + boundPipeline = pipeline; + } + + const std::vector descriptorsets = { + descriptorSets[cbIndex].scene, + primitive->material.descriptorSet, + node->mesh->uniformBuffer.descriptorSet, + }; + vkCmdBindDescriptorSets(commandbuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast(descriptorsets.size()), descriptorsets.data(), 0, NULL); + + // Pass material parameters as push constants + PBR::Material::PushConstBlockMaterial pushConstBlockMaterial{}; + pushConstBlockMaterial.emissiveFactor = primitive->material.emissiveFactor; + // To save push constant space, availabilty and texture coordiante set are combined + // -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set + pushConstBlockMaterial.colorTextureSet = primitive->material.baseColorTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1; + pushConstBlockMaterial.normalTextureSet = primitive->material.normalTexture != nullptr ? primitive->material.texCoordSets.normal : -1; + pushConstBlockMaterial.occlusionTextureSet = primitive->material.occlusionTexture != nullptr ? primitive->material.texCoordSets.occlusion : -1; + pushConstBlockMaterial.emissiveTextureSet = primitive->material.emissiveTexture != nullptr ? primitive->material.texCoordSets.emissive : -1; + pushConstBlockMaterial.alphaMask = static_cast(primitive->material.alphaMode == glTFModel::Material::ALPHAMODE_MASK); + pushConstBlockMaterial.alphaMaskCutoff = primitive->material.alphaCutoff; + + // TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present + + if (primitive->material.pbrWorkflows.metallicRoughness) { + // Metallic roughness workflow + pushConstBlockMaterial.workflow = static_cast(PBR::Material::PBRWorkflows::PBR_WORKFLOW_METALLIC_ROUGHNESS); + pushConstBlockMaterial.baseColorFactor = primitive->material.baseColorFactor; + pushConstBlockMaterial.metallicFactor = primitive->material.metallicFactor; + pushConstBlockMaterial.roughnessFactor = primitive->material.roughnessFactor; + pushConstBlockMaterial.PhysicalDescriptorTextureSet = primitive->material.metallicRoughnessTexture != nullptr ? primitive->material.texCoordSets.metallicRoughness : -1; + pushConstBlockMaterial.colorTextureSet = primitive->material.baseColorTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1; + } + + if (primitive->material.pbrWorkflows.specularGlossiness) { + // Specular glossiness workflow + pushConstBlockMaterial.workflow = static_cast(PBR::Material::PBRWorkflows::PBR_WORKFLOW_SPECULAR_GLOSINESS); + pushConstBlockMaterial.PhysicalDescriptorTextureSet = primitive->material.extension.specularGlossinessTexture != nullptr ? primitive->material.texCoordSets.specularGlossiness : -1; + pushConstBlockMaterial.colorTextureSet = primitive->material.extension.diffuseTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1; + pushConstBlockMaterial.diffuseFactor = primitive->material.extension.diffuseFactor; + pushConstBlockMaterial.specularFactor = glm::vec4(primitive->material.extension.specularFactor, 1.0f); + } + + vkCmdPushConstants(commandbuffers[cbIndex], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PBR::Material::PushConstBlockMaterial), &pushConstBlockMaterial); + + if (primitive->hasIndices) { + vkCmdDrawIndexed(commandbuffers[cbIndex], primitive->indexCount, 1, primitive->firstIndex, 0, 0); + } + else { + vkCmdDraw(commandbuffers[cbIndex], primitive->vertexCount, 1, 0, 0); + } + } + } + + }; + for (auto child : node->children) { + createglTFNodeCommandBuffer(child, cbIndex, alphaMode); + } +} + +void VulkanBackend::VulkanFoundation::createFenceAndSemaphore() +{ + waitFences.resize(setter.settings.MaxFrameInFlight); + presentCompleteSemaphores.resize(setter.settings.MaxFrameInFlight); + renderCompleteSemaphores.resize(setter.settings.MaxFrameInFlight); + + // Command buffer execution fences + for (auto& waitFence : waitFences) { + VkFenceCreateInfo fenceCI{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT }; + VK_CHECK_RESULT(vkCreateFence(device, &fenceCI, nullptr, &waitFence)); + } + if (!setter.settings.headless) + { + for (auto& semaphore : presentCompleteSemaphores) { + VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 }; + VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore)); + } + } + // Queue ordering semaphores + + for (auto& semaphore : renderCompleteSemaphores) { + VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 }; + VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore)); + } } diff --git a/src/render/vulkanFoundation.h b/src/render/vulkanFoundation.h index 28d6014..7bafbfb 100644 --- a/src/render/vulkanFoundation.h +++ b/src/render/vulkanFoundation.h @@ -13,14 +13,16 @@ #include "VulkanUtils.hpp" #include "PBR.h" #include "VulkanDevice.hpp" +#include +#include "renderUI.h" namespace VulkanBackend { - class VulkanFondation + class VulkanFoundation { public: - VulkanFondation(); - ~VulkanFondation(); + VulkanFoundation(); + ~VulkanFoundation(); const std::vector validationLayers = { "VK_LAYER_KHRONOS_validation" @@ -34,12 +36,15 @@ namespace VulkanBackend const int MAX_FRAME_IN_FLIGHT = 2; + const int frameRange = setter.settings.endFrameIndex - setter.settings.startFrameCount; + void initVulkan(); + VkDevice device; private: - VulkanBackend::Setter setter; + PlumageRender::Setter setter; PBR::Material pbrMaterial; vks::VulkanDevice* vulkanDevice; @@ -70,7 +75,7 @@ namespace VulkanBackend }; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VkDevice device; + GLFWwindow* window; VkSurfaceKHR surface; @@ -96,8 +101,12 @@ namespace VulkanBackend VkDescriptorPool descriptorPool; - VkFramebuffer framebuffer; - std::vector swapChainFramebuffers; + Camera camera; + + + std::vector framebuffers; + + std::vector commandbuffers; struct FrameBufferAttachment { @@ -123,6 +132,14 @@ namespace VulkanBackend VkDescriptorSetLayout node; } descriptorSetLayouts; + struct DescriptorSets { + VkDescriptorSet scene; + VkDescriptorSet skybox; + VkDescriptorSet tonemappingDescriptorSet = VK_NULL_HANDLE; + }; + + std::vector descriptorSets; + struct Pipelines { VkPipeline skybox; VkPipeline pbr; @@ -147,6 +164,35 @@ namespace VulkanBackend VkPipelineCache pipelineCache; + struct UniformBufferSet { + Buffer scene; + Buffer skybox; + Buffer params; + }; + + struct UBOMatrices { + glm::mat4 projection; + glm::mat4 model; + glm::mat4 view; + glm::vec3 camPos; + } shaderDataScene, shaderDataSkybox; + + struct ShaderData { + glm::vec4 lightDir; + float exposure = 4.5f; + float gamma = 2.2f; + float prefilteredCubeMipLevels; + float scaleIBLAmbient = 1.0f; + float debugViewInputs = 0; + float debugViewEquation = 0; + } shaderData; + + std::vector uniformBuffers; + + std::vector waitFences; + std::vector renderCompleteSemaphores; + std::vector presentCompleteSemaphores; + // 句柄创建,检查校验层支持和获取需要的扩展 void createInstance(); bool checkValidationLayerSupport(); @@ -169,8 +215,8 @@ namespace VulkanBackend void pickPhysicalDevice(); bool isDeviceSuitable(VkPhysicalDevice device); bool checkDeviceExtensionSupport(VkPhysicalDevice device); - VulkanBackend::VulkanFondation::QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); - VulkanBackend::VulkanFondation::SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device); + VulkanBackend::VulkanFoundation::QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); + VulkanBackend::VulkanFoundation::SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device); // 创建程序使用的逻辑设备 void createLogicalDevice(); @@ -206,31 +252,39 @@ namespace VulkanBackend // 创建命令缓冲池 void createCommandPool(); - // 创建顶点缓存区 - void createVertexBuffer(); - - // 创建索引缓存区 - void createIndexBuffer(); // 创建统一缓冲区 void createUniformBuffer(); + void updateUniformBuffers(); + // 创建描述符池 void createDescriptorPool(); // 创建描述符集合 void createDescriptorSets(); + void createSceneDescriptorSets(); + void createMaterialDescriptorSets(); + void createModelNodeDescriptorSets(); + void setupglTFNodeDescriptorSet(glTFModel::Node* node); + void createSkyboxDescriptorSets(); + // 创建命令缓存区 + void allocateCommandBuffers(); void createCommandBuffer(); + void createglTFNodeCommandBuffer(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode); + + // 创建栅栏和信号量,用于多帧并行的同步 + void createFenceAndSemaphore(); }; - VulkanFondation::VulkanFondation() + VulkanFoundation::VulkanFoundation() { } - VulkanFondation::~VulkanFondation() + VulkanFoundation::~VulkanFoundation() { }