Game Programming using Qt 5 Beginner’s Guide, 2nd Edition - vulkan_background

在这里插入图片描述

在开始使用 Vulkan 和 Qt 开发游戏之前,您需要做一些准备工作。首先,您需要安装 Vulkan SDK。为此,请前往 https://www.lunarg.com/vulkan-sdk/,下载适用于您的操作系统的文件,然后执行或解压缩它。检查安装文件夹中 doc 子目录中的 index.html 文件以查看是否需要执行任何其他操作。

接下来,您需要一个支持 Vulkan 的 Qt 构建;它必须是 Qt 5.10 或更高版本。如果您已通过安装程序安装了可用的最新版本,则它可能已经适用。

要检查您的 Qt 版本是否支持 Vulkan,请创建一个新的 Qt 控制台应用程序,确保您选择与最近安装的 Qt 版本对应的套件。 Vulkan SDK 还要求您设置一些环境变量,例如 VULKAN_SDK、PATH、LD_LIBRARY_PATH 和 VK_LAYER_PATH(具体名称和值可能取决于操作系统,因此请参阅 SDK 文档)。您可以通过切换到 Qt Creator 的 Projects 窗格并展开 Build Environment 部分来编辑项目的环境变量。

与 OpenGL 不同,Vulkan 没有全局状态。与 Vulkan 的交互从 VkInstance 类型表示的实例对象开始。应用程序通常会创建一个包含应用程序范围状态的单个 VkInstance 对象。所有其他 Vulkan 对象只能从实例对象创建。在 Qt 中,对应的类是 QVulkanInstance。此类提供了一种配置 Vulkan 的便捷方法,然后使用给定的配置对其进行初始化。您还可以使用其 supportedExtensions() 和 supportedLayers() 函数在使用之前查询支持的功能。配置完成后,您应该调用 create() 函数,该函数实际触发加载 Vulkan 库并创建 VkInstance 对象。如果此函数返回 true,则 Vulkan 实例对象已准备好使用。

main.cpp

#include <QGuiApplication>
#include <QVulkanWindow>
#include <vulkan/vulkan.h>
#include "myrenderer.h"
#include <QVulkanInstance>
#include <QVulkanFunctions>
#include <QLoggingCategory>
#include "mywindow.h"


int main(int argc, char *argv[]) 
{
    QGuiApplication app(argc, argv);
    QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true"));
    //应用程序通常会创建一个包含应用程序范围状态的单个 VkInstance 对象QVulkanInstance
    QVulkanInstance vulkan;
    vulkan.setLayers({ "VK_LAYER_LUNARG_standard_validation" });
    if (!vulkan.create()) {
        qFatal("Failed to create Vulkan instance: %d", vulkan.errorCode());        
    }
    //创建一个能够进行 Vulkan 渲染的窗口
    //这是通过继承 QVulkanWindow 类来完成的
    //与 QOpenGLWindow 类似,QVulkanWindow 扩展了 QWindow 并提供了利用 Vulkan 功能所需的功能以及一些便利功能
    //我们创建了一个将使用 Vulkan 渲染的窗口
    MyWindow window;
    window.resize(1024, 768);
    //数初始化 Vulkan,创建一个窗口,将实例对象传递给该窗口,并将其显示在屏幕上
    window.setVulkanInstance(&vulkan);
    window.show();
	//当窗口显示时,Qt 将调用窗口上的 createRenderer() 函数,并在您的此函数实现中创建一个新的渲染器对象。
    return app.exec();
}

myrenderer.h

#include <QVulkanWindow>
//MyRenderer 的类应从 QVulkanWindowRenderer 派生
class MyRenderer : public QVulkanWindowRenderer
{
public:
    MyRenderer(QVulkanWindow *w);
    void initResources();
    void startNextFrame() override;

protected:
    //将 QVulkanWindow *m_window 私有字段添加到渲染器类
    QVulkanWindow *m_window;

    QVulkanDeviceFunctions *m_devFuncs;
    float m_hue = 0;

};

myrenderer.cpp

