剥离UI和IO部分,重构完成到commandbuffer

ink-soul 2024-04-07 17:29:35 +08:00
parent e9eb47dfda
commit ee81b8e56d
15 changed files with 1164 additions and 884 deletions

View File

@ -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)

View File

@ -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})

View File

@ -1,5 +1,6 @@
#pragma once
#include "glm/glm.hpp"
#include <VulkanTexture.hpp>
@ -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:

View File

@ -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;

View File

@ -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);

View File

@ -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<PlumageRender*>(glfwGetWindowUserPointer(window));
auto app = reinterpret_cast<renderMain*>(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<VkDescriptorSet> descriptorsets = {
descriptorSets[cbIndex].scene,
primitive->material.descriptorSet,
node->mesh->uniformBuffer.descriptorSet,
};
vkCmdBindDescriptorSets(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(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<float>(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<float>(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<float>(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<VkDescriptorImageInfo> 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<VkWriteDescriptorSet, 5> 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<uint32_t>(i);
writeDescriptorSets[i].pImageInfo = &imageDescriptors[i];
}
vkUpdateDescriptorSets(device, static_cast<uint32_t>(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<VkWriteDescriptorSet, 3> 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<uint32_t>(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<uint32_t>(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<std::codecvt_utf8<wchar_t>> 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<std::string> debugNamesInputs = {
"none", "Base color", "Normal", "Occlusion", "Emissive", "Metallic", "Roughness"
};
if (gui->combo(chineseUI.debugInput, &debugViewInputs, debugNamesInputs)) {
shaderData.debugViewInputs = static_cast<float>(debugViewInputs);
updateShaderParams = true;
}
gui->endMenu();
}
if (gui->beginMenu("PBR"))
{
const std::vector<std::string> 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<float>(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<std::string> 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;
}

View File

@ -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<std::string, std::string> environments;
std::string selectedEnvironment = "papermill";
std::map<std::string, std::string> 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<VkCommandBuffer> 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<std::string, std::string> environments;
std::string selectedEnvironment = "papermill";
std::map<std::string, std::string> 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> descriptorSets;
std::vector<VkCommandBuffer> commandBuffers;
std::vector<UniformBufferSet> uniformBuffers;
std::vector<VkFence> waitFences;
std::vector<VkSemaphore> renderCompleteSemaphores;
std::vector<VkSemaphore> 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);
};

View File

View File

@ -0,0 +1 @@
#pragma once

View File

@ -1,6 +1,6 @@
#include "renderSetter.h"
void VulkanBackend::Setter::getSettingFromCommandLine()
void PlumageRender::Setter::getSettingFromCommandLine()
{
// 暂定
char* numConvPtr;

View File

@ -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; // 视频帧率

View File

@ -0,0 +1,215 @@
#include "renderUI.h"
#include <codecvt>
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<std::codecvt_utf8<wchar_t>> 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<std::string> debugNamesInputs = {
"none", "Base color", "Normal", "Occlusion", "Emissive", "Metallic", "Roughness"
};
if (gui->combo(chineseUI.debugInput, &debugViewInputs, debugNamesInputs)) {
shaderData.debugViewInputs = static_cast<float>(debugViewInputs);
updateShaderParams = true;
}
gui->endMenu();
}
if (gui->beginMenu("PBR"))
{
const std::vector<std::string> 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<float>(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<std::string> 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();
}
}

View File

@ -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()
{
}
}

View File

@ -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<const char*> VulkanBackend::VulkanFondation::getRequiredExtensions()
std::vector<const char*> VulkanBackend::VulkanFoundation::getRequiredExtensions()
{
std::vector<const char*> extensions;
if (!setter.settings.headless)
@ -165,7 +163,7 @@ std::vector<const char*> 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<VkDeviceQueueCreateInfo> 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<VkSurfaceFormatKHR>& availableFormats)
VkSurfaceFormatKHR VulkanBackend::VulkanFoundation::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& 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<VkPresentModeKHR>& availablePresentModes)
VkPresentModeKHR VulkanBackend::VulkanFoundation::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& 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<uint32_t>::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<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
VkFormat VulkanBackend::VulkanFoundation::findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
{
for (VkFormat format : candidates)
{
@ -1041,14 +1039,14 @@ VkFormat VulkanBackend::VulkanFondation::findSupportedFormat(const std::vector<V
throw std::runtime_error("failed to find supported format");
}
bool VulkanBackend::VulkanFondation::hasStencilComponent(VkFormat format)
bool VulkanBackend::VulkanFoundation::hasStencilComponent(VkFormat format)
{
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
}
void VulkanBackend::VulkanFondation::createDescriptorSetLayout()
void VulkanBackend::VulkanFoundation::createDescriptorSetLayout()
{
// scene场景的资源描述符
std::vector<VkDescriptorSetLayoutBinding> 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<VkWriteDescriptorSet, 5> 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<uint32_t>(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<VkDescriptorImageInfo> 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<VkWriteDescriptorSet, 5> 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<uint32_t>(i);
writeDescriptorSets[i].pImageInfo = &imageDescriptors[i];
}
vkUpdateDescriptorSets(device, static_cast<uint32_t>(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<VkWriteDescriptorSet, 3> 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<uint32_t>(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<uint32_t>(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<VkDescriptorSet> descriptorsets = {
descriptorSets[cbIndex].scene,
primitive->material.descriptorSet,
node->mesh->uniformBuffer.descriptorSet,
};
vkCmdBindDescriptorSets(commandbuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(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<float>(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<float>(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<float>(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));
}
}

View File

@ -13,14 +13,16 @@
#include "VulkanUtils.hpp"
#include "PBR.h"
#include "VulkanDevice.hpp"
#include <camera.hpp>
#include "renderUI.h"
namespace VulkanBackend
{
class VulkanFondation
class VulkanFoundation
{
public:
VulkanFondation();
~VulkanFondation();
VulkanFoundation();
~VulkanFoundation();
const std::vector<const char*> 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<VkFramebuffer> swapChainFramebuffers;
Camera camera;
std::vector<VkFramebuffer> framebuffers;
std::vector<VkCommandBuffer> 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> 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<UniformBufferSet> uniformBuffers;
std::vector<VkFence> waitFences;
std::vector<VkSemaphore> renderCompleteSemaphores;
std::vector<VkSemaphore> 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()
{
}