尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

VulkanSceneGraph学习教程(五)

VulkanSceneGraph学习教程(五) 第 5 章 第一个 VSG 程序创建窗口并渲染一个三角形本章定位这是整套教程的第一个完整可运行示例也是后续所有章节的写作模板。 请从「目标 → 前置准备 → 完整代码 → 逐段解析 → 构建与运行 → 运行效果 → 常见问题 → 小结 → 延伸阅读」这一固定结构来组织每一章保证全教程风格统一、详略一致。5.1 本章目标学完本章你将能够用vsg::Viewervsg::Window创建一个 Vulkan 窗口理解 VSG 中「场景图 → 渲染图RenderGraph/ 命令图CommandGraph」的装配方式用vsg::ShaderSetvsg::GraphicsPipelineConfigurator配置一条图形管线用vsg::Geometry描述顶点/索引数据并完成一次索引绘制跑通一个最小但完整的 VSG 程序。最终效果一个 800×600 的窗口中渲染出一个蓝色实心三角形。5.2 前置准备依赖项说明Vulkan SDK提供 Vulkan 运行时与头文件含vulkan.hCMake ≥ 3.7构建系统已安装的 VSG通过find_package(vsg REQUIRED)引入导出目标为vsg::vsgglslang随 VSG 自带用于把 GLSL 源码在运行时编译为 SPIR-V关于着色器VSG 在构建管线时会用自带的 glslang 把 GLSL 字符串直接编译成 SPIR-V因此本章示例无需预先生成.spv文件。如果你更习惯离线编译也可以用glslangValidator -V shader.vert -o shader.vert.spv预编译后通过vsg::ShaderModule::read()加载进阶话题后续章节涉及。5.3 完整代码5.3.1 工程文件CMakeLists.txtcmake_minimum_required(VERSION 3.7) project(vsg_triangle) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 引入已安装的 VulkanSceneGraph find_package(vsg REQUIRED) add_executable(vsg_triangle main.cpp) target_link_libraries(vsg_triangle PRIVATE vsg::vsg) # 调试时开启 Vulkan 验证层仅开发期发布请移除 # target_compile_definitions(vsg_triangle PRIVATE VSG_DEBUG)5.3.2 源文件main.cpp#include vsg/all.h // ---- 着色器GLSL运行时由 VSG 编译为 SPIR-V---- static const char* vertSrc R( #version 450 layout(location 0) in vec3 inPosition; layout(location 0) out vec3 vColor; void main() { vColor vec3(0.4, 0.7, 1.0); gl_Position vec4(inPosition, 1.0); } ); static const char* fragSrc R( #version 450 layout(location 0) in vec3 vColor; layout(location 0) out vec4 outColor; void main() { outColor vec4(vColor, 1.0); } ); int main(int argc, char** argv) { // 1) 窗口特性与窗口 auto windowTraits vsg::WindowTraits::create(800, 600, VSG Triangle); auto window vsg::Window::create(windowTraits); if (!window || !window-valid()) { std::cerr 无法创建 Vulkan 窗口请确认已安装 Vulkan 驱动 std::endl; return 1; } // 2) Viewer 并挂载窗口 auto viewer vsg::Viewer::create(); viewer-addWindow(window); // 3) 着色器集合 ShaderSet auto shaderSet vsg::ShaderSet::create(); shaderSet-stages { vsg::ShaderStage::create(VK_SHADER_STAGE_VERTEX_BIT, main, vertSrc), vsg::ShaderStage::create(VK_SHADER_STAGE_FRAGMENT_BIT, main, fragSrc) }; // 声明一个顶点属性名为 inPositionlocation0格式为 RGB float32 shaderSet-addAttributeBinding(inPosition, , 0, VK_FORMAT_R32G32B32_SFLOAT, vsg::vec3Array::create({vsg::vec3(0.0f, 0.0f, 0.0f)})); // 4) 用 GraphicsPipelineConfigurator 生成图形管线状态 auto pipelineConfig vsg::GraphicsPipelineConfigurator::create(shaderSet); pipelineConfig-enableArray(inPosition, VK_VERTEX_INPUT_RATE_VERTEX, sizeof(vsg::vec3), VK_FORMAT_R32G32B32_SFLOAT); pipelineConfig-init(); // 真正创建 PipelineLayout / GraphicsPipeline / BindGraphicsPipeline // 5) 状态组承载管线状态并挂载几何体 auto stateGroup vsg::StateGroup::create(); pipelineConfig-copyTo(stateGroup); // 把 BindGraphicsPipeline 等拷入 stateGroup-stateCommands // 6) 几何体顶点 索引 绘制命令 auto vertices vsg::vec3Array::create({ vsg::vec3( 0.0f, -0.5f, 0.0f), vsg::vec3( 0.5f, 0.5f, 0.0f), vsg::vec3(-0.5f, 0.5f, 0.0f) }); auto indices vsg::uint16Array::create({0, 1, 2}); auto geometry vsg::Geometry::create(); geometry-assignArrays({vertices}); // 顶点属性数组 geometry-assignIndices(indices); // 索引数组 geometry-commands.push_back(vsg::DrawIndexed::create(3, 1, 0, 0, 0)); // 3 个索引、1 个实例 stateGroup-addChild(geometry); // 7) 相机透视投影 观察矩阵 auto camera vsg::Camera::create(); camera-projectionMatrix vsg::Perspective::create( 60.0, static_castdouble(window-extent2D().width) / static_castdouble(window-extent2D().height), 0.1, 10.0); camera-viewMatrix vsg::LookAt::create( vsg::dvec3(0.0, 0.0, 3.0), // eye vsg::dvec3(0.0, 0.0, 0.0), // center vsg::dvec3(0.0, 1.0, 0.0)); // up camera-viewportState vsg::ViewportState::create(window-extent2D()); // 8) 渲染图 命令图把场景图编译成 Vulkan 命令 auto renderGraph vsg::createRenderGraphForView(window, camera, stateGroup, VK_SUBPASS_CONTENTS_INLINE, false /* 不需要默认头灯 */); auto commandGraph vsg::CommandGraph::create(window); commandGraph-addChild(renderGraph); viewer-assignRecordAndSubmitTaskAndPresentation({commandGraph}); // 9) 编译并进入主循环 auto compileResult viewer-compile(); updateViewer(viewer, compileResult); while (viewer-advanceToNextFrame()) { viewer-handleEvents(); // 处理窗口/输入事件 viewer-update(); // 更新动画、分页等 viewer-recordAndSubmit(); // 录制并提交命令缓冲 viewer-present(); // 呈现到屏幕 } return 0; }5.4 逐段解析5.4.1 窗口与 Viewer步骤 1–2vsg::WindowTraits描述窗口与 Vulkan 实例/设备的创建参数这里用构造函数WindowTraits(uint32_t width, uint32_t height, const std::string title)直接指定尺寸与标题。vsg::Window::create(traits)是静态工厂会根据平台Win32 / Xcb / MacOS / …创建对应的窗口实现。务必检查window-valid()在缺少 Vulkan 驱动或头灯headless环境下会返回无效窗口。vsg::Viewer是顶层管理者负责窗口、事件、线程以及把场景图「编译」成 Vulkan 命令图。通过addWindow()把窗口挂到 Viewer 上。5.4.2 着色器与 ShaderSet步骤 3vsg::ShaderSet是现代 VSG 推荐的「着色器集合 内省」容器stages顶点/片元着色器阶段vsg::ShaderStage。直接传 GLSL 源码字符串VSG 会在compile()时用 glslang 编译为 SPIR-VaddAttributeBinding(name, define, location, format, sampleData)声明一个顶点属性。这里的nameinPosition要与前向着色器layout(location0) in vec3 inPosition对应location与format必须和几何体里的数据一致。为什么要用 ShaderSet 而不是直接手写管线因为它能自动生成DescriptorSetLayout、PipelineLayout、VertexInputState并通过GraphicsPipelineConfigurator把它们装配成一套可复用的状态——这正是 VSG「声明式」风格的精髓。5.4.3 图形管线配置步骤 4vsg::GraphicsPipelineConfigurator把 ShaderSet 翻译成 Vulkan 管线对象enableArray(inPosition, VK_VERTEX_INPUT_RATE_VERTEX, stride, format)告诉配置器“启用名为inPosition的顶点属性”从而生成对应的VertexInputState顶点绑定/属性描述init()关键一步真正创建PipelineLayout、GraphicsPipeline、BindGraphicsPipelinecopyTo(stateGroup)把BindGraphicsPipeline等状态命令拷入vsg::StateGroup的stateCommands使其成为场景图中的固定状态。⚠️ 顺序很重要enableArray → init → copyTo。漏掉init()会导致layout/graphicsPipeline为空渲染时崩溃。5.4.4 几何体步骤 5–6vsg::Geometry把「顶点数组 索引数组 绘制命令」打包成一个可录制的节点assignArrays({vertices})顶点属性数组DataListassignIndices(indices)索引数组元素类型决定索引格式uint16→VK_INDEX_TYPE_UINT16commands绘制命令列表这里用vsg::DrawIndexed::create(indexCount3, instanceCount1, firstIndex0, vertexOffset0, firstInstance0)。几何体作为stateGroup的子节点——stateGroup提供管线状态几何体提供数据二者在录制阶段自动配合。5.4.5 相机步骤 7vsg::Camera持有三个核心成员projectionMatrix投影矩阵这里用vsg::PerspectivegluPerspective 模型注意aspectRatio要用窗口宽高比否则三角形会被拉伸viewMatrix观察矩阵用vsg::LookAt(eye, center, up)viewportState视口与裁剪区域用窗口extent2D()创建。5.4.6 渲染图与命令图步骤 8这是 VSG 区别于 OSG 的关键对应大纲第 12 章要展开的内容这里先建立直觉vsg::createRenderGraphForView(window, camera, scenegraph, …)一键创建RenderGraph及其内部View自动接好WindowResizeHandler窗口缩放时同步视口vsg::CommandGraph位于场景图顶层的「命令图」管理把子图录制到 Vulkan 命令缓冲viewer-assignRecordAndSubmitTaskAndPresentation({commandGraph})把命令图交给 Viewer由它生成录制/提交/呈现任务。也可用vsg::createCommandGraphForView(window, camera, scenegraph)一步到位分开写则是为了在教程里把「RenderGraph」与「CommandGraph」两个概念讲清楚。5.4.7 编译与主循环步骤 9viewer-compile()遍历命令图把场景图编译成 Vulkan 对象管线、缓冲、描述符集等返回CompileResultupdateViewer(viewer, compileResult)必须调用——把编译结果同步回 Viewer如分配 viewID、绑定必要的 viewer 级状态主循环四步advanceToNextFrame()推进帧、轮询事件→handleEvents()→update()→recordAndSubmit()→present()。5.5 构建与运行mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease cmake --build . --config Release ./vsg_triangle # Windows 下为 vsg_triangle.exe开发期建议开启验证层以便排错在WindowTraits上设置windowTraits-debugLayer true;在create之后、Window::create之前或在 CMake 中定义VSG_DEBUG。5.6 运行效果程序会弹出一个窗口背景为窗口默认清屏色中央显示一个蓝色实心三角形。拖动窗口边缘缩放三角形应保持比例因为Perspective的宽高比在WindowResizeHandler作用下会自动随窗口更新。5.7 常见问题与调试现象可能原因排查/解决编译报错vsg/all.h: No such file未正确find_package(vsg)或头文件路径未加入确认 VSG 已安装且target_link_libraries(… vsg::vsg)运行时提示「无法创建 Vulkan 窗口」缺少 Vulkan 驱动 / ICD安装显卡厂商 Vulkan 驱动或用vulkaninfo验证黑屏但无崩溃顶点属性 location/format 与着色器不匹配核对addAttributeBinding的location、format与 GLSLlayout(location)一致三角形被拉伸变形投影矩阵宽高比错误用window-extent2D().width/height作为aspectRatio段错误在渲染前漏掉pipelineConfig-init()保证enableArray → init → copyTo顺序想看每一步的 Vulkan 调用——开启debugLayer true并配合 RenderDoc / 验证层日志5.8 小结VSG 程序的标准骨架是Viewer Window → 场景图StateGroup/Geometry→ 相机 → RenderGraph/CommandGraph → compile → 主循环管线推荐用ShaderSetGraphicsPipelineConfigurator声明式创建避免手写大量 Vulkan 样板vsg::Geometry用「顶点数组 索引 绘制命令」描述一次绘制主循环前必须compile()并updateViewer()。5.9 延伸阅读与下一章预告第 6 章《场景图基础》深入Node / Group / MatrixTransform / Switch的层次组织第 12 章《RenderGraph 与 CommandGraph 编译流程》理解 VSG 如何把场景图编译成 Vulkan 命令图的完整机制附录 API 速查表本章涉及的vsg::Viewer、vsg::Window、vsg::ShaderSet、vsg::GraphicsPipelineConfigurator、vsg::Geometry、vsg::Camera、vsg::RenderGraph、vsg::CommandGraph签名汇总。模板一致性提醒后续每一章请沿用本章的九段式结构目标 / 前置 / 完整代码 / 逐段解析 / 构建运行 / 效果 / 排错 / 小结 / 延伸代码均须对照include/vsg/实际 API 校验后再写入。
返回列表