ETH官方钱包

前往
大廳
主題

看圖學Vulkan,Window resize功能,附github連結(jié)

%%鼠 拒收病婿 | 2024-12-21 13:18:36 | 巴幣 136 | 人氣 69

在上一篇,我們在一個固定大小的視窗畫了個三角形,今天要講怎麼把window變成resizeable。

Swapchain recreation

在Vulkan中,當窗口大小改變時,需要重新創(chuàng)建swap chain,這是因為swap chain與窗口的尺寸和格式密切相關(guān)。當窗口大小改變時,原有的swap chain可能不再適用於新的窗口尺寸,這會導(dǎo)致渲染結(jié)果不正確或無法顯示。

具體來說,swap chain包含了一組圖像,這些圖像用於在屏幕上顯示渲染結(jié)果。這些圖像的大小和格式是根據(jù)窗口的初始尺寸設(shè)置的。如果窗口大小改變,這些圖像也需要相應(yīng)地調(diào)整大小,否則會出現(xiàn)圖像失真或無法正確顯示的情況。因此,需要重新創(chuàng)建swap chain來適應(yīng)新的窗口尺寸。

此外,重新創(chuàng)建swap chain還涉及到重新創(chuàng)建與之相關(guān)的其他資源,如圖像視圖(image views)和幀緩衝區(qū)(framebuffers),以確保整個渲染管線能夠正常工作。

他們之間的關(guān)聯(lián)如下圖:
  • Swapchain的圖片跟image buffer有關(guān)聯(lián)。
  • RenderPass的渲染目標須指定frame buffer。
  • 由於surface大小改變,牽扯到image的需重新創(chuàng)立。

Dynamic viewport

動態(tài)視口允許你在渲染過程中改變視口的大小和位置,而不需要重新創(chuàng)建或修改pipeline。
//-------------------
//    Dynamic
//-------------------
// While most of the pipeline state needs to be baked into the pipeline state, a limited amount of
// the state can actually be changed without recreating the pipeline at draw time. Examples are the
// size of the viewport, line width and blend constants.
// This will cause the configuration of these values to be ignored and you will be able (and required)
// to specify the data at drawing time.
std::vector<VkDynamicState> dynamicStates = {
    VK_DYNAMIC_STATE_VIEWPORT,
    VK_DYNAMIC_STATE_SCISSOR
};

VkPipelineDynamicStateCreateInfo dynamicState{};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size());
dynamicState.pDynamicStates = dynamicStates.data();
VkPipelineViewportStateCreateInfo viewportState{};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.scissorCount = 1;

Window resize觸發(fā)

header:
namespace ltn {
    class DisplayWindow {
    private:
        static void framebufferResizeCallback(GLFWwindow* window, int width, int height);
};

}

cpp
void ltn::DisplayWindow::init_window()
{
    // Init window
    glfwInit();
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);

    this->window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "test window", nullptr, nullptr);
    glfwSetWindowUserPointer(window,this);
    glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
}

void ltn::DisplayWindow::framebufferResizeCallback(GLFWwindow* window, int width, int height)
{
    auto ltnWindow = reinterpret_cast<DisplayWindow*>(glfwGetWindowUserPointer(window));
    ltnWindow->SCR_WIDTH = width;
    ltnWindow->SCR_HEIGHT = height;
    ltnWindow->frameBufferedResized = true;

}

在main loop中:
因為有設(shè)定dynamic viewport,因此pipeline無須重建。
while (main_window.is_window_alive())
{
    glfwPollEvents();
    
    // Detect resize :
    if (main_window.frameBufferedResized) {
        main_window.frameBufferedResized = false;
        vkDeviceWaitIdle(coreInstance.get_device());
        swapchain->cleanup();
        forward_renderer_pass->cleanup();
        
        swapchain = std::make_unique<ltn::SwapChain>(coreInstance, main_window.SCR_WIDTH, main_window.SCR_HEIGHT);
        forward_renderer_pass = std::make_unique<ltn::Renderer>(coreInstance, *swapchain);
        /*
        pipeline = std::make_unique<ltn::GraphicsPipeline>(coreInstance, *swapchain);
        pipeline->create_pipleine(
            forward_renderer_pass->get_renderPass(),
            nullptr
            //gameobject.get_all_descriptorLayouts()
        );
        */

    }
}

此git在main function的resize方法重複建了pipeline,可以註解掉。
送禮物贊助創(chuàng)作者 !
0
留言

創(chuàng)作回應(yīng)

更多創(chuàng)作