为了能够使用 VkImage,包括交换链中的在内,我们需要在渲染管线中创建 VkImageView。一个图像视图真的就是字面意思的图像的视图。它描述了如何访问这个图像以及访问这个图像的哪个部分,例如图像可能被当作不需要 Mipmap 的二维深度贴图

创建图像视图

首先还是先定义一个成员变量用于保存图像视图

std::vector<VkImageView> swapchainImageViews;

添加一个成员函数用于创建图像视图,并在 initVulkan 中调用它

void initVulkan() {
    createInstance();
    createSurface();
    pickPhysicalDevice();
    createLogicalDevice();
    createSwapchain();
    createImageViews();
}

void createImageViews() {

}

我们需要为每一个图像都创建一个图像视图

对于一个图像视图,填充它的创建信息就行了

void createImageViews() {
    swapchainImageViews.resize(swapchainImages.size());
    for (size_t i = 0; i < swapchainImages.size(); i++) {
        VkImageViewCreateInfo createInfo = {};
        createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        createInfo.image = swapchainImages[i];
        createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
        createInfo.format = swapchainImageFormat;
        createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        createInfo.subresourceRange.baseMipLevel = 0;
        createInfo.subresourceRange.levelCount = 1;
        createInfo.subresourceRange.baseArrayLayer = 0;
        createInfo.subresourceRange.layerCount = 1;
        if (vkCreateImageView(device, &createInfo, nullptr, &swapchainImageViews[i]) != VK_SUCCESS)
            throw std::runtime_error("failed to create image views!");
    }
}

稍微解释一下创建信息的成员

viewTypeformat 指定了图像数据应当如何被解释

components 允许我们进行颜色通道的映射,比如把红色通道映射到所有的通道来实现黑白纹理,也可以为一个通道映射一个常量,当然我们这里使用了默认映射

subresourceRange 描述了图像的目的以及应当访问图像的哪一个部分,我们的图像将会被用于不需要 Mipmap 也不需要多层的颜色目标。但如果需要开发立体三维应用,我们应当创建一个多层的交换链,并为图像创建多层图像视图,通过访问不同的层来代表左眼和右眼

销毁图像视图

编辑 cleanup 函数

void cleanup() {
    for (auto imageView : swapchainImageViews)
        vkDestroyImageView(device, imageView, nullptr);
    vkDestroySwapchainKHR(device, swapchain, nullptr);
    vkDestroyDevice(device, nullptr);
    vkDestroySurfaceKHR(instance, surface, nullptr);
    vkDestroyInstance(instance, nullptr);

    glfwDestroyWindow(window);
    glfwTerminate();
}