如何将 Vulkan 的场景渲染到 ImGui 窗口

发布于 2025-01-14 05:34:52 字数 2858 浏览 0 评论 0 原文

https://github.com/ocornut/imgui/issues/5110

版本:1.87 分支:对接

后端/渲染器/编译器/操作系统

后端:imgui_impl_Vulkan.cpp + imgui_impl_Vulkan.cpp 操作系统:MacOS

我的问题

如何将 Vulakn 的场景渲染到 ImGui 窗口?

想要实现这个:

image

我已经阅读了各种文档和 #914,但我仍然不知所措。 也许我已经接近答案了? 这是我的项目代码,通过 CMake 快速构建。参考Vulkan教程实现。 也将不胜感激任何帮助,非常感谢。

关键代码是这里

m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_TextureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
...
ImGui::Begin("Viewport");

ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_Dset, ImVec2{viewportPanelSize.x, viewportPanelSize.y});

ImGui::End();

我尝试了几种方法:

  1. 根据这段代码我得到了:
m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_TextureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
...
ImGui::Begin("Viewport");

ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_Dset, ImVec2{viewportPanelSize.x, viewportPanelSize.y});

ImGui::End();

image

  1. 根据这段代码我得到了:
m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_SwapChainImageViews[currentFrame], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); 
// std::vector<VkImageView> m_SwapChainImageViews;
...
ImGui::Begin("Viewport");

ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_Dset, ImVec2{viewportPanelSize.x, viewportPanelSize.y});

ImGui::End();

image

但是当我将 ImGui 窗口拖到主窗口时:

图片

3.最后一次尝试:

// remove m_Dset =  ImGui_ImplVulkan_AddTexture(...);
...
ImGui::Begin("Viewport");

ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_DescriptorSets[currentFrame], ImVec2{viewportPanelSize.x, viewportPanelSize.y});

ImGui::End();

我明白了:

图片

希望你明白我的意思......任何帮助将不胜感激。如果您有时间,可以使用上面提供的项目快速复制它。 我已经被困了好几天了

ps:我正在孜孜不倦地解决学习Vulkan和ImGui时遇到的问题。我因此感冒了。

https://github.com/ocornut/imgui/issues/5110

Version: 1.87
Branch: docking

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_Vulkan.cpp + imgui_impl_Vulkan.cpp
Operating System: MacOS

My Issue/Question:

How to render Vulakn's scene to ImGui window?

want to achieve this:

image

I have read various documents and #914,but I'm still at a loss.
Maybe I'm close to the answer?
Here is my project code, built quickly via CMake. It is implemented with reference to the Vulkan tutorial.
Also would appreciate any help, thanks a lot.

The key code is here:

m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_TextureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
...
ImGui::Begin("Viewport");

ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_Dset, ImVec2{viewportPanelSize.x, viewportPanelSize.y});

ImGui::End();

I tried several ways:

  1. According to this code I got it:
m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_TextureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
...
ImGui::Begin("Viewport");

ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_Dset, ImVec2{viewportPanelSize.x, viewportPanelSize.y});

ImGui::End();

image

  1. According to this code I got it:
m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_SwapChainImageViews[currentFrame], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); 
// std::vector<VkImageView> m_SwapChainImageViews;
...
ImGui::Begin("Viewport");

ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_Dset, ImVec2{viewportPanelSize.x, viewportPanelSize.y});

ImGui::End();

image

But when I drag the ImGui window to the main window:

image

3.last attempt:

// remove m_Dset =  ImGui_ImplVulkan_AddTexture(...);
...
ImGui::Begin("Viewport");

ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
ImGui::Image(m_DescriptorSets[currentFrame], ImVec2{viewportPanelSize.x, viewportPanelSize.y});

ImGui::End();

I got it:

image

Hope you understand what I mean......Any help would be greatly appreciated.It can be quickly reproduced with the items provided above, if you have the time.
I've been stuck for days.

ps: I'm working tirelessly on problems I've encountered while learning Vulkan and ImGui. I have a cold because of it. ????????????????????
I must be low IQ.

I have these variables:

