# VulkanMultiSample **Repository Path**: fuxii/vulkan-multi-sample ## Basic Information - **Project Name**: VulkanMultiSample - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-01-18 - **Last Updated**: 2024-01-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 说明 ## 程序使用说明 ![image01](./doc/03.png) * `-` 键:降低采样率 * `+` 键:增加采样率 ## 锯齿原因 图像之所以有锯齿是应为像素的采样率不够导致的。如下图: ![image01](./doc/01.png) 红点为采样点,灰框为对应的像素,黄色覆盖区域为要渲染的局域。如果黄色区域覆盖了采样点的话,对应的像素就会进行颜色计算填充。如上图只有右下角得到了颜色计算,左下角和右上角的像素虽然被部分覆盖了,却没有覆盖采样点,这样这些像素就不会进行颜色计算二导致采样率不够,导致锯齿。 ## 抗锯齿原理 抗锯齿其最本质的原理就是在单个像素中再分割子像素,通过增加像素提高采样率以达到抗锯齿的效果。如下图: ![image01](./doc/02.png) 蓝色虚线就是对于单个像素分割的子像素。这样原本不会被采样的左下角和右上角像素也会应覆盖到对应的某些子像素的采样点而进行颜色计算。以此来达到抗锯齿的目的。 所以一个抗锯齿的基本思想就是提高分辨率,将高分辨率的图片采样到低分辨率的图中,获得抗锯齿效果。 ## 抗锯齿途径 实现抗锯齿有很多途径。 * 硬抗锯齿 :硬抗锯齿通过 `GPU` 硬件自身的抗锯齿特性自动完成高分辨到低分辨率的采样。 * 软抗锯齿 :通过创建不同分辨率的图片在 ``GPU`` 上渲染,之后将高分辨率的渲染结果转至低分辨率中。(手动进行 `硬抗锯齿` 过程) 由于需要肉眼能够观察到抗锯齿的效果,这里使用 `软抗锯齿` 实现。 ## 实现 ### 创建不同分辨率的图片 首先创建分辨率为 `128×128` 分辨率的图片: ```c++ VkImage color_image_128x128 = VK_NULL_HANDLE; VkImageCreateInfo color_image_128x128_create_info = {}; { ... color_image_128x128_create_info.extent.width = 128; color_image_128x128_create_info.extent.height = 128; ... } driver.vkCreateImage(vk_device, &color_image_128x128_create_info, &vk_allocation_callbacks, &color_image_128x128); 分配内存() 图片与内存绑定() 创建VkImageView并与color_image_128x128关联() ``` 再创建分辨率为 `256×256` 分辨率的图片: ```c++ VkImage color_image_256x256 = VK_NULL_HANDLE; VkImageCreateInfo color_image_256x256_create_info = {}; { ... color_image_256x256_create_info.extent.width = 256; color_image_256x256_create_info.extent.height = 256; ... } driver.vkCreateImage(vk_device, &color_image_256x256_create_info, &vk_allocation_callbacks, &color_image_256x256); 分配内存() 图片与内存绑定() 创建VkImageView并与color_image_256x256关联() ``` 再创建分辨率为 `512×512` 分辨率的图片: ```c++ VkImage color_image_512x512 = VK_NULL_HANDLE; VkImageCreateInfo color_image_512x512_create_info = {}; { ... color_image_512x512_create_info.extent.width = 512; color_image_512x512_create_info.extent.height = 512; ... } driver.vkCreateImage(vk_device, &color_image_512x512_create_info, &vk_allocation_callbacks, &color_image_512x512); 分配内存() 图片与内存绑定() 创建VkImageView并与color_image_512x512关联() ``` ### 创建不同分辨率的帧缓存 之后分别根据不同分辨率的颜色图片创建 `Framebuffer` : ```c++ struct FramebufferPacket { VkImage image; VkImageView imageView; VkExtent2D extent; VkFramebuffer framebuffer; }; std::vector framebuffer_packets; FramebufferPacket framebuffer_packet_128x128 = {}; framebuffer_packet_128x128.image = color_image_128x128; framebuffer_packet_128x128.imageView = color_image_view_128x128; framebuffer_packet_128x128.extent.width = color_image_128x128_create_info.extent.width; framebuffer_packet_128x128.extent.height = color_image_128x128_create_info.extent.height; framebuffer_packet_128x128.framebuffer = VK_NULL_HANDLE; framebuffer_packets.push_back(framebuffer_packet_128x128); FramebufferPacket framebuffer_packet_256x256 = {}; framebuffer_packet_256x256.image = color_image_256x256; framebuffer_packet_256x256.imageView = color_image_view_256x256; framebuffer_packet_256x256.extent.width = color_image_256x256_create_info.extent.width; framebuffer_packet_256x256.extent.height = color_image_256x256_create_info.extent.height; framebuffer_packet_256x256.framebuffer = VK_NULL_HANDLE; framebuffer_packets.push_back(framebuffer_packet_256x256); FramebufferPacket framebuffer_packet_512x512 = {}; framebuffer_packet_512x512.image = color_image_512x512; framebuffer_packet_512x512.imageView = color_image_view_512x512; framebuffer_packet_512x512.extent.width = color_image_512x512_create_info.extent.width; framebuffer_packet_512x512.extent.height = color_image_512x512_create_info.extent.height; framebuffer_packet_512x512.framebuffer = VK_NULL_HANDLE; framebuffer_packets.push_back(framebuffer_packet_512x512); for (FramebufferPacket &framebuffer_packet_item : framebuffer_packets) { VkFramebufferCreateInfo vk_frame_buffer_create_info = {}; vk_frame_buffer_create_info.sType VkStructureType::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; vk_frame_buffer_create_info.pNext = nullptr; vk_frame_buffer_create_info.flags = 0; vk_frame_buffer_create_info.renderPass = vk_render_pass; vk_frame_buffer_create_info.attachmentCount = 1; vk_frame_buffer_create_info.pAttachments = &framebuffer_packet_item.imageView; vk_frame_buffer_create_info.width = framebuffer_packet_item.extent.width; vk_frame_buffer_create_info.height = framebuffer_packet_item.extent.height; vk_frame_buffer_create_info.layers = 1; VkResult frame_buffer_create_result = driver.vkCreateFramebuffer(vk_device,vk_frame_buffer_create_info, &vk_allocation_callbacks, &framebuffer_packet_iteframebuffer); if (frame_buffer_create_result != VkResult::VK_SUCCESS) { throw std::runtime_error("Can not create Framebuffer"); } } ``` ### 渲染不同分辨率的图片 获取当前要渲染的目标帧缓存 ```c++ FramebufferPacket current_framebuffer_packet = framebuffer_pac[current_framebuffer_packet_index]; ``` 绑定到渲染目标 ```c++ VkRenderPassBeginInfo vk_render_pass_begin_info = {}; ... vk_render_pass_begin_info.framebuffer = current_framebuffer_packet.framebuffer; ... ``` 记录渲染指令 ```c++ driver.vkCmdBeginRenderPass(vk_command_buffer, &vk_render_pass_begin_info, VkSubpassContents::VK_SUBPASS_CONTENTS_INLINE); driver.vkCmdBindPipeline(vk_command_buffer, VkPipelineBindPoint::VK_PIPELINE_BIND_POINT_GRAPHICS, volume_pipeline); driver.vkCmdSetViewport(vk_command_buffer, 0, 1, ¤t_viewport); driver.vkCmdSetScissor(vk_command_buffer, 0, 1, ¤t_scissor); driver.vkCmdDraw(vk_command_buffer, 3, 1, 0, 0); ``` 这样就渲染了不同分辨率下的采样结果。 ### 将高分辨结果转移至目标图片 通过 `vkCmdBlitImage` 将高分辨率的结果转移用于显示的目标图片: ```c++ VkImageBlit vk_image_blit = {}; vk_image_blit.srcSubresource.aspectMask = VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT; vk_image_blit.srcSubresource.mipLevel = 0; vk_image_blit.srcSubresource.baseArrayLayer = 0; vk_image_blit.srcSubresource.layerCount = 1; vk_image_blit.srcOffsets[0].x = 0; vk_image_blit.srcOffsets[0].y = 0; vk_image_blit.srcOffsets[0].z = 0; vk_image_blit.srcOffsets[1].x = current_framebuffer_packet.extent.width; vk_image_blit.srcOffsets[1].y = current_framebuffer_packet.extent.height; vk_image_blit.srcOffsets[1].z = 1; vk_image_blit.dstSubresource.aspectMask = VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT; vk_image_blit.dstSubresource.mipLevel = 0; vk_image_blit.dstSubresource.baseArrayLayer = 0; vk_image_blit.dstSubresource.layerCount = 1; vk_image_blit.dstOffsets[0].x = 0; vk_image_blit.dstOffsets[0].y = 0; vk_image_blit.dstOffsets[0].z = 0; vk_image_blit.dstOffsets[1].x = vk_surface_capabilities_khr.currentExtent.width; vk_image_blit.dstOffsets[1].y = vk_surface_capabilities_khr.currentExtent.height; vk_image_blit.dstOffsets[1].z = 1; driver.vkCmdBlitImage(vk_command_buffer, current_framebuffer_packet.image, VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapchain_images[next_image_index], VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vk_image_blit, VkFilter::VK_FILTER_LINEAR); ``` ### 指令推送执行 最后将指令推送至 `GPU` 执行即可: ```c++ VkSubmitInfo vk_submit_info = {}; vk_submit_info.sType = VkStructureType::VK_STRUCTURE_TYPE_SUBMIT_INFO; vk_submit_info.pNext = 0; vk_submit_info.waitSemaphoreCount = 0; vk_submit_info.pWaitSemaphores = nullptr; vk_submit_info.pWaitDstStageMask = nullptr; vk_submit_info.commandBufferCount = 1; vk_submit_info.pCommandBuffers = &vk_command_buffer; vk_submit_info.signalSemaphoreCount = 0; vk_submit_info.pSignalSemaphores = nullptr; driver.vkQueueSubmit(vk_queue, 1, &vk_submit_info, fence); driver.vkWaitForFences(vk_device, 1, &fence, VK_TRUE, UINT64_MAX); ```