Depth buffer

When you want to render a whole scene or at least more complex geometry, there can certainly be cases of occlusion. Therefore you will either need to manually sort your geometry manually before rendering or you take advantage of a depth buffer storing the distance between your geometry and the position of the camera.

In Vulkan that means you will need to create a depth buffer in the size of your rendering resolution and attach it to the graphics pipeline as target. In the following example code the depth buffer is created dynamically in the main loop to adjust in case the resolution changes. This is necessary if you want to use windows which allow resizing during runtime (not just for a depth buffer but also for other images depending on the current render resolution).

vkcv::ImageHandle depthBuffer; // uninitialized depth buffer

core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt,
             uint32_t swapchainWidth, uint32_t swapchainHeight) {
  // check whether a depth buffer is not created yet or resolution mismatches
  if ((!depthBuffer) ||
      (swapchainWidth != core.getImageWidth(depthBuffer)) ||
      (swapchainHeight != core.getImageHeight(depthBuffer))) {
    // create depth buffer
    depthBuffer = core.createImage(
      vk::Format::eD32Sfloat, // format of the depth buffer
      vkcv::ImageConfig(
        swapchainWidth,       // width of the current swapchain image
        swapchainHeight       // height of the current swapchain image
      )
    );
  }
  
  // rendering with the depth buffer
});

A bit confusing might be the wording here. It's called "depth buffer" but the code seems to create an image. That is correct though because similar to buffers those images are only abstractions to address certain parts of memory on the GPU. However because images are usually addressed by their individual pixels or interpolated values between those, they got a different naming. There are also other reasons like image formats to allow special compression being used for example. For the start those differences aren't important though. Just notice that images used as render targets are usually called "buffers" in other computer graphics sources.

The most important part about the depth buffer creation is the format though. In Vulkan there are specific image formats defined to store depth values. Others can't be used as attached render target for depth values in a graphics pipeline.

In most cases you can use vk::Format::eD32Sfloat to store only depth values in 32bit floating-point precision. There are widely supported formats which also offer to store a stencil buffer as well by only using 24bit floating-point precision for the depth values and leaving 8bit for the stencil values. However the stencil buffer has far less usecases in practice. So you will likely not need it.

Notice that you will need to add the used format to the list of formats for render pass creation which specifies what your attached render targets will be like during rendering. For example to add the depth buffer as attachment later it should look similar to this:

vkcv::PassHandle renderPass = vkcv::passSwapchain(
  core,                  // the core instance
  window.getSwapchain(), // the swapchain from the window
  {
    vk::Format::eUndefined, // the format of the swapchain image
    vk::Format::eD32Sfloat  // the format of the depth buffer
  }
);

Previous

Next

Popular posts from this blog

Introduction

Application development

First setup