#include "myrenderer.h"
#include <QVulkanFunctions>
#include <QFile>

MyRenderer::MyRenderer(QVulkanWindow *w)
    : m_window(w)
{
}

void MyRenderer::initResources()
{
    //现在您可以使用 m_devFuncs 访问 Vulkan API 函数
    VkDevice device = m_window->device();
    //添加并初始化 m_devFuncs 私有字段
    m_devFuncs = m_window->vulkanInstance()->deviceFunctions(device);
}
//每次需要绘制窗口时,Qt 都会调用渲染器的 startNextFrame() 函数。
//与paintEvent() 的工作方式类似,默认情况下不会连续调用startNextFrame()
//它只会在显示窗口后调用一次
//如果需要连续渲染动态场景,调用m_window->frameReady()后调用m_window->requestUpdate()
void MyRenderer::startNextFrame()
{
    //背景颜色的当前色调的浮动 m_hue 私有字段
    //将其初始值设置为零
    m_hue += 0.005f;
    //我们增加 m_hue 变量并确保我们不会越界
    if (m_hue > 1.0f) {
        m_hue = 0.0f;
    }
    //然后,我们使用 QColor::fromHslF() 函数根据给定的色调、饱和度和亮度(每个范围从 0 到 1)构造一个 QColor值
    QColor color = QColor::fromHslF(m_hue, 1, 0.5);

    //使用这个颜色变量来构造一个 VkClearValue 数组,我们将使用它来设置背景颜色
    VkClearValue clearValues[2];
    memset(clearValues, 0, sizeof(clearValues));
    clearValues[0].color = {
        static_cast<float>(color.redF()),
        static_cast<float>(color.greenF()),
        static_cast<float>(color.blueF()),
        1.0f
    };
    clearValues[1].depthStencil = { 1.0f, 0 };
	//要在 Vulkan 中开始新的渲染
    //我们需要初始化一个 VkRenderPassBeginInfo 结构
    VkRenderPassBeginInfo info;
    memset(&info, 0, sizeof(info));
    //它需要大量数据,但幸运的是,QVulkanWindow 为我们提供了大部分数据
    //我们只需要将它放入结构中并使用我们之前设置的 clearValues 数组
    info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
    info.renderPass = m_window->defaultRenderPass();
    info.framebuffer = m_window->currentFramebuffer();
    const QSize imageSize = m_window->swapChainImageSize();
    info.renderArea.extent.width = imageSize.width();
    info.renderArea.extent.height = imageSize.height();
    info.clearValueCount = 2;
    //设置的 clearValues 数组
    info.pClearValues = clearValues;
    
    VkCommandBuffer commandBuffer = m_window->currentCommandBuffer();
    //vkCmdBeginRenderPass() Vulkan API 函数将开始渲染,这将导致使用我们设置的颜色清除窗口。
    
    m_devFuncs->vkCmdBeginRenderPass(commandBuffer, &info,
                                     VK_SUBPASS_CONTENTS_INLINE);
    //由于我们没有其他东西可绘制,因此我们立即使用 vkCmdEndRenderPass() 函数完成渲染过程。
    m_devFuncs->vkCmdEndRenderPass(commandBuffer);
    //每一帧的绘制都以调用 frameReady() 结束
    //在调用此函数之前,无法完成帧的处理
    //但是,不需要直接从 startNextFrame() 函数调用此函数。例如,如果您需要等待计算在单独的线程中完成,您可以延迟此调用。
    m_window->frameReady();
    m_window->requestUpdate();
}

mywindow.h

#ifndef MYWINDOW_H
#define MYWINDOW_H

#include <QObject>
#include <QVulkanWindow>

class MyWindow : public QVulkanWindow {
public:
    QVulkanWindowRenderer *createRenderer() override;
};


#endif // MYWINDOW_H

mywindow.cpp

#include "mywindow.h"
#include "myrenderer.h"

QVulkanWindowRenderer *MyWindow::createRenderer() {
    //渲染器是附加到窗口上的,会自动随它一起删除,所以不需要手动删除。
    return new MyRenderer(this);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值