使用颜色和深度附件准备渲染过程和帧缓冲
译者注:示例代码点击此处
渲染3D场景通常不仅涉及颜色附件,还涉及用于深度测试的深度附件(我们希望更靠近相机的物体遮挡更多物体)。
在本节中,我们将看到如何为颜色和深度数据创建图像,以及使用单个子过程创建渲染过程,渲染为颜色和深度附件。 我们还将创建一个帧缓冲区,它将两个图像用于渲染过程附件。
做好准备...
与本章的早期内容一样,在本节中,我们将使用SubpassParameters类型的自定义结构(请参阅指定子过程描述内容)。
怎么做...
1.使用VK_FORMAT_R8G8B8A8_UNORM格式以及VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT 或 VK_IMAGE_USAGE_SAMPLED_BIT用法和VK_IMAGE_ASPECT_COLOR_BIT方面创建2D图像和图像视图。选择图像的其余参数, 将创建的句柄存储在名为color_image的VkImage类型的变量中,名为color_image_memory_object的VkDeviceMemory的类型变量以及名为color_image_view的VkImageView类型变量(请参阅第4章创建2D图像和视图和资源和内存内容)。
2.使用VK_FORMAT_D16_UNORM格式以及VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT或VK_IMAGE_USAGE_SAMPLED_BIT用法和VK_IMAGE_ASPECT_DEPTH_BIT方面创建2D图像和图像视图,与其句柄存储在color_image变量中的图像大小相同。选择图像的其余参数, 将创建的句柄存储在名为depth_image的VkImage类型的变量中,名为depth_image_memory_object的VkDeviceMemory的类型变量以及名为depth_image_view的VkImageView类型变量(请参阅第4章创建2D图像和视图和资源和内存内容)。
3.创建一个名为attachments_descriptions的std::vector<VkAttachmentDescription>类型变量,并向向量添加两个元素。 使用以下值初始化第一个元素:
·flags为0
·format为VK_FORMAT_R8G8B8A8_UNORM
·samples为VK_SAMPLE_COUNT_1_BIT
·loadOp为VK_ATTACHMENT_LOAD_OP_CLEAR
·storeOp为VK_ATTACHMENT_STORE_OP_STORE
·stencilLoadOp为VK_ATTACHMENT_LOAD_OP_DONT_CARE
·stencilStoreOp为VK_ATTACHMENT_STORE_OP_DONT_CARE
·initialLayout为VK_IMAGE_LAYOUT_UNDEFINED
·finalLayout为VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
4.使用这些值初始化attachments_descriptions向量的第二个元素的成员:
·flags为0
·format为VK_FORMAT_D16_UNORM
·samples为VK_SAMPLE_COUNT_1_BIT
·loadOp为VK_ATTACHMENT_LOAD_OP_CLEAR
·storeOp为VK_ATTACHMENT_STORE_OP_STORE
·stencilLoadOp为VK_ATTACHMENT_LOAD_OP_DONT_CARE
·stencilStoreOp为VK_ATTACHMENT_STORE_OP_DONT_CARE
·initialLayout为VK_IMAGE_LAYOUT_UNDEFINED
·finalLayout为VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
5.创建一个名为depth_stencil_attachment的VkAttachmentReference类型的变量,并使用以下值初始化它:
·attachment为1
·layout为VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
6.创建一个名为subpass_parameters的std::vector<SubpassParameters>类型变量,向此向量添加单个元素并使用以下值对其进行初始化:
·PipelineType为VK_PIPELINE_BIND_POINT_GRAPHICS
·为ColorAttachments添加一个具有如下值的元素:
1.attachment为0
2.layout为VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
·ResolveAttachments为一个空向量
·DepthStencilAttachment为指向depth_stencil_attachment的指针
·PreserveAttachments为一个空向量
7.创建一个名为subpass_dependencies的std::vector<VkSubpassDependency>类型向量,并使用以下值初始化单个元素:
·srcSubpass为0
·dstSubpass为VK_SUBPASS_EXTERNAL
·srcStageMask为VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
·dstStageMask为VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
·srcAccessMask为VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
·dstAccessMask为VK_ACCESS_SHADER_READ_BIT
·dependencyFlags为0
8.使用attachments_descriptions,subpass_parameters和subpass_dependencies向量创建渲染过程。 将创建的渲染过程句柄存储在名为render_pass的VkRenderPass类型的变量中(请参阅本章中的创建渲染过程内容)。
9.使用render_pass变量和color_image_view变量为其第一个附件创建帧缓冲,并为第二个附件创建depth_image_view变量。 指定与color_image和depth_image变量使用的尺寸相同的尺寸。 将创建的framebuffer句柄存储在名为framebuffer的VkFramebuffer类型的变量中。
这个怎么运作...
在此节中,我们要渲染为两个图像 - 一个用于颜色数据,另一个用于深度数据。 我们暗示在渲染过程之后它们将被用作纹理(将在另一个渲染过程中在着色器中对它们进行采样); 这就是为什么它们是用COLOR_ATTACHMENT / DEPTH_STENCIL_ATTACHMENT用法创建的(所以我们可以渲染它们)和SAMPLED用法(所以它们都可以从着色器中采样):
if( !Create2DImageAndView( physical_device, logical_device, VK_FORMAT_R8G8B8A8_UNORM, { width, height }, 1, 1, VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_ASPECT_COLOR_BIT, color_image, color_image_memory_object, color_image_view ) ) {
return false;
}
if( !Create2DImageAndView( physical_device, logical_device, VK_FORMAT_D16_UNORM, { width, height }, 1, 1, VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_ASPECT_DEPTH_BIT, depth_image, depth_image_memory_object, depth_image_view ) ) {
return false;
}
接下来,我们为渲染过程指定两个附件。 它们都在渲染过程开始时被清除,并且它们的内容在渲染过程之后被保留:
std::vector<VkAttachmentDescription> attachments_descriptions = {
{
0,
VK_FORMAT_R8G8B8A8_UNORM,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
},
{
0,
VK_FORMAT_D16_UNORM,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
}
};
下一步是定义单个子过程。 它使用第一个附件进行颜色写入,使用第二个附件进行深度/模板数据:
VkAttachmentReference depth_stencil_attachment = {
1,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
};
std::vector<SubpassParameters> subpass_parameters = {
{
VK_PIPELINE_BIND_POINT_GRAPHICS,
{},
{
{
0,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
}
},
{},
&depth_stencil_attachment,
{}
}
};
最后,我们定义子过程和渲染过程后将执行的命令之间的依赖关系。 这是必需的,因为我们不希望其他命令在其内容完全写入渲染过程之前开始读取我们的图像。 我们还创建了渲染过程和帧缓冲:
std::vector<VkSubpassDependency> subpass_dependencies = {
{
0, // uint32_t srcSubpass
VK_SUBPASS_EXTERNAL, // uint32_t dstSubpass
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask
VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask
0 // VkDependencyFlags dependencyFlags
}
};
if( !CreateRenderPass( logical_device, attachments_descriptions, subpass_parameters, subpass_dependencies, render_pass ) ) {
return false;
}
if( !CreateFramebuffer( logical_device, render_pass, { color_image_view, depth_image_view }, width, height, 1, framebuffer ) ) {
return false;
}
return true;