private:
    GLFWwindow *m_Window;
    VkInstance m_Instance;
    VkDebugUtilsMessengerEXT m_DebugMessenger;
    VkPhysicalDevice m_PhysicalDevice = VK_NULL_HANDLE;
    VkDevice m_Device;
    VkQueue m_GraphicsQueue;
    VkQueue m_PresentQueue;
    VkSurfaceKHR m_Surface;
    VkSwapchainKHR m_SwapChain;
    std::vector<VkImage> m_SwapChainImages;
    VkFormat m_SwapChainImageFormat;
    VkExtent2D m_SwapChainExtent;

    std::vector<VkImageView> m_SwapChainImageViews;
    VkRenderPass m_RenderPass;
    VkDescriptorSetLayout m_DescriptorSetLayout;
    VkPipelineLayout m_PipelineLayout;
    VkPipeline m_GraphicsPipeline;
    std::vector<VkFramebuffer> m_SwapChainFramebuffers;
    VkCommandPool m_CommandPool;

    // for imgui
    VkDescriptorPool m_ImGuiDescriptorPool;
    VkRenderPass m_ImGuiRenderPass;
    std::vector<VkFramebuffer> m_ImGuiFramebuffers;
    VkCommandPool m_ImGuiCommandPool;
    std::vector<VkCommandBuffer> m_ImGuiCommandBuffers;

    VkImage m_TextureImage;
    VkDeviceMemory m_TextureImageMemory;
    VkImageView m_TextureImageView;
    VkSampler m_TextureSampler;

    VkImage m_DepthImage;
    VkDeviceMemory m_DepthImageMemory;
    VkImageView m_DepthImageView;

    VkBuffer m_VertexBuffer;
    VkDeviceMemory m_VertexBufferMemory;
    VkBuffer m_IndexBuffer;
    VkDeviceMemory m_IndexBufferMemory;
    // UniformBuffer
    std::vector<VkBuffer> m_UniformBuffers;
    std::vector<VkDeviceMemory> m_UniformBuffersMemory;
    VkDescriptorPool m_DescriptorPool;
    std::vector<VkDescriptorSet> m_DescriptorSets;

    std::vector<VkCommandBuffer> m_CommandBuffers;
    std::vector<VkSemaphore> m_ImageAvailableSemaphores;
    std::vector<VkSemaphore> m_RenderFinishedSemaphores;
    std::vector<VkFence> m_InFlightFences;

    QueueFamilyIndices m_QueueFamilyIndices;

    uint32_t currentFrame = 0;
    uint32_t m_ImageCount = 2;

    VkDescriptorSet m_Dset;
void initVulkan()
    {
        createInstance();
        setupDebugMessenger();
        createSurface();
        pickPhysicalDevice();
        createLogicalDevice();
        createSwapChain();
        createImageViews();
        createRenderPass();
        createDescriptorSetLayout();
        createGraphicsPipeline();
        createCommandPool(&m_CommandPool);
        createDepthResources();
        createFramebuffers();
        createTextureImage();
        createTextureImageView();
        createTextureSampler();
        createVertexBuffer();
        createIndexBuffer();
        createUniformBuffers();
        createDescriptorPool();
        createDescriptorSets();
        createCommandBuffers();
        createSyncObjects();

        IMGUI_CHECKVERSION();
        ImGui::CreateContext();

        ImGuiIO &io = ImGui::GetIO();
        (void)io;
        io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
        io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
        io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;

        ImGui::StyleColorsDark();

        // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
        ImGuiStyle &style = ImGui::GetStyle();
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
        {
            style.WindowRounding = 0.0f;
            style.Colors[ImGuiCol_WindowBg].w = 1.0f;
        }

        {
            VkDescriptorPoolSize pool_sizes[] =
                    {
                            {VK_DESCRIPTOR_TYPE_SAMPLER, 1000},
                            {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000},
                            {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000},
                            {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000},
                            {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000},
                            {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000},
                            {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000},
                            {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000},
                            {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000},
                            {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000},
                            {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000}};

            VkDescriptorPoolCreateInfo pool_info = {};
            pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
            pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
            pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes);
            pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes);
            pool_info.pPoolSizes = pool_sizes;

            if (vkCreateDescriptorPool(m_Device, &pool_info, nullptr, &m_ImGuiDescriptorPool) != VK_SUCCESS)
                throw std::runtime_error("Create DescriptorPool for m_ImGuiDescriptorPool failed!");
        }

        // Create RenderPass for m_ImGuiRenderPass
        {
            createImGuiRenderPass();
        }

        // Create CommandPool for m_ImGuiCommandPool
        {
            createCommandPool(&m_ImGuiCommandPool);
        }

        // Create CommandBuffers for m_ImGuiCommandBuffers
        {
            createImGuiCommandBuffers();
        }

        {
            createImGuiFramebuffers();
        }

        ImGui_ImplGlfw_InitForVulkan(m_Window, true);
        ImGui_ImplVulkan_InitInfo init_info = {};
        init_info.Instance = m_Instance;
        init_info.PhysicalDevice = m_PhysicalDevice;
        init_info.Device = m_Device;
        init_info.QueueFamily = m_QueueFamilyIndices.graphicsFamily.value();
        init_info.Queue = m_GraphicsQueue;
        init_info.PipelineCache = VK_NULL_HANDLE;
        init_info.DescriptorPool = m_ImGuiDescriptorPool;
        init_info.Subpass = 0;
        init_info.MinImageCount = m_ImageCount;
        init_info.ImageCount = m_ImageCount;
        init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
        init_info.Allocator = nullptr;
        init_info.CheckVkResultFn = nullptr;
        ImGui_ImplVulkan_Init(&init_info, m_ImGuiRenderPass);

        // Upload Fonts
        {
            VkCommandBuffer commandBuffer = beginSingleTimeCommands(m_ImGuiCommandPool);
            ImGui_ImplVulkan_CreateFontsTexture(commandBuffer);
            endSingleTimeCommands(commandBuffer, m_ImGuiCommandPool);
            ImGui_ImplVulkan_DestroyFontUploadObjects();
        }

        // m_Dset = ImGui_ImplVulkan_AddTexture(m_TextureSampler, m_TextureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
    }
