剥离UI和IO部分,重构完成到commandbuffer
parent
e9eb47dfda
commit
ee81b8e56d
|
@ -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)
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
@ -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()
|
||||
{
|
||||
|
||||
|
||||
|
@ -364,99 +257,8 @@ void PlumageRender::setupDescriptors()
|
|||
{
|
||||
|
||||
|
||||
// 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();
|
||||
|
||||
|
@ -1261,7 +1063,8 @@ void PlumageRender::generateBRDFLUT()
|
|||
}
|
||||
|
||||
// Prepare and initialize uniform buffer containing shader uniforms
|
||||
void PlumageRender::prepareUniformBuffers()
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
struct Signal
|
||||
{
|
||||
bool imageSequenceOutputComplete = false;
|
||||
bool imageSequenceToVideoComplete = false;
|
||||
|
||||
}signal;
|
||||
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;
|
||||
|
||||
|
||||
|
||||
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 = "模型";
|
||||
int32_t debugViewInputs = 0;
|
||||
int32_t debugViewEquation = 0;
|
||||
|
||||
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 = "当前模型没有动画!";
|
||||
struct StagingBuffer {
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory memory;
|
||||
} vertexStaging, indexStaging;
|
||||
|
||||
const char* menuAnimationActivation = "开关";
|
||||
const char* menuAnimationAnimationSequence = "动画序列";
|
||||
std::vector<VkCommandBuffer> commandBuffers;
|
||||
|
||||
uint32_t frameIndex = 0;
|
||||
|
||||
}chineseUI;
|
||||
struct UniformBufferSet {
|
||||
Buffer scene;
|
||||
Buffer skybox;
|
||||
Buffer params;
|
||||
//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);
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
#pragma once
|
|
@ -1,6 +1,6 @@
|
|||
#include "renderSetter.h"
|
||||
|
||||
void VulkanBackend::Setter::getSettingFromCommandLine()
|
||||
void PlumageRender::Setter::getSettingFromCommandLine()
|
||||
{
|
||||
// 暂定
|
||||
char* numConvPtr;
|
||||
|
|
|
@ -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; // 视频帧率
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
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));
|
||||
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);
|
||||
if (setter.settings.headless)
|
||||
{
|
||||
uniformBuffers.resize(frameRange);
|
||||
}
|
||||
else
|
||||
{
|
||||
uniformBuffers.resize(swapChainImages.size());
|
||||
}
|
||||
|
||||
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);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue