AFrame中向已有Object3D添加新对象时的位置偏移单位问题
解决GLTF模型子Object3D位置偏移的问题
这个问题的核心是你混淆了世界空间与模型局部空间的坐标/尺寸逻辑——当把bar添加到模型的object3D下时,它的位置是相对于模型局部坐标系的,但你用Box3.setFromObject获取的尺寸是世界空间的大小,完全没考虑模型自身的缩放、坐标系原点偏移这些因素。
最可靠的解决方案:坐标空间转换
直接计算目标位置的世界坐标,再转换为模型的局部坐标,不管模型有没有缩放、旋转,都能准确定位:
this.el.addEventListener('model-loaded', () => { this.bar = new MyCustomObject3D(); const modelObj = this.el.object3D; // 获取模型在世界空间的包围盒 const box = new THREE.Box3().setFromObject(modelObj); // 计算模型顶部上方1单位的世界空间位置(保持x/z轴居中) const targetWorldPos = new THREE.Vector3( box.getCenter(new THREE.Vector3()).x, box.max.y + 1, box.getCenter(new THREE.Vector3()).z ); // 将世界坐标转换为模型局部坐标系的坐标 modelObj.worldToLocal(targetWorldPos); // 设置bar的局部位置并添加到模型中 this.bar.position.copy(targetWorldPos); modelObj.add(this.bar); })
为什么之前需要乘25?
你提到的“乘以25”根本不是随机数——这应该是你GLTF模型缩放因子的倒数。比如如果给模型设置了scale="0.04 0.04 0.04",那么1 / 0.04 = 25。因为你计算的height = size.y +1是世界空间的尺寸,但添加到模型局部空间时,局部空间的1单位等于世界空间的scale.y单位,所以需要把世界空间的偏移量除以缩放因子,才能得到正确的局部空间偏移:
// 另一种方案:直接考虑模型缩放 this.el.addEventListener('model-loaded', () => { this.bar = new MyCustomObject3D(); const modelObj = this.el.object3D; const size = new THREE.Vector3(); const box = new THREE.Box3().setFromObject(modelObj); box.getSize(size); // 获取模型的局部缩放因子 const scale = modelObj.scale.y; // 计算局部空间的偏移量:世界空间高度/缩放 + 世界空间偏移/缩放 const localHeightOffset = (size.y / scale) + (1 / scale); this.bar.position.set(0, localHeightOffset, 0); modelObj.add(this.bar); })
额外注意:GLTF模型的原点问题
很多GLTF模型的原点默认在模型中心(而非底部),这也是直接用size.y计算会出错的原因之一。上面的两种方案都自动处理了这个问题:第一种通过世界空间的box.max.y直接获取模型顶部的世界坐标,第二种通过size.y/scale得到模型局部空间的实际高度,再加上偏移。
内容的提问来源于stack exchange,提问作者Nikita Fedorov
相关产品推荐
相关产品推荐