void drawFrame()
    {
        vkWaitForFences(m_Device, 1, &m_InFlightFences[currentFrame], VK_TRUE, UINT64_MAX);

        uint32_t imageIndex;
        VkResult result = vkAcquireNextImageKHR(m_Device, m_SwapChain, UINT64_MAX, m_ImageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);

        if (result == VK_ERROR_OUT_OF_DATE_KHR)
        {
            recreateSwapChain();
            return;
        }
        else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
        {
            throw std::runtime_error("failed to acquire swap chain image!");
        }

        // Only reset the fence if we are submitting work
        vkResetFences(m_Device, 1, &m_InFlightFences[currentFrame]);

        // vkResetCommandBuffer(m_CommandBuffers[currentFrame], 0);
        recordCommandBuffer(m_CommandBuffers[currentFrame], imageIndex, m_DescriptorSets[currentFrame]);

        {
            // vkResetCommandPool(m_Device, m_ImGuiCommandPool, 0);
            VkCommandBufferBeginInfo info = {};
            info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
            info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
            vkBeginCommandBuffer(m_ImGuiCommandBuffers[currentFrame], &info);

            VkRenderPassBeginInfo renderPassInfo = {};
            renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
            renderPassInfo.renderPass = m_ImGuiRenderPass;
            renderPassInfo.framebuffer = m_ImGuiFramebuffers[imageIndex];
            renderPassInfo.renderArea.offset = {0, 0};
            renderPassInfo.renderArea.extent = m_SwapChainExtent;
            VkClearValue clearColor = {0.0f, 0.0f, 0.0f, 1.0f};
            renderPassInfo.clearValueCount = 1;
            renderPassInfo.pClearValues = &clearColor;
            vkCmdBeginRenderPass(m_ImGuiCommandBuffers[currentFrame], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);

            // Record dear imgui primitives into command buffer
            ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), m_ImGuiCommandBuffers[currentFrame]);

            vkCmdEndRenderPass(m_ImGuiCommandBuffers[currentFrame]);
            vkEndCommandBuffer(m_ImGuiCommandBuffers[currentFrame]);
        }

        updateUniformBuffer(currentFrame);

        VkSubmitInfo submitInfo{};
        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;

        std::array<VkCommandBuffer, 2> submitCommandBuffers =
                {m_CommandBuffers[currentFrame], m_ImGuiCommandBuffers[currentFrame]};
        VkSemaphore waitSemaphores[] = {m_ImageAvailableSemaphores[currentFrame]};
        VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
        submitInfo.waitSemaphoreCount = 1;
        submitInfo.pWaitSemaphores = waitSemaphores;
        submitInfo.pWaitDstStageMask = waitStages;
        submitInfo.commandBufferCount = static_cast<uint32_t>(submitCommandBuffers.size());
        submitInfo.pCommandBuffers = submitCommandBuffers.data();

        VkSemaphore signalSemaphores[] = {m_RenderFinishedSemaphores[currentFrame]};
        submitInfo.signalSemaphoreCount = 1;
        submitInfo.pSignalSemaphores = signalSemaphores;

        if (vkQueueSubmit(m_GraphicsQueue, 1, &submitInfo, m_InFlightFences[currentFrame]) != VK_SUCCESS)
        {
            throw std::runtime_error("failed to submit draw command buffer!");
        }

        VkPresentInfoKHR presentInfo{};
        presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;

        presentInfo.waitSemaphoreCount = 1;
        presentInfo.pWaitSemaphores = signalSemaphores;

        VkSwapchainKHR swapChains[] = {m_SwapChain};
        presentInfo.swapchainCount = 1;
        presentInfo.pSwapchains = swapChains;
        presentInfo.pImageIndices = &imageIndex;
        presentInfo.pResults = nullptr; // Optional

        result = vkQueuePresentKHR(m_PresentQueue, &presentInfo);

        if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || m_FramebufferResized)
        {
            m_FramebufferResized = false;
            recreateSwapChain();
        }
        else if (result != VK_SUCCESS)
        {
            throw std::runtime_error("failed to present swap chain image!");
        }

        currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
    }

