狸村 Mystic Web · 狸村

要在渲染管线中使用任何 vk::Image(包括交换链中的图像),我们必须创建一个 vk::raii::ImageView 对象。图像视图字面意思就是图像的一个视图。它描述了如何访问图像以及访问图像的哪个部分,例如,是否应将其视为没有任何 mipmap 级别的 2D 纹理深度纹理。

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

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

std::vector<vk::raii::ImageView> swapChainImageViews;

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

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

void createImageViews()
{
}

图像视图创建的参数在 vk::ImageViewCreateInfo 结构体中指定。对于每个图像视图,viewTypeformatsubresourceRange 都是相同的。

通过 viewType,我们指定要渲染到 2D 屏幕。如果我们想要渲染到 3D 屏幕或立方体贴图,这些也是选项,1D 屏幕也是。你可能已经猜到,在大多数情况下,当我们渲染到屏幕时,我们希望使用 2D 渲染目标。

接下来,我们指定图像格式;这决定了颜色空间分量的配置方式,以便在渲染中获得正确的颜色格式。

接下来,components 字段对于我们的交换链来说不是必需的;但我们稍后会讨论它。

最后一个成员是 subresourceRange,它是必需的,我们稍后会讨论。

void createImageViews()
{
    assert(swapChainImageViews.empty());

    vk::ImageViewCreateInfo imageViewCreateInfo{ .viewType         = vk::ImageViewType::e2D,
                                                 .format           = swapChainSurfaceFormat.format,
                                                 .subresourceRange = { vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1 } };
}

components 字段允许你重新排列颜色通道。例如,你可以将所有通道映射到红色通道以创建单色纹理。你也可以将常量值 01 映射到某个通道。在我们的例子中,我们将使用默认映射(接受构造的默认值),但下面是如何显式设置的方法:

imageViewCreateInfo.components = {
    vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity};

subresourceRange 字段描述图像的用途以及应访问图像的哪个部分。我们的图像将用作颜色目标,没有任何 mipmap 级别或多层。 注意:你可以像上面代码片段那样列出 subresourceRange 的所有元素,或者使用指定初始化器仅初始化那些与默认值不同的成员,如下所示:

imageViewCreateInfo.subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1};

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

你应该期望显卡能够处理的最大多个图像视图数量是 16。这种配置涵盖了大多数标准用例,VR/AR 头显通常需要的并发视图不超过四个。然而,光场显示器和 CAVE 显示器可能需要不同的解决方案,因为它们对并发视图的需求可能数以千计。这些特殊的渲染需求超出了本教程的范围,但即使是这些用例,也可以使用我们在此描述的相同结构和技术进行渲染。

接下来,设置循环遍历所有交换链图像,并将它们添加到我们的结构体中。

for (auto &image : swapChainImages)
{
    imageViewCreateInfo.image = image;
}

创建图像视图现在只需使用 vk::raii::CreateImageView 的构造函数,这里通过 std::vector::emplace_back 来实现:

for (auto &image : swapChainImages)
{
    imageViewCreateInfo.image = image;
    swapChainImageViews.emplace_back( device, imageViewCreateInfo );
}

图像视图足以开始将图像用作纹理,但它还不能用作渲染目标。这还需要一步,称为帧缓冲。在接下来的章节中,我们将必须设置图形管线。

Vulkan 是 Khronos Group Inc. 的注册商标

教程内容版权归原作者,遵循 CC BY-SA 4.0;本站独立代码及设计除外。