plumageRender/src/render/render.cpp

2109 lines
83 KiB
C++
Raw Normal View History


2023-05-26 16:19:12 +08:00
#ifndef TINYGLTF_IMPLEMENTATION
#define TINYGLTF_IMPLEMENTATION
#endif
#ifndef STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#endif
2023-05-26 16:19:12 +08:00
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
#define TINYGLTF_NO_STB_IMAGE_WRITE
#endif
2023-05-26 16:19:12 +08:00
#include "render.h"
2023-06-07 10:52:04 +08:00
//#include "VulkanUtils.hpp"
//#include "assetLoader.h"
2023-05-17 14:53:31 +08:00
2023-06-06 17:18:45 +08:00
PlumageRender::PlumageRender()
2023-05-17 14:49:05 +08:00
{
2023-06-05 16:40:39 +08:00
title = "plumage render";
2023-05-17 14:49:05 +08:00
}
2024-04-01 13:45:00 +08:00
void PlumageRender::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)
{
auto app = reinterpret_cast<PlumageRender*>(glfwGetWindowUserPointer(window));
app->framebufferResized = true;
}
2024-04-01 18:05:17 +08:00
// 重构至gltfModel中
2024-04-01 13:45:00 +08:00
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;
2023-06-05 22:37:31 +08:00
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);
}
2023-06-05 22:37:31 +08:00
}
2023-05-17 14:49:05 +08:00
2024-04-01 18:05:17 +08:00
void PlumageRender::buildCommandBuffers()
2023-05-17 14:49:05 +08:00
{
2023-06-05 22:37:31 +08:00
VkCommandBufferBeginInfo cmdBufferBeginInfo{};
cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2023-05-17 14:49:05 +08:00
2023-06-05 22:37:31 +08:00
VkClearValue clearValues[3];
2024-04-01 13:45:00 +08:00
if (setter.settings.multiSampling) {
2023-06-05 22:37:31 +08:00
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 };
}
2023-05-17 14:49:05 +08:00
2023-06-05 22:37:31 +08:00
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderPass;
2023-05-17 14:49:05 +08:00
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
2024-04-01 13:45:00 +08:00
renderPassBeginInfo.renderArea.extent.width = setter.settings.width;
renderPassBeginInfo.renderArea.extent.height = setter.settings.height;
renderPassBeginInfo.clearValueCount = setter.settings.multiSampling ? 3 : 2;
2023-05-17 14:49:05 +08:00
renderPassBeginInfo.pClearValues = clearValues;
2024-03-25 11:51:10 +08:00
2023-06-05 22:37:31 +08:00
for (uint32_t i = 0; i < commandBuffers.size(); ++i) {
renderPassBeginInfo.framebuffer = frameBuffers[i];
2023-05-17 14:49:05 +08:00
2023-06-05 22:37:31 +08:00
VkCommandBuffer currentCB = commandBuffers[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(currentCB, &cmdBufferBeginInfo));
vkCmdBeginRenderPass(currentCB, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport{};
2024-04-01 13:45:00 +08:00
viewport.width = (float)setter.settings.width;
viewport.height = (float)setter.settings.height;
2023-06-05 22:37:31 +08:00
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(currentCB, 0, 1, &viewport);
VkRect2D scissor{};
2024-04-01 13:45:00 +08:00
scissor.extent = { setter.settings.width, setter.settings.height };
2023-06-05 22:37:31 +08:00
vkCmdSetScissor(currentCB, 0, 1, &scissor);
VkDeviceSize offsets[1] = { 0 };
if (displayBackground) {
vkCmdBindDescriptorSets(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i].skybox, 0, nullptr);
vkCmdBindPipeline(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skybox);
models.skybox.draw(currentCB);
}
2023-06-05 22:37:31 +08:00
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) {
renderNode(node, i, glTFModel::Material::ALPHAMODE_OPAQUE);
}
// Alpha masked primitives
for (auto node : model.nodes) {
renderNode(node, i, glTFModel::Material::ALPHAMODE_MASK);
}
// Transparent primitives
// TODO: Correct depth sorting
for (auto node : model.nodes) {
renderNode(node, i, glTFModel::Material::ALPHAMODE_BLEND);
}
// User interface
2024-04-01 13:45:00 +08:00
if (!setter.settings.headless)
2024-03-29 18:11:09 +08:00
{
gui->draw(currentCB);
}
2023-06-05 22:37:31 +08:00
vkCmdEndRenderPass(currentCB);
VK_CHECK_RESULT(vkEndCommandBuffer(currentCB));
2024-03-25 11:51:10 +08:00
2023-05-17 14:49:05 +08:00
}
}
2023-05-17 14:49:05 +08:00
2024-04-01 18:05:17 +08:00
void PlumageRender::loadScene(std::string filename)
2023-06-05 22:37:31 +08:00
{
std::cout << "Loading scene from " << filename << std::endl;
models.scene.destroy(device);
animationIndex = 0;
animationTimer = 0.0f;
auto tStart = std::chrono::high_resolution_clock::now();
models.scene.loadFromFile(filename, vulkanDevice, queue);
auto tFileLoad = std::chrono::duration<double, std::milli>(std::chrono::high_resolution_clock::now() - tStart).count();
std::cout << "Loading took " << tFileLoad << " ms" << std::endl;
camera.setPosition({ 0.0f, 0.0f, -1.0f });
2023-06-05 22:37:31 +08:00
camera.setRotation({ 0.0f, 0.0f, 0.0f });
}
2024-04-01 18:05:17 +08:00
void PlumageRender::loadEnvironment(std::string filename)
2023-06-05 22:37:31 +08:00
{
std::cout << "Loading environment from " << filename << std::endl;
if (textures.environmentCube.image) {
textures.environmentCube.destroy();
textures.irradianceCube.destroy();
textures.prefilteredCube.destroy();
}
textures.environmentCube.loadFromFile(filename, VK_FORMAT_R16G16B16A16_SFLOAT, vulkanDevice, queue);
generateCubemaps();
}
2023-06-06 11:40:59 +08:00
2024-04-01 18:05:17 +08:00
void PlumageRender::loadAssets()
2023-05-17 14:49:05 +08:00
{
2023-06-06 11:40:59 +08:00
const std::string assetpath = getAssetPath();
if (std::filesystem::exists(assetpath.c_str())) {
std::string msg = "asset path get " + assetpath;
std::cout << msg << std::endl;
}
else
{
2024-03-02 21:59:07 +08:00
std::string msg = "Could not locate asset path in \"" + assetpath + "\".\nMake sure binary is running from correct relative directory!";
2023-06-05 22:37:31 +08:00
std::cerr << msg << std::endl;
system("pause");
//exit(-1);
}
2023-06-05 22:37:31 +08:00
readDirectory(assetpath + "environments", "*.ktx", environments, false);
2023-06-05 22:37:31 +08:00
2024-04-01 13:45:00 +08:00
textures.empty.loadFromFile(setter.filePath.emptyEnvmapFilePath, VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
2023-06-05 22:37:31 +08:00
2024-04-01 13:45:00 +08:00
std::string sceneFile = setter.filePath.glTFModelFilePath;
std::string envMapFile = setter.filePath.envMapFilePath;
2023-06-05 22:37:31 +08:00
loadScene(sceneFile.c_str());
2024-04-01 13:45:00 +08:00
models.skybox.loadFromFile(setter.filePath.skyboxModleFilePath, vulkanDevice, queue);
2023-06-05 22:37:31 +08:00
loadEnvironment(envMapFile.c_str());
2023-05-17 14:49:05 +08:00
}
2024-04-01 18:05:17 +08:00
void PlumageRender::setupNodeDescriptorSet(glTFModel::Node* node)
2023-05-17 14:49:05 +08:00
{
/*
This sample uses separate descriptor sets (and layouts) for the matrices and materials (textures)
*/
2023-06-06 11:40:59 +08:00
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);
2023-05-25 16:13:37 +08:00
}
2023-06-06 11:40:59 +08:00
for (auto& child : node->children) {
setupNodeDescriptorSet(child);
}
}
2023-05-17 14:49:05 +08:00
2024-04-01 18:05:17 +08:00
void PlumageRender::setupDescriptors()
2023-06-06 11:40:59 +08:00
{
2024-04-03 12:07:49 +08:00
2023-06-06 11:40:59 +08:00
/*
Descriptor sets
*/
2023-05-17 14:49:05 +08:00
2023-06-06 11:40:59 +08:00
// Scene (matrices and environment maps)
{
2024-04-02 18:08:46 +08:00
2023-06-06 11:40:59 +08:00
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 = &textures.irradianceCube.descriptor;
writeDescriptorSets[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSets[3].descriptorCount = 1;
writeDescriptorSets[3].dstSet = descriptorSets[i].scene;
writeDescriptorSets[3].dstBinding = 3;
writeDescriptorSets[3].pImageInfo = &textures.prefilteredCube.descriptor;
writeDescriptorSets[4].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[4].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSets[4].descriptorCount = 1;
writeDescriptorSets[4].dstSet = descriptorSets[i].scene;
writeDescriptorSets[4].dstBinding = 4;
writeDescriptorSets[4].pImageInfo = &textures.lutBrdf.descriptor;
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
}
}
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
// Material (samplers)
{
2024-04-02 18:08:46 +08:00
2023-06-06 11:40:59 +08:00
// 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;
}
}
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
if (material.pbrWorkflows.specularGlossiness) {
if (material.extension.diffuseTexture) {
imageDescriptors[0] = material.extension.diffuseTexture->descriptor;
}
if (material.extension.specularGlossinessTexture) {
imageDescriptors[1] = material.extension.specularGlossinessTexture->descriptor;
}
}
2023-06-06 11:40:59 +08:00
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);
2023-05-25 16:13:37 +08:00
}
2023-06-06 11:40:59 +08:00
// Model node (matrices)
2023-05-25 16:13:37 +08:00
{
2024-04-02 18:08:46 +08:00
2023-06-06 11:40:59 +08:00
// Per-Node descriptor set
for (auto& node : models.scene.nodes) {
setupNodeDescriptorSet(node);
}
2023-05-25 16:13:37 +08:00
}
2023-05-17 14:49:05 +08:00
2023-06-06 11:40:59 +08:00
}
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
// 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);
2023-05-17 14:49:05 +08:00
}
}
2024-04-01 18:05:17 +08:00
// generate two cube maps
// irradiance cube map
// prefileter environment cube map
// 重构到PBR中
void PlumageRender::generateCubemaps()
2023-05-17 14:49:05 +08:00
{
2023-06-06 11:40:59 +08:00
enum Target { IRRADIANCE = 0, PREFILTEREDENV = 1 };
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++) {
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vks::TextureCubeMap cubemap;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
auto tStart = std::chrono::high_resolution_clock::now();
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkFormat format;
int32_t dim;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
switch (target) {
case IRRADIANCE:
format = VK_FORMAT_R32G32B32A32_SFLOAT;
dim = 64;
break;
case PREFILTEREDENV:
format = VK_FORMAT_R16G16B16A16_SFLOAT;
dim = 512;
break;
};
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
const uint32_t numMips = static_cast<uint32_t>(floor(log2(dim))) + 1;
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
// Create target cubemap
{
// Image
VkImageCreateInfo imageCI{};
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = format;
imageCI.extent.width = dim;
imageCI.extent.height = dim;
imageCI.extent.depth = 1;
imageCI.mipLevels = numMips;
imageCI.arrayLayers = 6;
imageCI.samples = VK_SAMPLE_COUNT_1_BIT;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
imageCI.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &cubemap.image));
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device, cubemap.image, &memReqs);
VkMemoryAllocateInfo memAllocInfo{};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &cubemap.deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(device, cubemap.image, cubemap.deviceMemory, 0));
// View
VkImageViewCreateInfo viewCI{};
viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
viewCI.format = format;
viewCI.subresourceRange = {};
viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCI.subresourceRange.levelCount = numMips;
viewCI.subresourceRange.layerCount = 6;
viewCI.image = cubemap.image;
VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &cubemap.view));
// Sampler
VkSamplerCreateInfo samplerCI{};
samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerCI.magFilter = VK_FILTER_LINEAR;
samplerCI.minFilter = VK_FILTER_LINEAR;
samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.minLod = 0.0f;
samplerCI.maxLod = static_cast<float>(numMips);
samplerCI.maxAnisotropy = 1.0f;
samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &cubemap.sampler));
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// FB, Att, RP, Pipe, etc.
VkAttachmentDescription attDesc{};
// Color attachment
attDesc.format = format;
attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
VkSubpassDescription subpassDescription{};
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDescription.colorAttachmentCount = 1;
subpassDescription.pColorAttachments = &colorReference;
// Use subpass dependencies for layout transitions
std::array<VkSubpassDependency, 2> dependencies;
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
// Renderpass
VkRenderPassCreateInfo renderPassCI{};
renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCI.attachmentCount = 1;
renderPassCI.pAttachments = &attDesc;
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpassDescription;
renderPassCI.dependencyCount = 2;
renderPassCI.pDependencies = dependencies.data();
VkRenderPass renderpass;
VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderpass));
// Create offscreen framebuffer
2023-05-25 16:13:37 +08:00
{
2023-06-06 11:40:59 +08:00
// Image
VkImageCreateInfo imageCI{};
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = format;
imageCI.extent.width = dim;
imageCI.extent.height = dim;
imageCI.extent.depth = 1;
imageCI.mipLevels = 1;
imageCI.arrayLayers = 1;
imageCI.samples = VK_SAMPLE_COUNT_1_BIT;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &offscreen.image));
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device, offscreen.image, &memReqs);
VkMemoryAllocateInfo memAllocInfo{};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &offscreen.memory));
VK_CHECK_RESULT(vkBindImageMemory(device, offscreen.image, offscreen.memory, 0));
// View
VkImageViewCreateInfo viewCI{};
viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCI.format = format;
viewCI.flags = 0;
viewCI.subresourceRange = {};
viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCI.subresourceRange.baseMipLevel = 0;
viewCI.subresourceRange.levelCount = 1;
viewCI.subresourceRange.baseArrayLayer = 0;
viewCI.subresourceRange.layerCount = 1;
viewCI.image = offscreen.image;
VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &offscreen.view));
// Framebuffer
VkFramebufferCreateInfo framebufferCI{};
framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferCI.renderPass = renderpass;
framebufferCI.attachmentCount = 1;
framebufferCI.pAttachments = &offscreen.view;
framebufferCI.width = dim;
framebufferCI.height = dim;
framebufferCI.layers = 1;
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCI, nullptr, &offscreen.framebuffer));
VkCommandBuffer layoutCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.image = offscreen.image;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
vkCmdPipelineBarrier(layoutCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
vulkanDevice->flushCommandBuffer(layoutCmd, queue, true);
}
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
// Descriptors
VkDescriptorSetLayout descriptorsetlayout;
VkDescriptorSetLayoutBinding setLayoutBinding = { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr };
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{};
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutCI.pBindings = &setLayoutBinding;
descriptorSetLayoutCI.bindingCount = 1;
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorsetlayout));
// Descriptor Pool
VkDescriptorPoolSize poolSize = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 };
VkDescriptorPoolCreateInfo descriptorPoolCI{};
descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptorPoolCI.poolSizeCount = 1;
descriptorPoolCI.pPoolSizes = &poolSize;
descriptorPoolCI.maxSets = 2;
VkDescriptorPool descriptorpool;
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorpool));
// Descriptor sets
VkDescriptorSet descriptorset;
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocInfo.descriptorPool = descriptorpool;
descriptorSetAllocInfo.pSetLayouts = &descriptorsetlayout;
descriptorSetAllocInfo.descriptorSetCount = 1;
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorset));
VkWriteDescriptorSet writeDescriptorSet{};
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSet.descriptorCount = 1;
writeDescriptorSet.dstSet = descriptorset;
writeDescriptorSet.dstBinding = 0;
writeDescriptorSet.pImageInfo = &textures.environmentCube.descriptor;
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
// Pipeline layout
VkPipelineLayout pipelinelayout;
VkPushConstantRange pushConstantRange{};
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
switch (target) {
case IRRADIANCE:
pushConstantRange.size = sizeof(IrradiancePushBlock);
break;
case PREFILTEREDENV:
pushConstantRange.size = sizeof(PrefilterPushBlock);
break;
};
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
VkPipelineLayoutCreateInfo pipelineLayoutCI{};
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCI.setLayoutCount = 1;
pipelineLayoutCI.pSetLayouts = &descriptorsetlayout;
pipelineLayoutCI.pushConstantRangeCount = 1;
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelinelayout));
// Pipeline
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{};
inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkPipelineRasterizationStateCreateInfo rasterizationStateCI{};
rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL;
rasterizationStateCI.cullMode = VK_CULL_MODE_NONE;
rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizationStateCI.lineWidth = 1.0f;
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
VkPipelineColorBlendAttachmentState blendAttachmentState{};
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blendAttachmentState.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo colorBlendStateCI{};
colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendStateCI.attachmentCount = 1;
colorBlendStateCI.pAttachments = &blendAttachmentState;
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{};
depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilStateCI.depthTestEnable = VK_FALSE;
depthStencilStateCI.depthWriteEnable = VK_FALSE;
depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
depthStencilStateCI.front = depthStencilStateCI.back;
depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS;
VkPipelineViewportStateCreateInfo viewportStateCI{};
viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportStateCI.viewportCount = 1;
viewportStateCI.scissorCount = 1;
VkPipelineMultisampleStateCreateInfo multisampleStateCI{};
multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo dynamicStateCI{};
dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicStateCI.pDynamicStates = dynamicStateEnables.data();
dynamicStateCI.dynamicStateCount = static_cast<uint32_t>(dynamicStateEnables.size());
// Vertex input state
VkVertexInputBindingDescription vertexInputBinding = { 0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX };
VkVertexInputAttributeDescription vertexInputAttribute = { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0 };
VkPipelineVertexInputStateCreateInfo vertexInputStateCI{};
vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputStateCI.vertexBindingDescriptionCount = 1;
vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding;
vertexInputStateCI.vertexAttributeDescriptionCount = 1;
vertexInputStateCI.pVertexAttributeDescriptions = &vertexInputAttribute;
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
VkGraphicsPipelineCreateInfo pipelineCI{};
pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineCI.layout = pipelinelayout;
pipelineCI.renderPass = renderpass;
pipelineCI.pInputAssemblyState = &inputAssemblyStateCI;
pipelineCI.pVertexInputState = &vertexInputStateCI;
pipelineCI.pRasterizationState = &rasterizationStateCI;
pipelineCI.pColorBlendState = &colorBlendStateCI;
pipelineCI.pMultisampleState = &multisampleStateCI;
pipelineCI.pViewportState = &viewportStateCI;
pipelineCI.pDepthStencilState = &depthStencilStateCI;
pipelineCI.pDynamicState = &dynamicStateCI;
pipelineCI.stageCount = 2;
pipelineCI.pStages = shaderStages.data();
pipelineCI.renderPass = renderpass;
2024-04-01 13:45:00 +08:00
shaderStages[0] = loadShader(device, setter.filePath.filterVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT);
2023-06-06 11:40:59 +08:00
switch (target) {
case IRRADIANCE:
2024-04-01 13:45:00 +08:00
shaderStages[1] = loadShader(device, setter.filePath.irradianceFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT);
2023-06-06 11:40:59 +08:00
break;
case PREFILTEREDENV:
2024-04-01 13:45:00 +08:00
shaderStages[1] = loadShader(device, setter.filePath.prefilterEnvmapFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT);
2023-06-06 11:40:59 +08:00
break;
2023-05-25 16:13:37 +08:00
};
2023-06-06 11:40:59 +08:00
VkPipeline pipeline;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
for (auto shaderStage : shaderStages) {
vkDestroyShaderModule(device, shaderStage.module, nullptr);
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// Render cubemap
VkClearValue clearValues[1];
clearValues[0].color = { { 0.0f, 0.0f, 0.2f, 0.0f } };
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderpass;
renderPassBeginInfo.framebuffer = offscreen.framebuffer;
renderPassBeginInfo.renderArea.extent.width = dim;
renderPassBeginInfo.renderArea.extent.height = dim;
renderPassBeginInfo.clearValueCount = 1;
renderPassBeginInfo.pClearValues = clearValues;
std::vector<glm::mat4> matrices = {
glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f)),
};
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkCommandBuffer cmdBuf = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false);
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkViewport viewport{};
viewport.width = (float)dim;
viewport.height = (float)dim;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkRect2D scissor{};
scissor.extent.width = dim;
scissor.extent.height = dim;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkImageSubresourceRange subresourceRange{};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = numMips;
subresourceRange.layerCount = 6;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// Change image layout for all cubemap faces to transfer destination
2023-05-24 16:10:36 +08:00
{
2023-06-06 11:40:59 +08:00
vulkanDevice->beginCommandBuffer(cmdBuf);
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.image = cubemap.image;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.subresourceRange = subresourceRange;
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
vulkanDevice->flushCommandBuffer(cmdBuf, queue, false);
2023-05-24 16:10:36 +08:00
}
2023-06-06 11:40:59 +08:00
for (uint32_t m = 0; m < numMips; m++) {
for (uint32_t f = 0; f < 6; f++) {
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vulkanDevice->beginCommandBuffer(cmdBuf);
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
viewport.width = static_cast<float>(dim * std::pow(0.5f, m));
viewport.height = static_cast<float>(dim * std::pow(0.5f, m));
vkCmdSetViewport(cmdBuf, 0, 1, &viewport);
vkCmdSetScissor(cmdBuf, 0, 1, &scissor);
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// Render scene from cube face's point of view
vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// Pass parameters for current pass using a push constant block
switch (target) {
case IRRADIANCE:
irradiancePushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f];
2023-06-06 15:52:39 +08:00
vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(IrradiancePushBlock), &irradiancePushBlock);
2023-06-06 11:40:59 +08:00
break;
case PREFILTEREDENV:
prefilterPushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f];
prefilterPushBlock.roughness = (float)m / (float)(numMips - 1);
2023-06-06 15:52:39 +08:00
vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PrefilterPushBlock), &prefilterPushBlock);
2023-06-06 11:40:59 +08:00
break;
};
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinelayout, 0, 1, &descriptorset, 0, NULL);
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkDeviceSize offsets[1] = { 0 };
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
models.skybox.draw(cmdBuf);
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vkCmdEndRenderPass(cmdBuf);
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = numMips;
subresourceRange.layerCount = 6;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
{
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.image = offscreen.image;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// Copy region for transfer from framebuffer to cube face
VkImageCopy copyRegion{};
copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyRegion.srcSubresource.baseArrayLayer = 0;
copyRegion.srcSubresource.mipLevel = 0;
copyRegion.srcSubresource.layerCount = 1;
copyRegion.srcOffset = { 0, 0, 0 };
copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyRegion.dstSubresource.baseArrayLayer = f;
copyRegion.dstSubresource.mipLevel = m;
copyRegion.dstSubresource.layerCount = 1;
copyRegion.dstOffset = { 0, 0, 0 };
copyRegion.extent.width = static_cast<uint32_t>(viewport.width);
copyRegion.extent.height = static_cast<uint32_t>(viewport.height);
copyRegion.extent.depth = 1;
vkCmdCopyImage(
cmdBuf,
offscreen.image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
cubemap.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&copyRegion);
{
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.image = offscreen.image;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vulkanDevice->flushCommandBuffer(cmdBuf, queue, false);
}
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
{
vulkanDevice->beginCommandBuffer(cmdBuf);
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.image = cubemap.image;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.subresourceRange = subresourceRange;
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
vulkanDevice->flushCommandBuffer(cmdBuf, queue, false);
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vkDestroyRenderPass(device, renderpass, nullptr);
vkDestroyFramebuffer(device, offscreen.framebuffer, nullptr);
vkFreeMemory(device, offscreen.memory, nullptr);
vkDestroyImageView(device, offscreen.view, nullptr);
vkDestroyImage(device, offscreen.image, nullptr);
vkDestroyDescriptorPool(device, descriptorpool, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorsetlayout, nullptr);
vkDestroyPipeline(device, pipeline, nullptr);
vkDestroyPipelineLayout(device, pipelinelayout, nullptr);
cubemap.descriptor.imageView = cubemap.view;
cubemap.descriptor.sampler = cubemap.sampler;
cubemap.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
cubemap.device = vulkanDevice;
switch (target) {
case IRRADIANCE:
textures.irradianceCube = cubemap;
break;
case PREFILTEREDENV:
textures.prefilteredCube = cubemap;
shaderData.prefilteredCubeMipLevels = static_cast<float>(numMips);
break;
};
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
std::cout << "Generating cube map with " << numMips << " mip levels took " << tDiff << " ms" << std::endl;
2023-05-24 16:10:36 +08:00
}
}
2024-04-01 18:05:17 +08:00
// generate BRDF integration map for roughness/NdotV
// 重构到PBR
void PlumageRender::generateBRDFLUT()
2023-05-24 16:10:36 +08:00
{
auto tStart = std::chrono::high_resolution_clock::now();
2023-06-06 11:40:59 +08:00
const VkFormat format = VK_FORMAT_R16G16_SFLOAT;
const int32_t dim = 512;
2023-05-24 16:10:36 +08:00
// Image
2023-06-06 11:40:59 +08:00
VkImageCreateInfo imageCI{};
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
2023-05-24 16:10:36 +08:00
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = format;
imageCI.extent.width = dim;
imageCI.extent.height = dim;
imageCI.extent.depth = 1;
imageCI.mipLevels = 1;
imageCI.arrayLayers = 1;
imageCI.samples = VK_SAMPLE_COUNT_1_BIT;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
2023-06-06 11:40:59 +08:00
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &textures.lutBrdf.image));
2023-05-24 16:10:36 +08:00
VkMemoryRequirements memReqs;
2023-06-06 11:40:59 +08:00
vkGetImageMemoryRequirements(device, textures.lutBrdf.image, &memReqs);
VkMemoryAllocateInfo memAllocInfo{};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &textures.lutBrdf.deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(device, textures.lutBrdf.image, textures.lutBrdf.deviceMemory, 0));
// View
VkImageViewCreateInfo viewCI{};
viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2023-05-24 16:10:36 +08:00
viewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCI.format = format;
viewCI.subresourceRange = {};
viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCI.subresourceRange.levelCount = 1;
viewCI.subresourceRange.layerCount = 1;
2023-06-06 11:40:59 +08:00
viewCI.image = textures.lutBrdf.image;
VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &textures.lutBrdf.view));
2023-05-24 16:10:36 +08:00
// Sampler
2023-06-06 11:40:59 +08:00
VkSamplerCreateInfo samplerCI{};
samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
2023-05-24 16:10:36 +08:00
samplerCI.magFilter = VK_FILTER_LINEAR;
samplerCI.minFilter = VK_FILTER_LINEAR;
samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.minLod = 0.0f;
samplerCI.maxLod = 1.0f;
2023-06-06 11:40:59 +08:00
samplerCI.maxAnisotropy = 1.0f;
2023-05-24 16:10:36 +08:00
samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
2023-06-06 11:40:59 +08:00
VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &textures.lutBrdf.sampler));
2023-05-24 16:10:36 +08:00
// FB, Att, RP, Pipe, etc.
2023-06-06 11:40:59 +08:00
VkAttachmentDescription attDesc{};
2023-05-24 16:10:36 +08:00
// Color attachment
attDesc.format = format;
attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attDesc.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2023-06-06 11:40:59 +08:00
VkSubpassDescription subpassDescription{};
2023-05-24 16:10:36 +08:00
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDescription.colorAttachmentCount = 1;
subpassDescription.pColorAttachments = &colorReference;
// Use subpass dependencies for layout transitions
std::array<VkSubpassDependency, 2> dependencies;
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
2023-06-06 11:40:59 +08:00
// Create the actual renderpass
VkRenderPassCreateInfo renderPassCI{};
renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
2023-05-24 16:10:36 +08:00
renderPassCI.attachmentCount = 1;
renderPassCI.pAttachments = &attDesc;
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpassDescription;
renderPassCI.dependencyCount = 2;
renderPassCI.pDependencies = dependencies.data();
VkRenderPass renderpass;
VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderpass));
2023-06-06 11:40:59 +08:00
VkFramebufferCreateInfo framebufferCI{};
framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
2023-05-24 16:10:36 +08:00
framebufferCI.renderPass = renderpass;
framebufferCI.attachmentCount = 1;
2023-06-06 11:40:59 +08:00
framebufferCI.pAttachments = &textures.lutBrdf.view;
2023-05-24 16:10:36 +08:00
framebufferCI.width = dim;
framebufferCI.height = dim;
framebufferCI.layers = 1;
VkFramebuffer framebuffer;
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCI, nullptr, &framebuffer));
2023-06-06 11:40:59 +08:00
// Desriptors
2023-05-24 16:10:36 +08:00
VkDescriptorSetLayout descriptorsetlayout;
2023-06-06 11:40:59 +08:00
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{};
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorsetlayout));
2023-05-24 16:10:36 +08:00
// Pipeline layout
VkPipelineLayout pipelinelayout;
2023-06-06 11:40:59 +08:00
VkPipelineLayoutCreateInfo pipelineLayoutCI{};
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCI.setLayoutCount = 1;
pipelineLayoutCI.pSetLayouts = &descriptorsetlayout;
2023-05-24 16:10:36 +08:00
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelinelayout));
// Pipeline
2023-06-06 11:40:59 +08:00
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{};
inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkPipelineRasterizationStateCreateInfo rasterizationStateCI{};
rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL;
rasterizationStateCI.cullMode = VK_CULL_MODE_NONE;
rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizationStateCI.lineWidth = 1.0f;
VkPipelineColorBlendAttachmentState blendAttachmentState{};
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blendAttachmentState.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo colorBlendStateCI{};
colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendStateCI.attachmentCount = 1;
colorBlendStateCI.pAttachments = &blendAttachmentState;
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{};
depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilStateCI.depthTestEnable = VK_FALSE;
depthStencilStateCI.depthWriteEnable = VK_FALSE;
depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
depthStencilStateCI.front = depthStencilStateCI.back;
depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS;
VkPipelineViewportStateCreateInfo viewportStateCI{};
viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportStateCI.viewportCount = 1;
viewportStateCI.scissorCount = 1;
VkPipelineMultisampleStateCreateInfo multisampleStateCI{};
multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
2023-05-24 16:10:36 +08:00
std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
2023-06-06 11:40:59 +08:00
VkPipelineDynamicStateCreateInfo dynamicStateCI{};
dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicStateCI.pDynamicStates = dynamicStateEnables.data();
dynamicStateCI.dynamicStateCount = static_cast<uint32_t>(dynamicStateEnables.size());
VkPipelineVertexInputStateCreateInfo emptyInputStateCI{};
emptyInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
2023-05-24 16:10:36 +08:00
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
2023-06-06 11:40:59 +08:00
VkGraphicsPipelineCreateInfo pipelineCI{};
pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineCI.layout = pipelinelayout;
pipelineCI.renderPass = renderpass;
pipelineCI.pInputAssemblyState = &inputAssemblyStateCI;
pipelineCI.pVertexInputState = &emptyInputStateCI;
pipelineCI.pRasterizationState = &rasterizationStateCI;
pipelineCI.pColorBlendState = &colorBlendStateCI;
pipelineCI.pMultisampleState = &multisampleStateCI;
pipelineCI.pViewportState = &viewportStateCI;
pipelineCI.pDepthStencilState = &depthStencilStateCI;
pipelineCI.pDynamicState = &dynamicStateCI;
2023-05-24 16:10:36 +08:00
pipelineCI.stageCount = 2;
pipelineCI.pStages = shaderStages.data();
2023-06-06 11:40:59 +08:00
// Look-up-table (from BRDF) pipeline
shaderStages = {
2024-04-01 13:45:00 +08:00
loadShader(device,setter.filePath.brdfVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT),
loadShader(device,setter.filePath.brdfFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT)
2023-06-06 11:40:59 +08:00
};
2023-05-24 16:10:36 +08:00
VkPipeline pipeline;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
2023-06-06 11:40:59 +08:00
for (auto shaderStage : shaderStages) {
vkDestroyShaderModule(device, shaderStage.module, nullptr);
}
2023-05-24 16:10:36 +08:00
// Render
VkClearValue clearValues[1];
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
2023-06-06 11:40:59 +08:00
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
2023-05-24 16:10:36 +08:00
renderPassBeginInfo.renderPass = renderpass;
renderPassBeginInfo.renderArea.extent.width = dim;
renderPassBeginInfo.renderArea.extent.height = dim;
renderPassBeginInfo.clearValueCount = 1;
renderPassBeginInfo.pClearValues = clearValues;
renderPassBeginInfo.framebuffer = framebuffer;
VkCommandBuffer cmdBuf = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
2023-06-06 11:40:59 +08:00
VkViewport viewport{};
viewport.width = (float)dim;
viewport.height = (float)dim;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.extent.width = dim;
scissor.extent.height = dim;
2023-05-24 16:10:36 +08:00
vkCmdSetViewport(cmdBuf, 0, 1, &viewport);
vkCmdSetScissor(cmdBuf, 0, 1, &scissor);
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
vkCmdEndRenderPass(cmdBuf);
vulkanDevice->flushCommandBuffer(cmdBuf, queue);
vkQueueWaitIdle(queue);
vkDestroyPipeline(device, pipeline, nullptr);
vkDestroyPipelineLayout(device, pipelinelayout, nullptr);
vkDestroyRenderPass(device, renderpass, nullptr);
vkDestroyFramebuffer(device, framebuffer, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorsetlayout, nullptr);
2023-06-06 11:40:59 +08:00
textures.lutBrdf.descriptor.imageView = textures.lutBrdf.view;
textures.lutBrdf.descriptor.sampler = textures.lutBrdf.sampler;
textures.lutBrdf.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
textures.lutBrdf.device = vulkanDevice;
2023-05-24 16:10:36 +08:00
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
std::cout << "Generating BRDF LUT took " << tDiff << " ms" << std::endl;
2023-05-25 16:13:37 +08:00
}
2023-06-06 15:52:39 +08:00
2024-04-01 18:05:17 +08:00
// Prepare and initialize uniform buffer containing shader uniforms
void PlumageRender::prepareUniformBuffers()
2023-05-17 14:49:05 +08:00
{
2023-06-06 15:52:39 +08:00
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));
2023-05-25 16:13:37 +08:00
}
2023-05-17 14:49:05 +08:00
updateUniformBuffers();
}
2024-04-01 18:05:17 +08:00
// 更新统一缓冲区
void PlumageRender::updateUniformBuffers()
2023-05-17 14:49:05 +08:00
{
2023-06-06 15:52:39 +08:00
// 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));
}
2024-04-01 18:05:17 +08:00
void PlumageRender::updateShaderData()
2023-06-06 15:52:39 +08:00
{
shaderData.lightDir = glm::vec4(
sin(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)),
sin(glm::radians(lightSource.rotation.y)),
cos(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)),
0.0f);
}
2024-04-01 18:05:17 +08:00
// todo重写成glfw的
void PlumageRender::windowResized()
2023-06-06 15:52:39 +08:00
{
buildCommandBuffers();
vkDeviceWaitIdle(device);
updateUniformBuffers();
2023-06-07 10:52:04 +08:00
//update UI
updateUIOverlay();
2023-05-17 14:49:05 +08:00
}
2024-04-01 18:05:17 +08:00
void PlumageRender::prepare()
2023-05-17 14:49:05 +08:00
{
2024-04-02 18:08:46 +08:00
//VulkanExampleBase::prepare();
2023-06-06 15:52:39 +08:00
camera.type = Camera::CameraType::lookat;
2024-04-01 13:45:00 +08:00
camera.setPerspective(45.0f, (float)setter.settings.width / (float)setter.settings.height, 0.1f, 256.0f);
2023-06-06 15:52:39 +08:00
camera.rotationSpeed = 0.25f;
camera.movementSpeed = 0.1f;
camera.setPosition({ 0.0f, 0.0f, -1.0f });
2023-06-06 15:52:39 +08:00
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));
}
2024-04-01 13:45:00 +08:00
if (!setter.settings.headless)
2024-03-29 18:11:09 +08:00
{
for (auto& semaphore : presentCompleteSemaphores) {
VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 };
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore));
}
2023-06-06 15:52:39 +08:00
}
2024-03-29 18:11:09 +08:00
// Queue ordering semaphores
2023-06-06 15:52:39 +08:00
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()));
}
2023-05-17 14:49:05 +08:00
loadAssets();
2023-06-06 15:52:39 +08:00
generateBRDFLUT();
generateCubemaps();
2023-05-17 14:49:05 +08:00
prepareUniformBuffers();
setupDescriptors();
preparePipelines();
2024-04-01 13:45:00 +08:00
if (!setter.settings.headless)
2024-03-29 18:11:09 +08:00
{
2024-04-01 13:45:00 +08:00
gui = new UI(vulkanDevice, renderPass, queue, pipelineCache, setter.settings.sampleCount);
2024-03-29 18:11:09 +08:00
updateUIOverlay();
}
2023-06-06 15:52:39 +08:00
2023-05-17 14:49:05 +08:00
buildCommandBuffers();
2023-06-06 15:52:39 +08:00
2023-05-17 14:49:05 +08:00
prepared = true;
}
2024-04-01 18:05:17 +08:00
void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue)
2024-03-22 18:05:18 +08:00
{
VkSubmitInfo submitInfo = vks::initializers::submitInfo();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuffer;
VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo();
VkFence fence;
VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence));
2024-03-22 18:05:18 +08:00
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX));
vkDestroyFence(device, fence, nullptr);
2024-03-22 18:05:18 +08:00
}
2024-04-01 18:05:17 +08:00
// todo :根据physicalDeviceIndex确定子文件夹路径frameIndex确定fileName
// 移动到fileSystem里
void PlumageRender::writeImageToFile(std::string filePath)
2024-03-22 18:05:18 +08:00
{
2024-03-26 15:17:51 +08:00
bool screenshotSaved = false;
bool supportsBlit = true;
2024-03-26 15:17:51 +08:00
// Check blit support for source and destination
VkFormatProperties formatProps;
2024-03-26 15:17:51 +08:00
// Check if the device supports blitting from optimal images (the swapchain images are in optimal format)
vkGetPhysicalDeviceFormatProperties(physicalDevice, swapChain.colorFormat, &formatProps);
if (!(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) {
std::cerr << "Device does not support blitting from optimal tiled images, using copy instead of blit!" << std::endl;
supportsBlit = false;
}
2024-03-22 18:05:18 +08:00
2024-03-26 15:17:51 +08:00
// Check if the device supports blitting to linear images
vkGetPhysicalDeviceFormatProperties(physicalDevice, VK_FORMAT_R8G8B8A8_UNORM, &formatProps);
if (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) {
std::cerr << "Device does not support blitting to linear tiled images, using copy instead of blit!" << std::endl;
supportsBlit = false;
}
2024-03-22 18:05:18 +08:00
2024-03-26 15:17:51 +08:00
// Source for the copy is the last rendered swapchain image
VkImage srcImage = swapChain.images[currentBuffer];
2024-03-29 18:11:09 +08:00
2024-03-26 15:17:51 +08:00
// Create the linear tiled destination image to copy to and to read the memory from
VkImageCreateInfo imageCreateCI(vks::initializers::imageCreateInfo());
imageCreateCI.imageType = VK_IMAGE_TYPE_2D;
// Note that vkCmdBlitImage (if supported) will also do format conversions if the swapchain color format would differ
imageCreateCI.format = VK_FORMAT_R8G8B8A8_UNORM;
2024-04-01 13:45:00 +08:00
imageCreateCI.extent.width = setter.settings.width;
imageCreateCI.extent.height = setter.settings.height;
2024-03-26 15:17:51 +08:00
imageCreateCI.extent.depth = 1;
imageCreateCI.arrayLayers = 1;
imageCreateCI.mipLevels = 1;
imageCreateCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateCI.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateCI.tiling = VK_IMAGE_TILING_LINEAR;
imageCreateCI.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
// Create the image
VkImage dstImage;
VK_CHECK_RESULT(vkCreateImage(device, &imageCreateCI, nullptr, &dstImage));
// Create memory to back up the image
2024-03-22 18:05:18 +08:00
VkMemoryRequirements memRequirements;
VkMemoryAllocateInfo memAllocInfo(vks::initializers::memoryAllocateInfo());
VkDeviceMemory dstImageMemory;
vkGetImageMemoryRequirements(device, dstImage, &memRequirements);
memAllocInfo.allocationSize = memRequirements.size;
2024-03-26 15:17:51 +08:00
// Memory must be host visible to copy from
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
2024-03-22 18:05:18 +08:00
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &dstImageMemory));
VK_CHECK_RESULT(vkBindImageMemory(device, dstImage, dstImageMemory, 0));
2024-03-26 15:17:51 +08:00
// Do the actual blit from the swapchain image to our host visible destination image
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
// Transition destination image to transfer destination layout
vks::tools::insertImageMemoryBarrier(
copyCmd,
dstImage,
0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
// Transition swapchain image from present to transfer source layout
vks::tools::insertImageMemoryBarrier(
copyCmd,
srcImage,
VK_ACCESS_MEMORY_READ_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
2024-03-29 18:11:09 +08:00
//VK_IMAGE_LAYOUT_UNDEFINED,
2024-03-26 15:17:51 +08:00
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
// If source and destination support blit we'll blit as this also does automatic format conversion (e.g. from BGR to RGB)
if (supportsBlit)
{
// Define the region to blit (we will blit the whole swapchain image)
VkOffset3D blitSize;
2024-04-01 13:45:00 +08:00
blitSize.x = setter.settings.width;
blitSize.y = setter.settings.height;
2024-03-26 15:17:51 +08:00
blitSize.z = 1;
VkImageBlit imageBlitRegion{};
imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageBlitRegion.srcSubresource.layerCount = 1;
imageBlitRegion.srcOffsets[1] = blitSize;
imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageBlitRegion.dstSubresource.layerCount = 1;
imageBlitRegion.dstOffsets[1] = blitSize;
// Issue the blit command
vkCmdBlitImage(
copyCmd,
srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&imageBlitRegion,
VK_FILTER_NEAREST);
}
else
{
// Otherwise use image copy (requires us to manually flip components)
VkImageCopy imageCopyRegion{};
imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageCopyRegion.srcSubresource.layerCount = 1;
imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageCopyRegion.dstSubresource.layerCount = 1;
2024-04-01 13:45:00 +08:00
imageCopyRegion.extent.width = setter.settings.width;
imageCopyRegion.extent.height = setter.settings.height;
2024-03-26 15:17:51 +08:00
imageCopyRegion.extent.depth = 1;
// Issue the copy command
vkCmdCopyImage(
copyCmd,
srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&imageCopyRegion);
}
2024-03-22 18:05:18 +08:00
2024-03-26 15:17:51 +08:00
// Transition destination image to general layout, which is the required layout for mapping the image memory later on
vks::tools::insertImageMemoryBarrier(
copyCmd,
dstImage,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_MEMORY_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_GENERAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
2024-04-01 13:45:00 +08:00
if (!setter.settings.headless)
2024-03-29 18:11:09 +08:00
{
// Transition back the swap chain image after the blit is done
vks::tools::insertImageMemoryBarrier(
copyCmd,
srcImage,
VK_ACCESS_TRANSFER_READ_BIT,
VK_ACCESS_MEMORY_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
}
2024-03-26 15:17:51 +08:00
vulkanDevice->flushCommandBuffer(copyCmd, queue);
// Get layout of the image (including row pitch)
VkImageSubresource subResource{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
2024-03-22 18:05:18 +08:00
VkSubresourceLayout subResourceLayout;
vkGetImageSubresourceLayout(device, dstImage, &subResource, &subResourceLayout);
2024-03-26 15:17:51 +08:00
// Map image memory so we can start copying from it
const char* data;
vkMapMemory(device, dstImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&data);
data += subResourceLayout.offset;
2024-03-22 18:05:18 +08:00
2024-03-26 15:17:51 +08:00
// If source is BGR (destination is always RGB) and we can't use blit (which does automatic conversion), we'll have to manually swizzle color components
bool colorSwizzle = false;
// Check if source is BGR
// Note: Not complete, only contains most common and basic BGR surface formats for demonstration purposes
if (!supportsBlit)
{
std::vector<VkFormat> formatsBGR = { VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM };
colorSwizzle = (std::find(formatsBGR.begin(), formatsBGR.end(), swapChain.colorFormat) != formatsBGR.end());
}
2024-03-22 18:05:18 +08:00
2024-04-01 13:45:00 +08:00
if (setter.settings.outputPNGimage)
2024-03-26 15:17:51 +08:00
{
if (colorSwizzle)
2024-03-26 15:17:51 +08:00
{
2024-03-29 15:45:45 +08:00
// 暂时不改此处需要将BGR通道改成RGB格式
2024-04-01 13:45:00 +08:00
stbi_write_png(filePath.c_str(), setter.settings.width, setter.settings.height, 4, data, static_cast<int>(subResourceLayout.rowPitch));
}
else
{
2024-04-01 13:45:00 +08:00
stbi_write_png(filePath.c_str(), setter.settings.width, setter.settings.height, 4, data, static_cast<int>(subResourceLayout.rowPitch));
}
}
else
{
std::ofstream file(filePath, std::ios::out | std::ios::binary);
// ppm header
2024-04-01 13:45:00 +08:00
file << "P6\n" << setter.settings.width << "\n" << setter.settings.height << "\n" << 255 << "\n";
// ppm binary pixel data
2024-04-01 13:45:00 +08:00
for (uint32_t y = 0; y < setter.settings.height; y++)
{
unsigned int* row = (unsigned int*)data;
2024-04-01 13:45:00 +08:00
for (uint32_t x = 0; x < setter.settings.width; x++)
2024-03-26 15:17:51 +08:00
{
if (colorSwizzle)
{
file.write((char*)row + 2, 1);
file.write((char*)row + 1, 1);
file.write((char*)row, 1);
}
else
{
file.write((char*)row, 3);
}
row++;
2024-03-22 18:05:18 +08:00
}
data += subResourceLayout.rowPitch;
2024-03-22 18:05:18 +08:00
}
file.close();
2024-03-22 18:05:18 +08:00
}
2024-03-26 18:04:18 +08:00
std::cout << "Screenshot saved to " << filePath << std::endl;
2024-03-22 18:05:18 +08:00
// Clean up resources
vkUnmapMemory(device, dstImageMemory);
vkFreeMemory(device, dstImageMemory, nullptr);
vkDestroyImage(device, dstImage, nullptr);
2024-03-26 15:17:51 +08:00
screenshotSaved = true;
2024-03-25 11:51:10 +08:00
2024-03-22 18:05:18 +08:00
}
2024-04-01 18:05:17 +08:00
void PlumageRender::outputImageSequence()
2024-03-22 18:05:18 +08:00
{
// 比较已保存的帧数和设置里的开始帧数,在生成前清理上一次生成的图片序列
2024-04-01 13:45:00 +08:00
if (savedFrameCounter == setter.settings.startFrameCount)
{
std::cout << "clean up directory for image sequence generation" << std::endl;
removeImageSequence();
}
// 根据显卡编号设置输出路径todo提前到配置里
2024-04-01 13:45:00 +08:00
setter.filePath.deviceSpecFilePath = setter.filePath.imageOutputPath + "/device" + std::to_string(selectedPhysicalDeviceIndex);
// 非第一次生成,生成结束的边界条件
2024-04-01 13:45:00 +08:00
if (savedFrameCounter > setter.settings.outputFrameCount)
2024-03-25 11:51:10 +08:00
{
// 避免重复改变为true带来的无效性能开销
if (signal.imageSequenceOutputComplete)
{
return;
}
// 生成结束的信号标志置为true
signal.imageSequenceOutputComplete = true;
// 构造ffmpeg脚本需要的路径变量(提前到配置)
std::string fileName = "/%dresult.ppm";
2024-04-01 13:45:00 +08:00
setter.filePath.totalImageOutputPath = setter.filePath.deviceSpecFilePath + fileName;
2024-03-26 18:04:18 +08:00
return;
2024-03-25 11:51:10 +08:00
}
// 路径存在性检查,不存在则创建
2024-04-01 13:45:00 +08:00
if (!std::filesystem::exists(setter.filePath.deviceSpecFilePath.c_str()))
{
2024-04-01 13:45:00 +08:00
std::filesystem::create_directories(setter.filePath.deviceSpecFilePath.c_str());
}
// 拼接图片序列编号到路径里
std::string fileName ="/" + std::to_string(savedFrameCounter) + "result.ppm";
2024-04-01 13:45:00 +08:00
setter.filePath.totalImageOutputPath = setter.filePath.deviceSpecFilePath + fileName;
2024-03-26 18:04:18 +08:00
//std::cout << outputPath << std::endl;
// 写入文件
2024-04-01 13:45:00 +08:00
writeImageToFile(setter.filePath.totalImageOutputPath.c_str());
// 写入一帧后已保存帧数+1
2024-03-26 18:04:18 +08:00
savedFrameCounter++;
2024-03-22 18:05:18 +08:00
}
2024-04-01 18:05:17 +08:00
void PlumageRender::imageSequenceToVideo()
{
// 边界条件,图片序列输出未完成
if (!signal.imageSequenceOutputComplete)
{
return;
}
// 边界条件,图片序列到视频的输出已完成
if (signal.imageSequenceToVideoComplete)
{
return;
}
// 拼接视频保存的设备编号路径(提前到配置文件进行)
2024-04-01 13:45:00 +08:00
std::string deviceFilePath = setter.filePath.videoOutputPath + "/device" + std::to_string(selectedPhysicalDeviceIndex);
// 判断路径是否存在,不存在则创建
if (std::filesystem::exists(deviceFilePath.c_str()))
{
std::filesystem::create_directories(deviceFilePath.c_str());
}
// 构造结果视频路径
std::string resultVideoPath = deviceFilePath + "/result.mp4";
// 构造脚本需要参数,图片序列路径和设定的帧率
2024-04-01 13:45:00 +08:00
std::string commandLineImageSequencePath = setter.filePath.totalImageOutputPath;
//std::string commandLineCodecAndResultPath = resultVideoPath;
2024-04-01 13:45:00 +08:00
std::string commandLineFrameRate = std::to_string(setter.settings.videoFrameRate);
// 根据不同系统使用不同脚本
#if defined(_WIN32)
2024-04-01 13:45:00 +08:00
std::string commandLine = setter.filePath.image2videoBatFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath;
#else
std::string commandLine = filePath.image2videoShFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath;
#endif
std::cout << commandLine << std::endl;
std::system(commandLine.c_str());
// 视频输出完成置标志为true
signal.imageSequenceToVideoComplete = true;
std::cout << "vidoe codec complete,saved in:" << resultVideoPath << std::endl;
std::cout << "star to clean up image sequence" << std::endl;
removeImageSequence();
}
2024-04-01 18:05:17 +08:00
void PlumageRender::removeImageSequence()
{
// 函数非第一次运行的边界条件
2024-04-01 13:45:00 +08:00
if (savedFrameCounter != setter.settings.startFrameCount)
{
// 检查视频输出完成的标志位
if (!signal.imageSequenceToVideoComplete)
{
return;
}
}
// 遍历删除图片序列文件和空文件夹
2024-04-01 13:45:00 +08:00
if (std::filesystem::exists(setter.filePath.deviceSpecFilePath))
{
2024-04-01 13:45:00 +08:00
for (const auto& entry : std::filesystem::directory_iterator(setter.filePath.deviceSpecFilePath))
{
if (std::filesystem::is_directory(entry.path()))
{
std::filesystem::remove_all(entry.path());
}
else
{
std::filesystem::remove(entry.path());
}
}
2024-04-01 13:45:00 +08:00
std::filesystem::remove(setter.filePath.deviceSpecFilePath);
std::cout << "clean up complete" << std::endl;
}
return;
}
2024-03-29 18:11:09 +08:00
2024-03-22 18:05:18 +08:00
2024-04-01 18:05:17 +08:00
void PlumageRender::render()
2023-05-17 14:49:05 +08:00
{
2023-06-06 15:52:39 +08:00
if (!prepared) {
return;
}
2024-04-01 13:45:00 +08:00
if (!setter.settings.headless)
2024-03-29 18:11:09 +08:00
{
updateUIOverlay();
}
2024-03-22 18:05:18 +08:00
//加入写到文件的函数
//swapChainImage = swapChain.images[frameIndex];
//outputImageSequeue(swapChainImage,filePath.imageSequenceFilePath);
2024-03-25 11:51:10 +08:00
2024-03-26 18:04:18 +08:00
outputImageSequence();
2024-03-29 18:11:09 +08:00
VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX));
imageSequenceToVideo();
VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex]));
2023-06-06 15:52:39 +08:00
VkResult acquire = swapChain.acquireNextImage(presentCompleteSemaphores[frameIndex], &currentBuffer);
if ((acquire == VK_ERROR_OUT_OF_DATE_KHR) || (acquire == VK_SUBOPTIMAL_KHR)) {
windowResize();
}
else {
VK_CHECK_RESULT(acquire);
2024-03-22 18:05:18 +08:00
2023-06-06 15:52:39 +08:00
}
2024-03-29 18:11:09 +08:00
2023-06-06 15:52:39 +08:00
// Update UBOs
updateUniformBuffers();
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));
const VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = &waitDstStageMask;
submitInfo.pWaitSemaphores = &presentCompleteSemaphores[frameIndex];
submitInfo.waitSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[frameIndex];
submitInfo.signalSemaphoreCount = 1;
submitInfo.pCommandBuffers = &commandBuffers[currentBuffer];
submitInfo.commandBufferCount = 1;
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, waitFences[frameIndex]));
2024-03-22 18:05:18 +08:00
//显示队列
2024-03-29 18:11:09 +08:00
2023-06-06 15:52:39 +08:00
VkResult present = swapChain.queuePresent(queue, currentBuffer, renderCompleteSemaphores[frameIndex]);
if (!((present == VK_SUCCESS) || (present == VK_SUBOPTIMAL_KHR))) {
if (present == VK_ERROR_OUT_OF_DATE_KHR) {
windowResize();
return;
}
else {
VK_CHECK_RESULT(present);
}
}
frameIndex += 1;
frameIndex %= renderAhead;
if (!paused) {
2024-04-01 13:45:00 +08:00
if (setter.settings.rotateModel) {
2023-06-06 15:52:39 +08:00
modelrot.y += frameTimer * 35.0f;
if (modelrot.y > 360.0f) {
modelrot.y -= 360.0f;
}
}
if ((animate) && (models.scene.animations.size() > 0)) {
animationTimer += frameTimer;
if (animationTimer > models.scene.animations[animationIndex].end) {
animationTimer -= models.scene.animations[animationIndex].end;
}
models.scene.updateAnimation(animationIndex, animationTimer);
}
updateShaderData();
2024-04-01 13:45:00 +08:00
if (setter.settings.rotateModel) {
2023-06-06 15:52:39 +08:00
updateUniformBuffers();
}
}
2023-05-17 14:49:05 +08:00
if (camera.updated) {
updateUniformBuffers();
}
2024-03-22 18:05:18 +08:00
2023-05-17 14:49:05 +08:00
}
2024-04-01 18:05:17 +08:00
void PlumageRender::fileDropped(std::string filename)
{
vkDeviceWaitIdle(device);
loadScene(filename);
setupDescriptors();
buildCommandBuffers();
}
2024-04-01 18:05:17 +08:00
// 重构到单独的UI里
void PlumageRender::updateUIOverlay()
2023-05-17 14:49:05 +08:00
{
ImGuiIO& io = ImGui::GetIO();
ImVec2 lastDisplaySize = io.DisplaySize;
2024-04-01 13:45:00 +08:00
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;
2023-06-17 01:18:15 +08:00
bool boolTitleWindowShow = false;
ImGui::NewFrame();
2023-06-17 01:18:15 +08:00
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);
2023-06-07 10:52:04 +08:00
2023-06-17 01:18:15 +08:00
2023-06-17 01:18:15 +08:00
if(gui->beginMainMenuBar()) {
2023-06-19 09:47:00 +08:00
if (gui->beginMenu(chineseUI.menuFile))
2023-06-17 01:18:15 +08:00
{
2023-06-19 09:47:00 +08:00
if (gui->menuItem(chineseUI.menuOpenNewModel))
2023-06-17 01:18:15 +08:00
{
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;
2023-06-17 01:18:15 +08:00
}
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;
2023-06-17 01:18:15 +08:00
}
}
gui->endMenu();
}
2023-06-19 09:47:00 +08:00
if (gui->beginMenu(chineseUI.menuEnvironment))
2023-06-17 01:18:15 +08:00
{
2023-06-19 09:47:00 +08:00
if (gui->beginMenu(chineseUI.menuEnvironmentConfig))
2023-06-17 01:18:15 +08:00
{
if (gui->combo(chineseUI.environmentMap, selectedEnvironment, environments)) {
vkDeviceWaitIdle(device);
loadEnvironment(environments[selectedEnvironment]);
setupDescriptors();
updateCBs = true;
}
2023-06-19 09:47:00 +08:00
if (gui->checkbox(chineseUI.environmentBackGround, &displayBackground)) {
2023-06-17 01:18:15 +08:00
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();
2023-05-25 16:13:37 +08:00
}
2023-06-17 01:18:15 +08:00
if (gui->beginMenu("debug"))
{
2023-06-19 09:47:00 +08:00
if (gui->beginMenu(chineseUI.menuDebugInput))
2023-06-17 01:18:15 +08:00
{
const std::vector<std::string> debugNamesInputs = {
"none", "Base color", "Normal", "Occlusion", "Emissive", "Metallic", "Roughness"
2023-06-17 01:18:15 +08:00
};
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"
2023-06-17 01:18:15 +08:00
};
if (gui->combo(chineseUI.debugPBREquation, &debugViewEquation, debugNamesEquation)) {
shaderData.debugViewEquation = static_cast<float>(debugViewEquation);
updateShaderParams = true;
}
gui->endMenu();
}
2023-06-19 10:09:08 +08:00
2023-06-19 09:47:00 +08:00
if (gui->beginMenu(chineseUI.menuDebugFrameRate))
2023-06-17 01:18:15 +08:00
{
gui->text("%.1d fps (%.2f ms)", lastFPS, (1000.0f / lastFPS));
gui->endMenu();
}
gui->endMenu();
}
2023-06-19 09:47:00 +08:00
if (gui->beginMenu(chineseUI.menuAnimation))
2023-06-17 01:18:15 +08:00
{
if (models.scene.animations.size() > 0)
{
2023-06-19 09:47:00 +08:00
if (gui->beginMenu(chineseUI.menuAnimationActivation))
2023-06-17 01:18:15 +08:00
{
gui->checkbox(chineseUI.pauseAnimation, &animate);
gui->endMenu();
}
2023-06-19 09:47:00 +08:00
if (gui->beginMenu(chineseUI.menuAnimationAnimationSequence))
2023-06-17 01:18:15 +08:00
{
std::vector<std::string> animationNames;
for (auto animation : models.scene.animations) {
animationNames.push_back(animation.name);
}
gui->combo(chineseUI.animationSeq, &animationIndex, animationNames);
gui->endMenu();
}
}
2023-06-17 01:18:15 +08:00
else
{
2023-06-19 09:47:00 +08:00
gui->text(chineseUI.menuAnimationNoAnimation);
2023-06-17 01:18:15 +08:00
}
gui->endMenu();
2023-06-01 16:41:14 +08:00
}
2023-06-19 10:09:08 +08:00
2023-06-17 01:18:15 +08:00
gui->endMainMenuBar();
}
2023-06-17 01:18:15 +08:00
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;
}
2023-06-01 16:41:14 +08:00
// 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();
}
2023-05-17 14:49:05 +08:00
}
2023-05-25 16:27:50 +08:00
2024-04-01 18:05:17 +08:00
// 完全重写避免OS specific
/*
2024-04-01 18:05:17 +08:00
PlumageRender* plumageRender;
2023-06-06 17:18:45 +08:00
#if defined(_WIN32)
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (plumageRender != NULL)
{
plumageRender->handleMessages(hWnd, uMsg, wParam, lParam);
}
return (DefWindowProc(hWnd, uMsg, wParam, lParam));
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
2024-04-01 13:45:00 +08:00
VulkanBackend::Setter setter;
for (int32_t i = 0; i < __argc; i++) {setter.args.push_back(__argv[i]); };
2023-06-06 17:18:45 +08:00
plumageRender = new PlumageRender();
2024-03-29 18:11:09 +08:00
2023-06-06 17:18:45 +08:00
plumageRender->initVulkan();
2024-04-01 13:45:00 +08:00
if (!plumageRender->setter.settings.headless)
2024-03-29 18:11:09 +08:00
{
plumageRender->setupWindow(hInstance, WndProc);
}
2023-06-06 17:18:45 +08:00
plumageRender->prepare();
plumageRender->renderLoop();
delete(plumageRender);
return 0;
}
#endif
*/
int main()
{
PlumageRender* plumageRender;
VulkanBackend::Setter setter;
if (!setter.settings.headless)
{
plumageRender->initWindow(setter.settings.width, setter.settings.height);
plumageRender->initVulkan();
}
return 0;
}