根据多重采样值,设置颜色和深度的多重采样。
在SceneWidget.h中添加两个函数:
void CreateColorResources();
void CreateDepthResources();
分别处理颜色和深度的多重采样,然后在SceneWidget.cpp中实现这两个函数。
先在CreateColorResources函数中,需要生成相应的VkImage再生成相应的VkImageView,由于颜色和深度,都需要生成这些,所以可以将生成VkImage和VkImageView的操作,写成一个函数。先写生成Image的函数,再写生成ImageView的函数。
生成VkImage时,需要用到Image的宽、高、纹理的层级、平铺方式、内存布局等信息,才能生成VkImage。
void CreateImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory);
VkImageView的生成可以使用现有的CreateImageView的函数即可。
所以需要在SceneWidget.h中添加函数声明,并且添加成员变:
VkImage m_colorImgae = VK_NULL_HANDLE;和 VkImageView m_colorImageView = VK_NULL_HANDLE;
VkImage m_depthImage = VK_NULL_HANDLE;和VkImageView m_depthImageView = VK_NULL_HANDLE;
先实现CreateImage函数,要生成一个VkImage对象,可以调用vkCreateImage函数。同样,返回一个VkResult的值,并判断这个值是否有效。
VkResult result = vkCreateImage();其参数:
第一个参数:m_device,基本上在逻辑设备上生成的都是这个值。
第二个参数:是生成VkImage所需要的信息,所以在这个函数上面添加一个VkImageCreateInfo imageCreateInfo = {};在这里传入&imageCreateInfo。
第三个参数:记录申请的地址,这里不需要,传入nullptr。
第四个参数:传出生成的VkImage对象,所以传入入参image的引用。
imageCreateInfo的属性赋值如下:
这个数据结构的类型。
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
这里的image类型为2维的,除特殊指定外,一般都是2维。
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
图像的宽和高,一般与视口大小一致。
imageCreateInfo.extent.width = width;
imageCreateInfo.extent.height = height;
深度一般默认为1。
imageCreateInfo.extent.depth = 1;
mipmap的层级。
imageCreateInfo.mipLevels = mipLevels;
图像的层级,有的图像会有多个层级。
imageCreateInfo.arrayLayers = 1;
图像的像素格式。
imageCreateInfo.format = format;
图像的平铺方式。
imageCreateInfo.tiling = tiling;
布局
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
使用方式。
imageCreateInfo.usage = usage;
采样数
imageCreateInfo.samples = numSamples;
缓冲在设备的多缓冲队列中的共享方式。
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
其它的字段保持默认。
写到这个地方,本来以为这个函数算是写完了,但是看教程时,发现创建完VkImage后,还有操作。
获取图像对象的内存需求:vkGetImageMemoryRequirements(),其参数:
第一个参数:m_device。
第二个参数:image生成的VkImage对象。
第三个参数:VkMemoryRequirements结构指针,返回图像对象对内存的要求。
补充一个数据结构:
VkMemoryRequirements memoryRequirements = {};传入:&memoryRequirements。由于是传出参数,所以不需要对这个结构的属性赋值
申请内存,通过vkAllocateMemory函数,申请内存,并验证返回值是否为VK_SUCCESS。其参数:
第一个参数:m_device。
第二个参数:需要定义一个VkMemoryAllocateInfo memoryAllocateInfo = {}。传入&memoryAllocateInfo。
第三个参数:nullptr。
第四个参数:&imageMemory,函数的调用者传入的参数。申请的内存就放在imageMemory里。
给memoryAllocateInfo结构的成员赋值:
memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memoryAllocateInfo.pNext = nullptr;
memoryAllocateInfo.allocationSize = memRequirements.size;
memoryAllocateInfo.memoryTypeIndex;这个值需要查询一下:
可以通过vkGetPhysicalDeviceMemoryProperties函数,查询一下输入参数:
第一个参数:物理设备,m_physicalDevice,之前查询到的。
第二个参数:是VkPhysicalDeviceMemoryProperties的类型的数据结构memProperties输入引用。
然后通过遍历memProperties,找出包含输入的properties的特性的索引。
最后,调用vkBindImageMemory将分配的内存与VkImage对象绑定在一起。参数:
第一个参数:m_device。
第二个参数:要绑的image对象。
第三个参数:imageMemory。
第四个参数:内存的偏移,这里不用偏移,所以为0。
这里可以看出imageMemory是申请出来的,最后也是要清理的,所以在这里需要再添加成员变量,由于是color和depth两个都各有一个,所以一共要再添加两个成员变量VkDeviceMemory m_colorMemory和VkDeviceMemory m_depthMemory。
在CreateColorResources函数中调用CreateImage函数,其参数依次为:apabilities.currentExtent的宽高、层级为1、采样使用msaa、像素格式为m_swapchainImageFormat、使用平铺最佳的方式、使用动态绑定且绑定颜色附件方式、使用显存、要生成的image对象和momory对象。
在CreateDepthResources函数中,与CreateColorResources一样,只是CreateImage的参数略区别:
apabilities.currentExtent的宽高、层级为1、采样使用msaa、像素格式为VK_FORMAT_D32_SFLOAT、使用平铺最佳的方式、使用深度模板附件方式、使用显存、要生成的image对象和momory对象。
在生成完Image后,还要生成一下对应的imageView。
在最后,清理资源,先清理color的mmemory,再清理colorImage,最后清理colorImageView。depth也是这个清理顺序。
运行一下程序:
后台的输出,没有输出报错信息。