New Render Pass
We need a render pass with a depth attachment for rendering a 3d model.
The majority of render pass creation is pretty much the same as we did before, and it only differs that we attach an extra depth attachment. The stencilLoadOp
and stencilStoreOp
both being VK_ATTACHMENT_LOAD_OP_DONT_CARE
indicates we do not have stencil buffer and because we don’t care about the content of depth attachment after a render pass instance is completed, storeOp
is also VK_ATTACHMENT_LOAD_OP_DONT_CARE
.
New Scene
EarthScene
creates an EarthSceneRenderer
which draws the rotating earth with Phong shading. In the update loop of the scene, it updates the model, view, and projection matrices of the earth with UpdateMVP
.
New Scene Renderer
Constructor
EarthSceneRenderer
contains Model
(s)/ModelResource
(s) to render, Texture2D
(s) applied to the models, a VkSampler
controlling how to sample textures, Buffer
(s) storing the transform matrices about a model(s) and lighting related information. The depth image, memory, and image view are used for depth test. CommandBuffers
records scene-dependent commands and submits them to a queue. And, _application
is a typeless pointer to the application context.
Besides, descriptor and pipeline are concepts we have not mentioned, we‘ll check them out in the next article.
Instance and surface creation are the same as what EmptyScene
did. For the scene, we request the feature samplerAnisotropy
for a better quality of textures on surfaces that are at oblique viewing angles with respect to a perspective viewing camera when choosing a device. And as we said before, ColorDepthRenderPass
is created for depth test.
Framebuffers, command pools, command buffers, fences and semaphores are allocated and created as EmptyScene
did.
android_app
pointer is used to reference the path of Activity
related information, and in this case, it is used to access the model file at the path to the application. Once we get the model path we load the model data with Model::ReadFile
with scaling. STBI_rgb_alpha
indicates we want our pixels to be the RGBA format as possible as it can. However, I checked the stb_image.h
and found it does not work for jpg files.
The number of the mipmap level of texture is calculated by taking the binary logarithm of the largest dimension of the texture since each level of mipmap images are a power of 2 smaller than the previous level, and note the adding 1 is that the original texture is a mipmap level as well.
Now having loaded the pixel and vertices, we can copy the pixels to an image and upload the vertices to a buffer with BuildTexture2D
and UploadToGPU
which we’ve explained in this and this.
Next, we build two uniform buffers and create mappings between the memories of the buffer. The first buffer is as the resource of the transform matrices of the model. The second one is as the resource of the lighting data. Because we’ll update the transform matrices every updating frame we are not going to unmap the mvpBuffer
immediately.
If samplerAnisotropy
is enabled, we set the value to 8 for a balance between performance and quality. Because we are drawing earth, a sphere-shaped object, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
is suitable for this shape due to avoiding a visible line between the junction of texture borders.
BuildDepthImage
creates the depth image, allocates memory for it, creates the derived image view, and binds the memory to the image. VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
specifies that an image can be used to create a VkImageView
suitable for use as a depth/stencil in a VkFramebuffer
. VK_IMAGE_ASPECT_DEPTH_BIT
specifies the depth aspect of an image is included in an image view, and if the image format includes stencil test, we should append VK_IMAGE_ASPECT_STENCIL_BIT
, too.
Note we do not need to transition the image layout as we do in BuildTexture2D
since we have specified the transition at the vkAttachmentDescription
of ColorDepthRenderPass
already.