图像视图

使用任何VkImage对象,包括处于交换链中的,处于渲染管线中的,都需要我们创建一个VkImageView对象来绑定访问它。图像视图描述了访问图像的方式,以及图像的哪一部分可以被访问。比如,图像可以被图像视图描述为一个没有细化级别的二维深度纹理,进而可以在其上进行与二维深度纹理相关的操作。

在本章节,我们编写了一个叫做createImageViews的函数来为交换链中的每一个图像建立图像视图。

首先,添加用于存储图像视图的成员变量:

std::vector<VkImageView> swapChainImageViews;

然后,添加createImageViews函数,并在initVulkan函数调用createSwapChain函数创建交换链之后调用它:

void initVulkan() {
    createInstance();
    setupDebugCallback();
    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];

viewType和format成员变量用于指定图像数据的解释方式。viewType成员变量用于指定图像被看作是一维纹理、二维纹理、三维纹理还是立方体贴图。

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

components成员变量用于进行图像颜色通道的映射。比如,对于单色纹理,我们可以将所有颜色通道映射到红色通道。我们也可以直接将颜色通道的值映射为常数0或1。在这里,我们只使用默认的映射:

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成员变量用于指定图像的用途和图像的哪一部分可以被访问。在这里,我们的图像被用作渲染目标,并且没有细分级别,只存在一个图层:

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

如果读者在编写VR一类的应用程序,可能会使用支持多个层次的交换链。这时,读者应该为每个图像创建多个图像视图,分别用来访问左眼和右眼两个不同的图层。

调用vkCreateImageView函数创建图像视图:

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

和交换链图像不同,图像视图是由我们自己显式创建的,需要我们自己在cleanup函数中清除它们:

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

        ...
}

有了图像视图,就可以将图像作为纹理使用,但作为渲染目标,还需要帧缓冲对象。接下来的章节,我们会简要介绍渲染管线,然后介绍帧缓冲对象。

本章节代码:

C++:

https://vulkan-tutorial.com/code/07_image_views.cpp