使用pythonOCC读取GLB文件自定义Extras/用户数据:RWGltf_CafReader导入支持及正确读取方案咨询
RWGltf_CafReader对GLB Extras的支持及正确读取方案
首先直接给你结论:RWGltf_CafReader 默认并不支持自动将GLB节点的extras字段映射回OCC的TDataStd_NamedData属性——这就是你导出时能成功写入,但读取时找不到对应属性的原因。OCC的GLTF/GLB导出逻辑里做了TDataStd_NamedData到extras的映射,但导入流程没有反向实现这个逻辑。
不过别担心,我们可以通过自定义节点回调的方式,手动把extras数据导入并关联到对应的模型形状Label上。下面是PythonOCC中的具体实现步骤:
1. 核心思路
利用RWGltf_CafReader提供的AddNodeCallback方法,注册一个回调函数。当读取GLB文件中的每个节点时,我们:
- 提取节点的
extras数据 - 通过读取上下文找到该节点对应的OCC Label
- 在Label上创建
TDataStd_NamedData属性,并写入extras中的键值对
2. 完整代码示例
from OCC.Core.RWGltf import RWGltf_CafReader, RWGltf_GltfNode from OCC.Core.TDocStd import TDocStd_Document from OCC.Core.TDataStd import TDataStd_NamedData from OCC.Core.TCollection import TCollection_ExtendedString from OCC.Core.XCAFApp import XCAFApp_Application from OCC.Core.XCAFDoc import XCAFDoc_DocumentTool_ShapeTool def handle_node_extras(reader_context, node): """回调函数:处理GLB节点的extras数据,关联到OCC Label""" # 获取节点的extras(如果存在) extras = node.Extras() if extras.IsNull(): return # 获取该节点对应的OCC Label label = reader_context.GetLabelForNode(node.Id()) if label.IsNull(): return # 创建或获取TDataStd_NamedData属性 named_data = TDataStd_NamedData() if not label.FindAttribute(TDataStd_NamedData.GetID(), named_data): named_data = TDataStd_NamedData.Set(label) # 遍历extras中的键值对,写入NamedData # 这里假设extras是简单的字符串键值对,复杂结构需要额外解析 keys = extras.GetKeys() for key in keys: value = extras.GetValue(key) # 根据值类型选择对应的Set方法,这里以字符串为例 named_data.SetString(TCollection_ExtendedString(key), TCollection_ExtendedString(value)) def read_glb_with_extras(glb_file_path): # 初始化文档和应用 app = XCAFApp_Application.GetApplication() doc = TDocStd_Document(TCollection_ExtendedString("GLBImport")) app.NewDocument(TCollection_ExtendedString("BinXCAF"), doc) # 初始化GLB读取器 reader = RWGltf_CafReader() reader.SetDocument(doc) # 注册节点回调 reader.AddNodeCallback(handle_node_extras) # 执行读取 if not reader.Read(glb_file_path): print("GLB文件读取失败") return None, None # 获取形状工具,用于后续访问模型形状 shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main()) return doc, shape_tool # 测试读取 if __name__ == "__main__": glb_path = "your_model.glb" doc, shape_tool = read_glb_with_extras(glb_path) if doc is None: exit() # 遍历所有形状Label,验证extras数据是否导入成功 labels = [] shape_tool.GetFreeShapes(labels) for label in labels: # 获取NamedData属性 named_data = TDataStd_NamedData() if label.FindAttribute(TDataStd_NamedData.GetID(), named_data): if named_data.HasStrings(): print("找到自定义数据:") # 遍历所有字符串属性 keys = named_data.GetStrings() for key in keys: value = named_data.GetString(key) print(f" {key}: {value}") # 也可以读取其他类型数据,比如整数、浮点数等 # if named_data.HasIntegers(): ...
3. 注意事项
- 数据类型匹配:如果导出时你用了
SetInteger/SetReal等方法存储数据,导入时要对应使用GetValueAsInteger/GetValueAsReal等方式解析extras中的值,再调用named_data.SetInteger/named_data.SetReal写入。 - 复杂extras结构:如果你的
extras是嵌套的JSON对象,需要手动解析成TDataStd_NamedData支持的简单类型,或者考虑用TDataStd_ByteArray存储序列化后的JSON字符串。 - 节点与Label的映射:确保回调中
reader_context.GetLabelForNode(node.Id())能正确拿到对应Label,对于组合模型,可能需要遍历子节点的Label来获取所有形状的自定义数据。
这样处理后,你就能同时读取GLB的模型形状和对应的自定义extras数据了。
内容的提问来源于stack exchange,提问作者Sankalp Dhupar
相关产品推荐
相关产品推荐