void recordCommandBuffer(const VkCommandBuffer &commandBuffer, const uint32_t &imageIndex, const VkDescriptorSet &descriptorSet)
    {
        VkCommandBufferBeginInfo beginInfo{};
        beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
        // beginInfo.flags = 0;                                 // Optional
        // beginInfo.pInheritanceInfo = nullptr; // Optional

        if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS)
        {
            throw std::runtime_error("failed to begin recording command buffer!");
        }

        VkRenderPassBeginInfo renderPassInfo{};
        renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
        renderPassInfo.renderPass = m_RenderPass;
        renderPassInfo.framebuffer = m_SwapChainFramebuffers[imageIndex];
        renderPassInfo.renderArea.offset = {0, 0};
        renderPassInfo.renderArea.extent = m_SwapChainExtent;

        std::array<VkClearValue, 2> clearValues{};
        clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
        clearValues[1].depthStencil = {1.0f, 0};

        renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
        renderPassInfo.pClearValues = clearValues.data();

        vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);

        vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_GraphicsPipeline);

        VkBuffer vertexBuffers[] = {m_VertexBuffer};
        VkDeviceSize offsets[] = {0};
        vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);

        vkCmdBindIndexBuffer(commandBuffer, m_IndexBuffer, 0, VK_INDEX_TYPE_UINT16);
        vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_PipelineLayout, 0, 1, &descriptorSet, 0, nullptr);

        vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);

        vkCmdEndRenderPass(commandBuffer);

        if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS)
        {
            throw std::runtime_error("failed to record command buffer!");
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

日久见人心 2025-01-21 05:34:53

对我来说,图像只是没有在 ImGui::Image 中渲染,我不知道为什么。我在着色器输入中看到了我的图像,但在着色器输出中我只有黑色。
我想在你的情况下你应该将场景渲染到另一个图像(不是交换链图像)。这意味着您需要使用另一个渲染通道。仅将交换链图像用于 imgui 输出。

For me image just not rendering in ImGui::Image and i don't know why. I saw my image in shader inputs, but in shader outputs i had just black color.
I guess in your case you should render your scene to another image (not swapchain image). And it means that you need to use another render pass for it. Use swapchain images only for imgui output.

没︽人懂的悲伤 2025-01-21 05:34:53

我认为当我们 createSwapChain();

VkSurfaceFormatKHR surfaceFormat;
surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM;
surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;

这样设置时可以避免验证错误!

I think when we createSwapChain(); set

VkSurfaceFormatKHR surfaceFormat;
surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM;
surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;

like this to avoid validation error!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文