ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

VulkanSceneGraph学习教程(二十四)

2026/8/23 6:45:55 拓冰建站 浏览量
VulkanSceneGraph学习教程(二十四) 第 24 章 简易 3D 模型查看器综合实战摘要本章通过一个完整的 3D 模型查看器实战项目将前 23 章的核心知识模型加载、轨道相机、光照、渲染装配、ImGui 面板整合应用。读者将学会使用vsg::Trackball实现鼠标拖拽旋转与滚轮缩放通过createRenderGraphForView自动添加头灯并可选集成调试面板。项目代码约 200 行涵盖从 CMake 配置、模型加载、相机设置到事件处理与渲染循环的全流程是 VSG 教程系列的第一个完整应用案例。本章定位把前 23 章串起来——加载模型、轨道相机、光照、可选调试面板做一个能转、能缩放、能看的小查看器。这是整套教程第一个完整应用。24.1 本章目标整合加载第 13 章 轨道相机Trackball 头灯第 16 章 渲染装配第 12 章用vsg::Trackball实现鼠标拖拽旋转、滚轮缩放可选接入 ImGui 面板第 22 章做实时控制。24.2 前置准备已装VSGXchange模型加载第 5、12、13、16 章已读了解vsg::Trackballapp/Trackball.h内置相机操纵器。24.3 CMakecmake_minimum_required(VERSION 3.7) project(vsg_viewer) set(CMAKE_CXX_STANDARD 17) find_package(vsg REQUIRED) find_package(vsgXchange REQUIRED) # find_package(vsgImGui REQUIRED) # 若启用调试面板 add_executable(vsg_viewer main.cpp) target_link_libraries(vsg_viewer PRIVATE vsg::vsg vsgXchange::vsgXchange)24.4 完整main.cpp#includevsg/all.h// 辅助函数处理编译结果若编译失败则退出voidupdateViewer(vsg::ref_ptrvsg::Viewerviewer,constvsg::CompileResultcompileResult){if(compileResult.result!VK_SUCCESS){std::cerr渲染图编译失败错误码 compileResult.result\n;exit(1);}// 编译成功后Viewer 已准备好渲染}intmain(intargc,char**argv){// 1) 窗口与 Viewerautowindowvsg::Window::create(vsg::WindowTraits::create(1024,768,VSG Model Viewer));if(!window||!window-valid()){std::cerr窗口创建失败\n;return1;}autoviewervsg::Viewer::create();viewer-addWindow(window);// 2) 加载模型需 vsgXchangeautopath(argc1)?argv[1]:models/duck.gltf;automodelvsg::readvsg::Node(path);if(!model){std::cerr模型加载失败 path\n;return1;}// 3) 缩放/定位按需调整autoxformvsg::MatrixTransform::create(vsg::scale(1.0,1.0,1.0));xform-addChild(model);// 4) 相机autocameravsg::Camera::create();doubleaspectstatic_castdouble(window-extent2D().width)/window-extent2D().height;camera-projectionMatrixvsg::Perspective::create(60.0,aspect,0.1,100.0);camera-viewMatrixvsg::LookAt::create(vsg::dvec3(0.0,1.0,4.0),vsg::dvec3(0.0,0.0,0.0),vsg::dvec3(0.0,1.0,0.0));camera-viewportStatevsg::ViewportState::create(window-extent2D());// 5) 轨道相机内置操纵器拖拽旋转、滚轮缩放viewer-addEventHandler(vsg::Trackball::create(camera,window));// 6) 渲染装配assignHeadlighttrue 自动加一盏头灯第 16 章// 使用 createRenderGraphForView 创建完整的渲染图它已包含命令图autorenderGraphvsg::createRenderGraphForView(window,camera,xform,VK_SUBPASS_CONTENTS_INLINE,true);// 将渲染图而非独立的 commandGraph分配给 Viewerviewer-assignRecordAndSubmitTaskAndPresentation({renderGraph});// 7) 编译 主循环autocompileResultviewer-compile();updateViewer(viewer,compileResult);while(viewer-advanceToNextFrame()){viewer-handleEvents();// 处理 Trackball 等事件viewer-update();// 动画等viewer-recordAndSubmit();viewer-present();}return0;}24.5 关键点解析vsg::Trackball::create(camera, window)内置相机操纵器监听PointerEvent/ScrollEvent更新camera-viewMatrix。无需自己写事件处理见第 19/22 章的自定义事件思路。assignHeadlighttruecreateRenderGraphForView自动在场景里加createHeadlight()环境光 方向光否则模型可能全黑。缩放xform上的MatrixTransform控制模型大小也可在Trackball里滚轮缩放默认改距离。坐标/轴向glTF 是 Y-up若模型「躺平」在加载Options里处理轴向第 13 章或给xform加一个旋转。24.6 可选加上 ImGui 面板第 22 章// 链接 vsgImGui 后#includevsgImGui/RenderImGui.h#includevsgImGui/implot.h// 自定义 ImGui 面板类继承自 vsgImGui::RenderImGuiclassMyGui:publicvsgImGui::RenderImGui{public:MyGui(vsg::ref_ptrvsg::Cameracamera,vsg::ref_ptrvsg::floatValueexposure):vsgImGui::RenderImGui(),_camera(camera),_exposure(exposure),_wireframe(false),_initialViewMatrix(camera-viewMatrix){}// 静态创建函数便于使用staticvsg::ref_ptrMyGuicreate(vsg::ref_ptrvsg::Cameracamera,vsg::ref_ptrvsg::floatValueexposure){returnvsg::ref_ptrMyGui(newMyGui(camera,exposure));}protected:// 重写 renderUI 方法绘制 ImGui 界面voidrenderUI()override{// 开始新窗口ImGui::Begin(VSG 查看器控制面板,nullptr,ImGuiWindowFlags_AlwaysAutoResize);// 1) 曝光度滑块ImGui::Text(曝光控制);floatexposureValue_exposure-value();if(ImGui::SliderFloat(曝光度,exposureValue,0.1f,5.0f,%.2f)){_exposure-set(exposureValue);}ImGui::SameLine();if(ImGui::Button(重置曝光)){_exposure-set(1.0f);}ImGui::Separator();// 2) 线框模式切换按钮ImGui::Text(渲染模式);if(ImGui::Checkbox(线框模式,_wireframe)){// 这里可以添加线框模式切换逻辑// 例如切换渲染管线状态// 实际项目中可能需要修改渲染状态或着色器}ImGui::SameLine();ImGui::TextDisabled((?));if(ImGui::IsItemHovered()){ImGui::SetTooltip(切换模型线框显示模式);}ImGui::Separator();// 3) 相机复位功能ImGui::Text(相机控制);if(ImGui::Button(相机复位)){if(_camera){// 恢复相机到初始视图矩阵_camera-viewMatrix_initialViewMatrix;}}ImGui::SameLine();if(ImGui::Button(保存当前视角)){if(_camera){_initialViewMatrix_camera-viewMatrix;}}ImGui::Separator();// 显示当前相机信息ImGui::Text(相机信息);if(_camera){autolookAt_camera-viewMatrix.castvsg::LookAt();if(lookAt){autoeyelookAt-eye;ImGui::Text(相机位置: (%.2f, %.2f, %.2f),eye.x,eye.y,eye.z);}}ImGui::End();}private:vsg::ref_ptrvsg::Camera_camera;vsg::ref_ptrvsg::floatValue_exposure;bool_wireframe;vsg::dmat4 _initialViewMatrix;};// 在主函数中使用autoexposurevsg::floatValue::create(1.0f);autoguiMyGui::create(camera,exposure);// 创建自定义 ImGui 面板xform-addChild(gui);// 叠加到场景viewer-addEventHandlers({vsgImGui::CollectEvents::create(gui)});// 收集 ImGui 事件面板里可实时调曝光、线框开关、相机复位等。完整的MyGui类继承自vsgImGui::RenderImGui重写renderUI()方法实现曝光度滑块通过vsg::floatValue共享变量控制曝光支持滑块调节和重置按钮。线框模式切换复选框控制线框显示状态实际项目中需配合渲染管线状态切换。相机复位按钮将相机视图矩阵恢复到初始状态支持保存当前视角。相机信息显示实时显示相机位置坐标。使用时需链接vsgImGui库并在 CMake 中取消注释find_package(vsgImGui REQUIRED)和相应的链接指令。24.7 常见问题现象原因解决模型全黑没头灯且材质需光照createRenderGraphForView(..., true)或自加DirectionalLight拖不动没加Trackballviewer-addEventHandler(vsg::Trackball::create(camera, window))模型太小/太大缩放或相机距离不当调xform的scale或相机eye距离加载失败没链vsgXchangefind_package(vsgXchange) 链接24.8 小结一个查看器 窗口/Viewer 加载模型 MatrixTransform 相机 TrackballcreateRenderGraphForView 主循环Trackball提供开箱即用的轨道交互assignHeadlighttrue保证有光用 ImGui 面板把查看器升级成可调参工具。24.9 延伸阅读与下一章预告第 25 章《性能优化指南》让查看器应对大模型不卡。第 26 章《常见问题与调试技巧》验证层 RenderDoc 排错。第 16/22 章扩展光照与 UI。