在过去的几章中,我们已经讨论了很多帧缓冲区,我们已经设置了渲染过程,以期望单个帧缓冲区具有与交换链图像相同的格式,但我们实际上还没有创建任何帧缓冲区。
通过将渲染过程创建期间指定的附件包装到VkFramebuffer对象中来绑定它们。帧缓冲区对象引用表示附件的所有VkImageView对象。在我们的案例中,只有一个:颜色附件。然而,我们必须用于附件的图像取决于当我们检索一个图像以进行演示时交换链返回的图像。这意味着我们必须为交换链中的所有图像创建一个帧缓冲区,并在绘图时使用与检索到的图像相对应的帧缓冲区。
为此,创建另一个std::vector类成员来保存帧缓冲区:
std::vector<VkFramebuffer> swapChainFramebuffers;
我们将在创建图形管道后立即从initVulkan调用的新函数createFramebuffers中为该数组创建对象:
void initVulkan() {
createInstance();
setupDebugMessenger();
createSurface();
pickPhysicalDevice();
createLogicalDevice();
createSwapChain();
createImageViews();
createRenderPass();
createGraphicsPipeline();
createFramebuffers();
}
...
void createFramebuffers() {
}
首先调整容器大小以容纳所有帧缓冲区:
void createFramebuffers() {
swapChainFramebuffers.resize(swapChainImageViews.size());
}
然后,我们将遍历图像视图并从中创建帧缓冲区:
for (size_t i = 0; i < swapChainImageViews.size(); i++) {
VkImageView attachments[] = {
swapChainImageViews[i]
};
VkFramebufferCreateInfo framebufferInfo{};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = renderPass;
framebufferInfo.attachmentCount = 1;
framebufferInfo.pAttachments = attachments;
framebufferInfo.width = swapChainExtent.width;
framebufferInfo.height = swapChainExtent.height;
framebufferInfo.layers = 1;
if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
throw std::runtime_error("failed to create framebuffer!");
}
}
如您所见,帧缓冲区的创建非常简单。我们首先需要指定帧缓冲区需要与哪个renderPass兼容。只能在与之兼容的渲染过程中使用帧缓冲区,这大致意味着它们使用相同数量和类型的附件。
attachmentCount和pAttachments参数指定应绑定到渲染过程pAttachment数组中相应附件描述的VkImageView对象。
宽度和高度参数是不言自明的,层是指图像阵列中的层数。我们的交换链图像是单个图像,因此层数为1。
我们应该在图像视图和渲染过程之前删除它们所基于的帧缓冲区,但仅在完成渲染之后:
void cleanup() {
for (auto framebuffer : swapChainFramebuffers) {
vkDestroyFramebuffer(device, framebuffer, nullptr);
}
...
}
现在我们已经达到了一个里程碑,我们拥有了渲染所需的所有对象。在下一章中,我们将编写第一个实际的绘图命令。