ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

VulkanSceneGraph学习教程(二十一)

VulkanSceneGraph学习教程(二十一) 第 21 章 场景序列化摘要本章详细介绍了 VSGVulkan Scene Graph的场景序列化机制。通过对称的vsg::write()和vsg::read()API开发者可以将场景图保存为文本.vsgt或二进制.vsgb格式并在需要时恢复。文章涵盖了如何让自定义对象支持序列化、如何扩展文件格式支持并提供了常见问题的解决方案帮助读者掌握 VSG 场景持久化的完整流程。本章定位把场景图存盘、再读回来。VSG 内置一套对称的读写系统vsg::read/vsg::write核心是Object的read(Input)/write(Output)。21.1 本章目标用vsg::write()/vsg::read()保存与恢复场景了解原生格式.vsgt文本与.vsgb二进制让自己的Node子类可序列化实现read/write。21.2 准备工作第 6 章场景图节点与第 13 章加载模型已阅读vsg::read已在第 13 章用过。21.3 对称的读写 API写入boolvsg::write(ref_ptrObjectobject,constPathfilename,ref_ptrconstOptionsoptions{});读取第 13 章已见ref_ptrObjectvsg::read(constPathfilename,ref_ptrconstOptionsoptions{});二者根据扩展名选择编解码器。VSG 原生提供两种扩展名格式特点.vsgt文本ASCII可读、易调试、体积大.vsgb二进制紧凑、加载快// 保存vsg::write(scene,scene.vsgt);// 或 scene.vsgb// 加载autoloadedvsg::read(scene.vsgt);autonodevsg::ref_ptrvsg::Node(loaded);大多数核心类型Group/MatrixTransform/Geometry/StateGroup/Camera…都已实现read/write可直接序列化。glTF 读入后再write成.vsgb相当于做了一次格式转换与烘焙。21.4 让自己的对象可序列化只要你的类继承自vsg::Object或某个vsg::Node并实现read(vsg::Input)/write(vsg::Output)就能被vsg::write正确保存classMyNode:publicvsg::Inheritvsg::Node,MyNode{public:doublespeed1.0;vsg::ref_ptrvsg::Datapayload;voidread(vsg::Inputinput)override{Node::read(input);// 先读基类input.read(speed,speed);input.read(payload,payload);}voidwrite(vsg::Outputoutput)constoverride{Node::write(output);// 先写基类output.write(speed,speed);output.write(payload,payload);}};VSG_type_name(vsg::MyNode);// 注册类型名反序列化时能识别实战示例CustomMaterialNode下面是一个更完整的实战示例展示一个包含自定义材质属性和子节点引用的CustomMaterialNode类#includevsg/nodes/Group.h#includevsg/maths/vec4.h#includevsg/io/Input.h#includevsg/io/Output.h// 自定义材质节点包含颜色、光泽度等属性并可引用子节点classCustomMaterialNode:publicvsg::Inheritvsg::Group,CustomMaterialNode{public:// 自定义材质属性vsg::vec4 baseColor{1.0f,1.0f,1.0f,1.0f};// RGBA 颜色floatmetallic0.0f;// 金属度floatroughness0.5f;// 粗糙度floatemissiveStrength0.0f;// 自发光强度std::string materialNameDefaultMaterial;// 材质名称// 可选的纹理引用vsg::ref_ptrvsg::DatadiffuseTexture;vsg::ref_ptrvsg::DatanormalTexture;// 序列化将对象状态写入输出流voidwrite(vsg::Outputoutput)constoverride{// 1. 先序列化基类重要Group::write(output);// 2. 序列化自定义属性output.write(baseColor,baseColor);output.write(metallic,metallic);output.write(roughness,roughness);output.write(emissiveStrength,emissiveStrength);output.write(materialName,materialName);// 3. 序列化对象引用智能指针会自动处理引用计数output.write(diffuseTexture,diffuseTexture);output.write(normalTexture,normalTexture);// 4. 可以添加版本标记便于未来格式升级output.write(version,1);}// 反序列化从输入流读取对象状态voidread(vsg::Inputinput)override{// 1. 先反序列化基类重要Group::read(input);// 2. 读取自定义属性顺序应与 write 一致input.read(baseColor,baseColor);input.read(metallic,metallic);input.read(roughness,roughness);input.read(emissiveStrength,emissiveStrength);input.read(materialName,materialName);// 3. 读取对象引用input.read(diffuseTexture,diffuseTexture);input.read(normalTexture,normalTexture);// 4. 读取版本标记可根据版本进行兼容性处理intversion0;input.read(version,version);// 这里可以根据版本号进行不同的读取逻辑}};// 注册类型名必须在全局命名空间VSG_type_name(vsg::CustomMaterialNode);使用示例创建、序列化与反序列化// 1. 创建自定义材质节点并设置属性automaterialNodevsg::CustomMaterialNode::create();materialNode-baseColor{0.8f,0.2f,0.2f,1.0f};// 红色materialNode-metallic0.8f;materialNode-roughness0.3f;materialNode-materialNameRedMetal;// 2. 添加子节点可以是几何体、变换节点等autogeometryvsg::readvsg::Node(models/sphere.vsgb);if(geometry)materialNode-addChild(geometry);// 3. 加载纹理如果存在autotexturevsg::read_castvsg::Data(textures/red_diffuse.png);if(texture)materialNode-diffuseTexturetexture;// 4. 将自定义节点加入场景图autorootvsg::Group::create();root-addChild(materialNode);// 5. 序列化保存整个场景包含自定义节点vsg::write(root,scene_with_custom_material.vsgb);// 6. 反序列化恢复场景autorestoredScenevsg::readvsg::Node(scene_with_custom_material.vsgb);// 7. 验证恢复的数据if(autorestoredMaterialvsg::ref_ptr_castvsg::CustomMaterialNode(restoredScene)){std::cout恢复的材质名称: restoredMaterial-materialNamestd::endl;std::cout金属度: restoredMaterial-metallicstd::endl;std::cout粗糙度: restoredMaterial-roughnessstd::endl;std::cout子节点数量: restoredMaterial-children.size()std::endl;}关键要点继承链完整CustomMaterialNode继承自vsg::Group因此可以包含子节点类型注册必须VSG_type_name宏为类提供唯一字符串标识反序列化时用于创建正确类型的实例基类优先read/write中必须先调用基类的对应方法确保继承链上所有数据都被正确处理支持的类型VSG 的Input/Output支持基本类型int、float、double、向量vec2、vec3、vec4、矩阵、字符串、智能指针ref_ptr和标准容器版本控制通过添加版本字段可以在未来修改类结构时保持向后兼容性对象引用ref_ptrData等智能指针会被自动序列化和反序列化包括处理循环引用和共享对象VSG_type_name(...)给类一个字符串名序列化文件据此在读取时定位正确类型Input/Output提供read/write对各类型int/double/vec3/ref_ptrObject/数组等的重载读取时务必先读基类保证继承链完整。21.5 自定义文件格式ReaderWriter要支持自己的扩展名如.mymesh实现一个ReaderWriter子类并注册classMyReaderWriter:publicvsg::Inheritvsg::ReaderWriter,MyReaderWriter{public:vsg::ref_ptrvsg::Objectread(constvsg::Path,vsg::ref_ptrconstvsg::Options)constoverride;boolwrite(constvsg::Object*,constvsg::Path,vsg::ref_ptrconstvsg::Options)constoverride;};// 注册到 Options 的 readerWriters 列表vsg::read/write 即可识别生产实践模型/纹理通常交给vsgXchange.vsgt/.vsgb适合保存「已加载、已烘焙」的场景快照便于快速重开或跨会话复用。21.6 完整示例保存并恢复// 构建/加载一个场景autoscenevsg::readvsg::Node(models/duck.glTF);// 保存到原生格式vsg::write(scene,duck.vsgb);// 之后恢复可能在新进程里autorestoredvsg::readvsg::Node(duck.vsgb);root-addChild(restored);21.7 常见问题现象原因解决读取后类型丢失/报错没vsg::type_name或没先读基类注册类型名读取时先vsg::Base::read(input)自定义字段没保存没在vsg::read/vsg::write里处理对每字段调用input.read/input.write.vsgt巨大文本格式本就大发布/加载用.vsgb二进制读回场景不显示保存的不是vsg::Node或其子图断裂确认保存的是完整可渲染子树21.8 小结vsg::write/vsg::read对称按扩展名选编解码器.vsgt文本、.vsgb二进制自定义可序列化对象继承Object实现read/write并用VSG_type_name注册新格式通过ReaderWriter子类扩展。21.9 延伸阅读与下一章预告第 13 章《加载 3D 模型》vsg::read的来源第 22 章《ImGui 集成》序列化 UI 实时调参配合附录《API 速查表》序列化相关类型汇总。
返回列表