Вопрос о реализации буферизации глубины в Vulkan для многослойных текстур
Я просматриваю руководство по Vulkan и реализовал все, вплоть до текстур. Однако вместо того, чтобы реализовывать каждый пример в руководстве построчно, я пытаюсь разделить конкретные области выполнения на независимые классы. Пока я настраиваю все, что просит учебник, а код компилируется и выполняется без ошибок, буферизация глубины явно не работает и вместо рендеринга одного квадрата с текстурой поверх другого с текстурой, она рендерит их вместе. Я включаю ссылку на свою страницу GitHub, где хранится полная база кода. Ниже показано изображение неправильно отображаемых квадратов, чтобы подчеркнуть неправильное поведение. (Обратите внимание на совмещенный рендеринг в области перекрытия квадратов.)
[img]https://i.sstatic.net /ykDP5va0.png[/img]
Создание менеджера глубины
В этом примере я реализую буферизацию глубины со следующим классом под названием Менеджер глубины. Ниже приведен прототип в файле графики.hpp, а ниже — реализация в файле графики.cpp. Должен сказать, что я также использую библиотеку Vulkan Memory Allocator для управления памятью вместо встроенного распределителя.
Прототип и реализация DepthManager показаны ниже;
DepthManager::DepthManager(AllocatorManager& allocatorManager,
VkDevice device,
VkPhysicalDevice physicalDevice,
VkExtent2D swapChainExtent)
: allocatorManager(allocatorManager),
device(device),
physicalDevice(physicalDevice),
swapChainExtent(swapChainExtent) {
createDepthResources();
}
// --------------------------------------------------------------------------------
DepthManager::~DepthManager() {
if (depthImageView != VK_NULL_HANDLE) {
vkDestroyImageView(device, depthImageView, nullptr);
depthImageView = VK_NULL_HANDLE;
}
if (depthImage != VK_NULL_HANDLE && depthImageMemory != VK_NULL_HANDLE) {
vmaDestroyImage(allocatorManager.getAllocator(), depthImage, depthImageMemory);
depthImage = VK_NULL_HANDLE;
depthImageMemory = VK_NULL_HANDLE;
}
}
// --------------------------------------------------------------------------------
void DepthManager::createDepthResources() {
VkFormat depthFormat = findDepthFormat();
// Create depth image and verify initialization
createImage(swapChainExtent.width, swapChainExtent.height, depthFormat,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
VMA_MEMORY_USAGE_GPU_ONLY, depthImage, depthImageMemory);
// Check if depthImage and depthImageMemory are valid
if (depthImage == VK_NULL_HANDLE || depthImageMemory == VK_NULL_HANDLE) {
throw std::runtime_error("DepthManager: Failed to initialize depth image or memory allocation.");
}
// Create depth image view and verify initialization
depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
// Check if depthImageView is valid
if (depthImageView == VK_NULL_HANDLE) {
throw std::runtime_error("DepthManager: Failed to initialize depth image view.");
}
}
// --------------------------------------------------------------------------------
VkFormat DepthManager::findDepthFormat() {
// Define the list of depth formats to check in order of preference
std::vector depthFormats = {
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_D24_UNORM_S8_UINT
};
// Loop through each candidate format and check for support
for (VkFormat format : depthFormats) {
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);
// Check if this format supports optimal tiling for depth-stencil attachment
if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
return format;
}
}
throw std::runtime_error("failed to find supported depth format!");
}
// --------------------------------------------------------------------------------
VkImageView DepthManager::getDepthImageView() {
return depthImageView;
}
// ================================================================================
bool DepthManager::hasStencilComponent(VkFormat format) {
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
}
// --------------------------------------------------------------------------------
VkFormat DepthManager::findSupportedFormat(const std::vector& candidates,
VkImageTiling tiling, VkFormatFeatureFlags features) {
for (VkFormat format : candidates) {
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);
if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) {
return format;
} else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) {
return format;
}
}
throw std::runtime_error("failed to find supported format!");
}
// --------------------------------------------------------------------------------
void DepthManager::createImage(uint32_t width, uint32_t height, VkFormat format,
VkImageTiling tiling, VkImageUsageFlags usage,
VmaMemoryUsage memoryUsage, VkImage& image,
VmaAllocation& imageMemory) {
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = width;
imageInfo.extent.height = height;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = format;
imageInfo.tiling = tiling;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = usage;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocInfo{};
allocInfo.usage = memoryUsage;
if (vmaCreateImage(allocatorManager.getAllocator(), &imageInfo, &allocInfo, &image, &imageMemory, nullptr) != VK_SUCCESS) {
throw std::runtime_error("failed to create image!");
}
}
// --------------------------------------------------------------------------------
VkImageView DepthManager::createImageView(VkImage image, VkFormat format,
VkImageAspectFlags aspectFlags) {
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = format;
viewInfo.subresourceRange.aspectMask = aspectFlags;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
VkImageView imageView;
if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) {
throw std::runtime_error("failed to create texture image view!");
}
return imageView;
}
Управление глубиной графического конвейера
В этом руководстве также требуется обновить методы createRenderPass и createFrameBuffer, которые являются частью графического конвейера. Для полноты картины Ниже я показываю эти методы с обновлениями.
Вызов экземпляра Vulkan с буферизацией глубины
Проблема может быть связана с порядком, в котором я создаю экземпляры классов, поэтому для полноты картины я также показан ниже конструктор класса VulkanApplication, в котором организовано все приложение. Основная функция показана ниже.
Как я уже говорил, приложение работает, просто оно неправильно реализует DepthBuffering между двумя квадратами, и я не понимаю, почему! Я думаю, проблема либо в том, как написан класс DepthBuffer, либо в том, как он используется для поддержки createRenderPass.
functions, but is may also be in how it is called in the
Конструктор VulkanApplication`, поэтому я также делюсь этими реализациями. По сути, пока кто-то, кто знает лучше меня, не укажет на ошибку, я нахожусь в тупике и буду признателен за любую помощь, которую могу получить. Пожалуйста, не стесняйтесь просмотреть адрес gitub, показанный вверху, если вы считаете, что проблема связана где-то еще.
Вопрос о реализации буферизации глубины в Vulkan для многослойных текстур Я просматриваю руководство по Vulkan и реализовал все, вплоть до текстур. Однако вместо того, чтобы реализовывать каждый пример в руководстве построчно, я пытаюсь разделить конкретные области выполнения на независимые классы. Пока я настраиваю все, что просит учебник, а код компилируется и выполняется без ошибок, буферизация глубины явно не работает и вместо рендеринга одного квадрата с текстурой поверх другого с текстурой, она рендерит их вместе. Я включаю ссылку на свою страницу GitHub, где хранится полная база кода. Ниже показано изображение неправильно отображаемых квадратов, чтобы подчеркнуть неправильное поведение. (Обратите внимание на совмещенный рендеринг в области перекрытия квадратов.) [img]https://i.sstatic.net /ykDP5va0.png[/img]
Создание менеджера глубины В этом примере я реализую буферизацию глубины со следующим классом под названием Менеджер глубины. Ниже приведен прототип в файле графики.hpp, а ниже — реализация в файле графики.cpp. Должен сказать, что я также использую библиотеку Vulkan Memory Allocator для управления памятью вместо встроенного распределителя. Прототип и реализация DepthManager показаны ниже; [code]class DepthManager { public: DepthManager(AllocatorManager& allocatorManager, VkDevice device, VkPhysicalDevice physicalDevice, VkExtent2D swapChainExtent); // --------------------------------------------------------------------------------
// Check if depthImage and depthImageMemory are valid if (depthImage == VK_NULL_HANDLE || depthImageMemory == VK_NULL_HANDLE) { throw std::runtime_error("DepthManager: Failed to initialize depth image or memory allocation."); }
// Check if depthImageView is valid if (depthImageView == VK_NULL_HANDLE) { throw std::runtime_error("DepthManager: Failed to initialize depth image view."); } } // --------------------------------------------------------------------------------
VkFormat DepthManager::findDepthFormat() { // Define the list of depth formats to check in order of preference std::vector depthFormats = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT };
// Loop through each candidate format and check for support for (VkFormat format : depthFormats) { VkFormatProperties props; vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);
// Check if this format supports optimal tiling for depth-stencil attachment if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { return format; } }
throw std::runtime_error("failed to find supported depth format!"); } // --------------------------------------------------------------------------------
VkImageView imageView; if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) { throw std::runtime_error("failed to create texture image view!"); }
return imageView; } [/code] Управление глубиной графического конвейера В этом руководстве также требуется обновить методы createRenderPass и createFrameBuffer, которые являются частью графического конвейера. Для полноты картины Ниже я показываю эти методы с обновлениями. [code]void GraphicsPipeline::createRenderPass(VkFormat swapChainImageFormat) { VkAttachmentDescription colorAttachment{}; colorAttachment.format = swapChainImageFormat; colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
// Correct the attachments array and count std::array attachments = {colorAttachment, depthAttachment};
VkRenderPassCreateInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; renderPassInfo.attachmentCount = static_cast(attachments.size()); // Set to 2 renderPassInfo.pAttachments = attachments.data(); // Point to both color and depth attachments renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; renderPassInfo.dependencyCount = 1; renderPassInfo.pDependencies = &dependency;
if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) { throw std::runtime_error("failed to create render pass!"); } }
void GraphicsPipeline::createFrameBuffers(const std::vector& swapChainImageViews, VkExtent2D swapChainExtent) { // Verify depthImageView is initialized VkImageView depthImageView = depthManager.getDepthImageView(); if (depthImageView == VK_NULL_HANDLE) { throw std::runtime_error("DepthManager depthImageView is not initialized."); } framebuffers.resize(swapChainImageViews.size());
for (size_t i = 0; i < swapChainImageViews.size(); i++) { std::array attachments = { swapChainImageViews[i], depthImageView };
if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &framebuffers[i]) != VK_SUCCESS) { throw std::runtime_error("failed to create framebuffer!"); } } } [/code] Вызов экземпляра Vulkan с буферизацией глубины Проблема может быть связана с порядком, в котором я создаю экземпляры классов, поэтому для полноты картины я также показан ниже конструктор класса VulkanApplication, в котором организовано все приложение. Основная функция показана ниже. [code]GLFWwindow* create_window(uint32_t h, uint32_t w, const std::string& screen_title, bool full_screen) { if (!glfwInit()) { throw std::runtime_error("GLFW Initialization Failed!\n"); }
swapChain = std::make_unique(vulkanLogicalDevice->getDevice(), vulkanInstanceCreator->getSurface(), vulkanPhysicalDevice->getDevice(), this->windowInstance); depthManager = std::make_unique( *allocatorManager, // Dereference unique_ptr vulkanLogicalDevice->getDevice(), vulkanPhysicalDevice->getDevice(), swapChain->getSwapChainExtent() ); //depthManager->createDepthResources(); commandBufferManager = std::make_unique(vulkanLogicalDevice->getDevice(), indices, vulkanPhysicalDevice->getDevice(), vulkanInstanceCreator->getSurface()); samplerManager = std::make_unique( vulkanLogicalDevice->getDevice(), vulkanPhysicalDevice->getDevice() ); samplerManager->createSampler("default"); textureManager = std::make_unique( *allocatorManager, // Dereference unique_ptr vulkanLogicalDevice->getDevice(), vulkanPhysicalDevice->getDevice(), *commandBufferManager, // Dereference unique_ptr vulkanLogicalDevice->getGraphicsQueue(), "../../../data/texture.jpg", *samplerManager ); bufferManager = std::make_unique(vertices, indices, *allocatorManager, *commandBufferManager.get(), vulkanLogicalDevice->getGraphicsQueue()); descriptorManager = std::make_unique(vulkanLogicalDevice->getDevice()); descriptorManager->createDescriptorSets(bufferManager->getUniformBuffers(), textureManager->getTextureImageView(), samplerManager->getSampler("default")); graphicsPipeline = std::make_unique(vulkanLogicalDevice->getDevice(), *swapChain.get(), *commandBufferManager.get(), *bufferManager.get(), *descriptorManager.get(), indices, vulkanPhysicalDevice->getDevice(), std::string("../../shaders/shader.vert.spv"), std::string("../../shaders/shader.frag.spv"), *depthManager); graphicsPipeline->createFrameBuffers(swapChain->getSwapChainImageViews(), swapChain->getSwapChainExtent()); graphicsQueue = this->vulkanLogicalDevice->getGraphicsQueue(); presentQueue = this->vulkanLogicalDevice->getPresentQueue(); } [/code] Как я уже говорил, приложение работает, просто оно неправильно реализует DepthBuffering между двумя квадратами, и я не понимаю, почему! Я думаю, проблема либо в том, как написан класс DepthBuffer, либо в том, как он используется для поддержки createRenderPass.[code]or[/code]createFrameBuffer[code]functions, but is may also be in how it is called in the[/code]Конструктор VulkanApplication`, поэтому я также делюсь этими реализациями. По сути, пока кто-то, кто знает лучше меня, не укажет на ошибку, я нахожусь в тупике и буду признателен за любую помощь, которую могу получить. Пожалуйста, не стесняйтесь просмотреть адрес gitub, показанный вверху, если вы считаете, что проблема связана где-то еще.
Вопрос о реализации буферизации глубины в Vulkan для многослойных текстур
Я просматриваю руководство по Vulkan и реализовал все, вплоть до текстур. Однако вместо того, чтобы реализовывать каждый пример в руководстве построчно, я пытаюсь разделить...
Насколько мне известно, тестирование глубины настроено правильно, однако объекты просто отрисовываются от начала до конца. Я заглянул в графический отладчик и обнаружил, что при рисовании сетки буфер глубины устанавливается в 0 независимо от...