游戏引擎开发日志(第三天)

第三天2021年5月25日

上一天的地址:https://blog.csdn.net/z736248591/article/details/117234099

————————————哥是可爱的分割线————————————————

往期回顾>>>>>>>

之前,我们开了一个项目,决定底层使用c语言,渲染API使用Vulkan。关于渲染部分,我们的目标如下:

1.实例和物理设备选取;
2.逻辑设备和队列族;
3.窗口表面和交换链;
4.图像视图和帧缓冲;
5.渲染通道;
6.图形管线;
7.命令池和命令缓冲;
8.主循环渲染。

其中,我们已经完成了实例创建、选取物理设备、创建逻辑设备,这些部分。虽然实现了一个简单的主循环,但是要实际使用起来,这远远不够的。以后会逐渐填充。


题外话:昨天晚上不知道怎么搞的,VS被我彻底搞坏了。删除了文件夹下的.vs都没用,也没办法识别这个是CMake项目了,只会输出警告: 1 配置被排除,因为他们存在于输出目录中警告: 1 配置被排除,因为他们存在于输出目录中这些话,网络上也找不到解决方案,现在只能改用Clion编写代码。


看了一些,昨天漏掉了销毁逻辑设备的代码了。这里补上:

static void DestroyDevice()
{
     
    vkDestroyDevice(logicalDevice,NULL);
    printf("Vulkan logical device destroyed.");
}

今天来学习一下交换链

Vulkan没有默认帧缓冲的概念,它需要一个能够缓冲渲染操作的组件。在Vulkan中,这一组件就是交换链。Vulkan的交换链必须显式地创建,不存在默认的交换链。交换链本质上一个包含了若干等待呈现的图像的队列。我们的应用程序从交换链获取一张图像,然后在图像上进行渲染操作,完成后,将图像返回到交换链的队列中。交换链的队列的工作方式和它呈现图像到表面的条件依赖于交换链的设置。但通常来说,交换链被用来同步图像呈现和屏幕刷新1

创建KHR表面

VkResult result = glfwCreateWindowSurface(instance, window, NULL, &surfaceKHR);
if (result != VK_SUCCESS)
{
     
    printf("Create Surface failed.");
    abort();
}

VK_FORMAT_B8G8R8A8_UNORM代表了我们使用B,G,R和alpha次序的通道,且每一个通道为无符号8bit整数,每个像素总计32bits2

判断格式是否支持

    // 获取支持的格式
    uint32_t surfaceFormatCount;
    vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surfaceKHR, &surfaceFormatCount, NULL);
    VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)malloc(sizeof(VkSurfaceFormatKHR) * surfaceFormatCount);
    // 判断是否支持
    if (!(surfaceFormatCount == 1 && surfaceFormats[0].format == VK_FORMAT_UNDEFINED))
    {
     
        uint8_t available = 0;
        for(uint32_t i=0;i<surfaceFormatCount;i++)
        {
     
            if(surfaceFormats[i].format==VK_FORMAT_B8G8R8A8_UNORM)
            {
     
                available = 1;
                break;
            }
        }
        if (!available)
        {
     
            printf("Surface not support VK_FORMAT_B8G8R8A8_UNORM!");
            abort();
        }
    }

判断显示模式模式:

  1. VK_PRESENT_MODE_IMMEDIATE_KHR: 应用程序提交的图像被立即传输到屏幕呈现,这种模式可能会造成撕裂效果。

  2. VK_PRESENT_MODE_FIFO_KHR: 交换链被看作一个队列,当显示内容需要刷新的时候,显示设备从队列的前面获取图像,并且程序将渲染完成的图像插入队列的后面。如果队列是满的程序会等待。这种规模与视频游戏的垂直同步很类似。显示设备的刷新时刻被成为“垂直中断”。

  3. VK_PRESENT_MODE_FIFO_RELAXED_KHR: 该模式与上一个模式略有不同的地方为,如果应用程序存在延迟,即接受最后一个垂直同步信号时队列空了,将不会等待下一个垂直同步信号,而是将图像直接传送。这样做可能导致可见的撕裂效果。

  4. VK_PRESENT_MODE_MAILBOX_KHR: 这是第二种模式的变种。当交换链队列满的时候,选择新的替换旧的图像,从而替代阻塞应用程序的情形。这种模式通常用来实现三重缓冲区,与标准的垂直同步双缓冲相比,它可以有效避免延迟带来的撕裂效果。

    逻辑上看仅仅VR_PRESENT_MODE_FIFO_KHR模式保证可用性2

在顶部添加

// 支持的显示模式
static VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;

CreateSwap函数追加定义

// 获取显示模式
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,surface,&presentModeCount,NULL);
VkPresentModeKHR *presentModes=(VkPresentModeKHR*)malloc(sizeof(VkPresentModeKHR)*presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,surface,&presentModeCount,presentModes);
for(uint32_t i=0;i<presentModeCount;i++)
{
     
    // 如果支持VK_PRESENT_MODE_MAILBOX_KHR模式,由于其效率高,便选用
    if(presentModes[i]==VK_PRESENT_MODE_MAILBOX_KHR)
    {
     
        presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
        break;
    }
    //如果没能用上VK_PRESENT_MODE_MAILBOX_KHR模式,但有VK_PRESENT_MODE_IMMEDIATE_KHR模式
    //也比VK_PRESENT_MODE_FIFO_KHR模式强,故选用
    else if(presentMode == VK_PRESENT_MODE_IMMEDIATE_KHR)
    {
     
        presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
        // 注意这里不需要break。继续循环找VK_PRESENT_MODE_MAILBOX_KHR
    }
}

  1. Vulkan编程指南(章节10-交换链) - 知乎 https://zhuanlan.zhihu.com/p/56862714 ↩︎

  2. Vulkan填坑学习Day06—交换链_沉默的舞台剧的博客-CSDN博客 https://blog.csdn.net/qq_35312463/article/details/103880221?spm=1001.2014.3001.5501 ↩︎ ↩︎

你可能感兴趣的:(游戏开发,游戏引擎,c,Cmake,Vulkan,渲染器)