Three.js traverse无法遍历GLTF模型后代节点问题排查
A-Frame加载GLTF后traverse仅获取顶层节点问题
问题复现代码
let arHolder = $('#arHolder'); let gltfFilePath = MY_GLTF_PATH; // 动态构建AR场景 let sceneElement = document.createElement('a-scene'); sceneElement.setAttribute("embedded", ''); sceneElement.setAttribute("arjs", ''); let markerElement = document.createElement('a-marker'); markerElement.setAttribute("preset", 'hiro'); let glftElement = document.createElement('a-entity'); glftElement.setAttribute("id", 'glftElement'); glftElement.setAttribute("gltf-model", gltfFilePath); let cameraElement = document.createElement('a-entity'); cameraElement.setAttribute("camera", ''); markerElement.append(glftElement); sceneElement.append(markerElement); sceneElement.append(cameraElement); arHolder.append(sceneElement); sceneElement.addEventListener("loaded", (event) => { var gltfScene = document.querySelector('#glftElement').object3D; gltfScene.traverse( function( node ) { console.log(node); console.log("NAME:", node.name); }); });
上述代码预期通过traverse方法递归获取GLTF场景下所有节点名称,实际运行仅返回1个顶层节点,但在Chrome控制台手动检查gltfScene对象时,能看到内部存在完整的meshes网格对象。
问题原因
- 触发时机错误:
a-scene的loaded事件仅代表A-Frame场景基础框架初始化完成,不代表gltf-model组件已经完成模型资源的拉取、解析和子节点挂载。执行traverse逻辑时,GLTF模型的子节点还未被添加到对应a-entity的object3D对象上,因此只能拿到初始的空顶层占位节点。 - Chrome控制台的对象打印是懒加载机制:你在控制台展开对象看到的meshes,是你手动展开对象那一刻的对象状态——此时模型已经异步加载完成,子节点已经挂载,并不代表你执行traverse代码的时间点,对象上已经存在这些子节点。
修复方案
移除对a-scene loaded事件的监听,改为监听gltf-model组件专属的model-loaded事件,该事件会在模型完全解析、所有子节点挂载完成后触发,此时执行遍历即可拿到全部节点,核心修改代码如下:
// 给GLTF实体绑定模型加载完成事件 glftElement.addEventListener("model-loaded", () => { const gltfScene = document.querySelector('#glftElement').object3D; gltfScene.traverse( (node) => { console.log(node); console.log("NAME:", node.name); // 如需操作网格、材质,可在这里判断节点类型 if (node.isMesh) { // 自定义网格处理逻辑 } }); });
注意:所有依赖GLTF模型节点的操作(比如修改材质、添加动画、调整网格位置)都需要放在
model-loaded事件回调中执行,避免出现拿不到目标节点的问题。
内容的提问来源于stack exchange,提问作者Doug
相关产品推荐
相关产品推荐

