图像视图

要在渲染管线中使用任何 VkImage,包括交换链中的那些,我们必须创建一个 VkImageView 对象。图像视图字面上就是图像的视图。它描述了如何访问图像以及访问图像的哪一部分,例如,如果它应该被视为没有任何 mipmap 级别的 2D 纹理深度纹理。

在本章中,我们将编写一个 createImageViews 函数,为交换链中的每个图像创建基本图像视图,以便我们稍后将它们用作颜色目标。

首先添加一个类成员来存储图像视图

std::vector<VkImageView> swapChainImageViews;

创建 createImageViews 函数并在交换链创建后立即调用它。

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

void createImageViews() {

}

我们需要做的第一件事是调整列表的大小,以适应我们将要创建的所有图像视图

void createImageViews() {
    swapChainImageViews.resize(swapChainImages.size());

}

接下来,设置一个循环,遍历所有交换链图像。

for (size_t i = 0; i < swapChainImages.size(); i++) {

}

图像视图创建的参数在 VkImageViewCreateInfo 结构中指定。前几个参数很简单。

VkImageViewCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
createInfo.image = swapChainImages[i];

viewTypeformat 字段指定应如何解释图像数据。 viewType 参数允许您将图像视为 1D 纹理、2D 纹理、3D 纹理和立方体贴图。

createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
createInfo.format = swapChainImageFormat;

components 字段允许您对颜色通道进行混合。例如,您可以将所有通道映射到单色纹理的红色通道。您还可以将常量值 01 映射到通道。在我们的例子中,我们将坚持默认映射。

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;

subresourceRange 字段描述了图像的用途以及应访问图像的哪一部分。我们的图像将用作颜色目标,没有任何 mipmap 级别或多个图层。

createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
createInfo.subresourceRange.baseMipLevel = 0;
createInfo.subresourceRange.levelCount = 1;
createInfo.subresourceRange.baseArrayLayer = 0;
createInfo.subresourceRange.layerCount = 1;

如果您正在开发立体 3D 应用程序,那么您将创建一个具有多个图层的交换链。然后,您可以为每个图像创建多个图像视图,通过访问不同的图层来表示左眼和右眼的视图。

创建图像视图现在只是调用 vkCreateImageView 的问题

if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
    throw std::runtime_error("failed to create image views!");
}

与图像不同,图像视图是我们明确创建的,因此我们需要添加一个类似的循环,在程序结束时再次销毁它们

void cleanup() {
    for (auto imageView : swapChainImageViews) {
        vkDestroyImageView(device, imageView, nullptr);
    }

    ...
}

图像视图足以开始将图像用作纹理,但它还没有完全准备好用作渲染目标。这需要一个额外的间接步骤,称为帧缓冲。在接下来的章节中,我们将不得不设置图形管线。