如何遍历C++中深度未知的嵌套Assembly结构下的所有Model?
嵌套渲染架构的Model遍历方案
下面提供几种直接可用的实现方式,都不需要复制Model数据,适配你当前的架构:
1. 基于回调的递归遍历(推荐)
这种方式不需要额外存储Model,直接在遍历过程中处理数据,适合构建加速结构、光栅化这类实时处理场景。
首先给Assembly类添加一个接受回调的遍历方法:
class Assembly { // 原有成员:std::vector<std::shared_ptr<Model>> models; // std::vector<std::shared_ptr<Assembly>> assemblies; public: void traverseModels(const std::function<void(std::shared_ptr<Model>&)>& callback) { // 先处理当前Assembly下的Model for (auto& model : models) { callback(model); } // 递归处理子Assembly for (auto& sub_assembly : assemblies) { sub_assembly->traverseModels(callback); } } };
然后在Universe中封装统一的遍历入口:
class Universe { // 原有成员:std::vector<std::shared_ptr<Model>> models; // std::vector<std::shared_ptr<Assembly>> assemblies; public: void traverseAllModels(const std::function<void(std::shared_ptr<Model>&)>& callback) { // 处理直接属于Universe的Model for (auto& model : models) { callback(model); } // 遍历所有Assembly及其嵌套结构 for (auto& assembly : assemblies) { assembly->traverseModels(callback); } } };
使用时只需要传入处理逻辑即可,比如构建光线追踪加速结构:
Universe my_universe; BVHBuilder bvh_builder; // 遍历所有Model并添加到BVH my_universe.traverseAllModels([&](std::shared_ptr<Model>& model) { bvh_builder.add_model_geometry(model->get_geometry()); });
2. 收集Model引用的批量遍历
如果需要多次复用全量Model列表,可以收集所有Model的引用(而非复制),避免重复递归遍历:
在Assembly中添加收集方法:
class Assembly { public: void collectModels(std::vector<std::reference_wrapper<std::shared_ptr<Model>>>& out_models) { for (auto& model : models) { out_models.emplace_back(model); } for (auto& sub_assembly : assemblies) { sub_assembly->collectModels(out_models); } } };
在Universe中实现全量Model引用的获取:
class Universe { public: std::vector<std::reference_wrapper<std::shared_ptr<Model>>> getAllModels() { std::vector<std::reference_wrapper<std::shared_ptr<Model>>> all_models; // 添加直接属于Universe的Model for (auto& model : models) { all_models.emplace_back(model); } // 添加所有Assembly中的Model for (auto& assembly : assemblies) { assembly->collectModels(all_models); } return all_models; } };
使用时可以直接遍历引用列表:
auto all_models = my_universe.getAllModels(); for (auto& model_ref : all_models) { auto& model = model_ref.get(); // 执行光栅化或其他处理逻辑 rasterizer.submit_model(model); }
这里存储的是shared_ptr<Model>的引用,不会复制Model数据,仅维护引用关系。
3. 架构重构(简化层级)
如果后续需要频繁扩展场景节点逻辑,可以将Universe和Assembly抽象为统一的SceneNode类,减少层级区分的复杂度:
// 通用场景节点,包含Model和子节点 class SceneNode { public: std::vector<std::shared_ptr<Model>> models; std::vector<std::shared_ptr<SceneNode>> children; void traverseModels(const std::function<void(std::shared_ptr<Model>&)>& callback) { for (auto& model : models) callback(model); for (auto& child : children) child->traverseModels(callback); } }; // Universe作为根节点,扩展自身的管理功能 class Universe : public SceneNode { // 新增专属成员:比如相机、渲染设置、全局光源等 std::shared_ptr<Camera> main_camera; RenderSettings render_settings; };
这种重构后,所有遍历逻辑完全统一,不需要区分Universe和Assembly的处理流程,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者Chris Gnam
相关产品推荐
相关产品推荐

