框架
此文件夹包含示例使用的基础框架。它提供示例基类,封装了常用功能,例如加载资源(图像、模型、着色器),包装了常见的 Vulkan 对象,并实现了诸如缓存和场景图等常用概念。该框架还为 Windows、Linux、MacOS 和 Android 实现了平台支持。
它可以用作编写高级 Vulkan 应用程序的指南。
在尝试实现常用函数之前,请考虑检查框架是否已提供您正在寻找的内容。
示例基类
该框架提供了两个不同的示例基类。当创建新示例时,您可以选择其中一个
高级基类示例
此基类抽象了大多数 Vulkan API 调用,因此大量使用了框架的 Vulkan 对象包装类。使用基类编写示例的冗长程度较低。
请参阅 vulkan_sample.h 和 vulkan_sample.cpp。
对 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));