图像视图
在渲染管线中使用VkImage
对象(包括交换链中的图像),都必须创建一个绑定到图像的VkImageView
才能访问它。图像视图描述了访问图像的方式,以及图像的哪一部分可以被访问,比如,可以描述为一个没有mipmapping
的二维深度纹理,进而可以对其进行二维深度纹理相关的操作。
我们添加createImageViews
函数来为交换链中的每一个图像建立图像视图。
首先,添加用于存储图像视图的类成员变量:
std::vector<VkImageView> swapChainImageViews;
然后,添加createImageViews
函数,并在initVulkan
中调用它:
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++代码