框架

此文件夹包含示例使用的基础框架。它提供示例基类,封装了常用功能,例如加载资源(图像、模型、着色器),包装了常见的 Vulkan 对象,并实现了诸如缓存和场景图等常用概念。该框架还为 Windows、Linux、MacOS 和 Android 实现了平台支持。

它可以用作编写高级 Vulkan 应用程序的指南。

在尝试实现常用函数之前,请考虑检查框架是否已提供您正在寻找的内容。

示例基类

该框架提供了两个不同的示例基类。当创建新示例时,您可以选择其中一个

高级基类示例

此基类抽象了大多数 Vulkan API 调用,因此大量使用了框架的 Vulkan 对象包装类。使用基类编写示例的冗长程度较低。

API 示例基类

此基类使用的抽象较少,让您可以更明确地使用 API。

对 Vulkan-Hpp 的支持

虽然框架本身主要使用 Vulkan 的 C 接口,但高级和 API 示例基类都附带 Vulkan-Hpp 变体,让您可以使用 C++ Vulkan 语言绑定编写示例。

常用框架概念

启用扩展

Vulkan 是一个可扩展的 API。新功能通常通过实例或设备扩展公开。可以在高级和 API 基类示例的构造函数中启用扩展。

MySample::MySample()
{
    add_instance_extension(VK_SOME_INSTANCE_EXTENSION_NAME);
    add_device_extension(VK_SOME_DEVICE_EXTENSION_NAME);
}
该框架使用 Volk 元加载器,它会自动为所有启用的扩展加载扩展函数指针。无需手动获取扩展指针函数。

更改 Vulkan API 版本

默认情况下,所有示例都会创建一个 Vulkan 1.0 实例。可以在示例的构造函数中请求更高的版本。

MySample::MySample()
{
    set_api_version(VK_API_VERSION_1_2);
}

请求 GPU 功能

大多数扩展还需要启用相应的特性标志。这可以通过覆盖基类的 request_gpu_features 函数来完成

void MySample::request_gpu_features(vkb::PhysicalDevice &gpu)
{
    // Get a reference to the feature structure required for an extension
    auto &requested_extension_feature = gpu
    request_extension_features<VkPhysicalDeviceSomeExtensionFeaturesKHR>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SOME_EXTENSION_FEATURES_KHR);

    // Enable a selected feature
    requested_extension_feature.featureName = VK_TRUE;
}

扩展图形用户界面

该框架包含一个基于 Dear ImGui 的图形用户界面。示例可以使用它来显示数值,并添加诸如按钮、下拉菜单等控件。

要向示例的 UI 添加其他元素,你需要重写基类中的相应函数

基于高级基类的示例需要重写 draw_gui 函数

void MySample::draw_gui()
{
    if (ImGui::Checkbox("Enable Option", &option_enabled))
    {
        ...
    }
}

基于 API 基类的示例需要重写 on_update_ui_overlay 函数

void MyApiSample::on_update_ui_overlay(vkb::Drawer &drawer)
{
     if (drawer.checkbox("Enable option", &option_enabled))
    {
        ...
    }
}

加载模型

该框架支持 glTF 模型,并包含此格式的加载器。

高级基类使用在启动时加载的单个 glTF 场景。该场景是基类的一部分,无需显式绘制

bool MySample::prepare(const vkb::ApplicationOptions &options)
{
    scene = load_scene("filename.gltf");
}

使用 API 基类时,需要显式声明、加载和渲染

// my_sample.h
class MyApiSample : public ApiVulkanSample
{
    std::unique_ptr<vkb::sg::SubMesh> modelA;
    std::unique_ptr<vkb::sg::SubMesh> modelB;
    ...
}

// my_sample.cpp
bool MyApiSample::prepare(const vkb::ApplicationOptions &options)
{
    modelA = load_model("filenameA.gltf");
    modelB = load_model("filenameB.gltf");
}

void MyApiSample::build_command_buffers()
{
    vkBeginCommandBuffer(...);
    ...
    draw_model(modelA, draw_cmd_buffers[i]);
    ...
    draw_model(modelB, draw_cmd_buffers[i]);
    ...
    vkEndCommandBufer(...);
}

加载图像

该框架支持 KTX GPU 容器格式,并包含此格式的加载器。作为容器格式,KTX 支持不同的图像格式,从基本的 RGBA 图像到压缩格式。

texture = load_texture("rgba_texture.ktx", vkb::sg::Image::Color);

像这样加载的图像(纹理)随后可以用作描述符

VkDescriptorImageInfo  image_descriptor = create_descriptor(texture);

加载着色器

该框架支持加载文本 GLSL 着色器。这些着色器然后在运行时编译为 SPIR-V,以便 Vulkan 可以使用它们。

使用高级基类时,着色器附加到场景图形的渲染管线

vkb::ShaderSource vert_shader("vs.vert");
vkb::ShaderSource frag_shader("fs.frag");
auto              scene_subpass = std::make_unique<vkb::ForwardSubpass>(get_render_context(), std::move(vert_shader), std::move(frag_shader), *scene, *camera);

auto render_pipeline = vkb::RenderPipeline();
render_pipeline.add_subpass(std::move(scene_subpass));

set_render_pipeline(std::move(render_pipeline));

而在 API 基类中,则需要通过在管线创建时创建着色器模块来更显式地完成

std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages;
...
shader_stages[0] = load_shader("vs.vert", VK_SHADER_STAGE_VERTEX_BIT);
shader_stages[1] = load_shader("fs.frag", VK_SHADER_STAGE_FRAGMENT_BIT);
VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), pipeline_cache, 1, &pipeline_create_info, nullptr, &pipeline));