Vulkan Cookbook 第六章 7 使用颜色和深度附件准备渲染过程和帧缓冲

使用颜色和深度附件准备渲染过程和帧缓冲

译者注:示例代码点击此处

渲染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;

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Computer graphics have a very long and interesting history. Many APIs or custom approaches to the generation of 2D or 3D images have come and gone. A landmark in this history was the invention of OpenGL, one of the first graphics libraries, which allowed us to create real-time, high-performance 3D graphics, and which was available for everyone on multiple operating systems. It is still developed and widely used even today. And this year we can celebrate its 25th birthday! But many things have changed since OpenGL was created. The graphics hardware industry is evolving very quickly. And recently, to accommodate these changes, a new approach to 3D graphics rendering was presented. It took the form of a low-level access to the graphics hardware. OpenGL was designed as a high-level API, which allows users to easily render images on screen. But this high-level approach, convenient for users, is difficult for graphics drivers to handle. This is one of the main reasons for restricting the hardware to show its full potential. The new approach tries to overcome these struggles–it gives users much more control over the hardware, but also many more responsibilities. This way application developers can release the full potential of the graphics hardware, because the drivers no longer block them. Low-level access allows drivers to be much smaller, much thinner. But these benefits come at the expense of much more work that needs to done by the developers. The first evangelist of the new approach to graphics rendering was a Mantle API designed by AMD. When it proved that low-level access can give considerable performance benefits, other companies started working on their own graphics libraries. One of the most notable representatives of the new trend were Metal API, designed by Apple, and DirectX 12, developed by Microsoft. But all of the above libraries were developed with specific operating systems and/or hardware in mind. There was no open and multiplatform standard such as OpenGL. Until last year. Year 2016 saw the release of the Vulkan API, developed by Khronos consortium, which maintains the OpenGL library. Vulkan also represents the new approach, a low-level access to the graphics hardware, but unlike the other libraries it is available for everyone on multiple operating systems and hardware platforms–from high-performance desktop computers with Windows or Linux operating systems, to mobile devices with Android OS. And as it is still being very new, there are few resources teaching developers how to use it. This book tries to fill this gap.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值