Three.js中为导入的Blender玫瑰模型绑定Cannon-es物理体时的位置更新问题
问题分析与解决方案
你遇到的核心问题是GLTF模型加载是异步操作,你的代码把物理体创建和objectsToUpdate数组的更新放在了加载回调外面,这时候rose变量根本没被正确赋值(回调里的rose是局部变量,外面的作用域拿不到它),所以在tick函数里访问object.roseAndBody.rose.position时,这个rose是undefined,自然会提示不存在position属性。
修复步骤
- 将物理体逻辑移到加载回调内:确保只有当模型成功加载并获取到
rose对象后,才创建对应的物理体并将两者关联存入更新数组。 - 同步物理体初始位置:利用函数传入的
px, py, pz设置物理体初始位置,贴合你调用函数时的预期,而不是固定的(0,3,0)。 - 优化变量作用域:彻底避免异步导致的变量未初始化问题。
修改后的代码
const objectsToUpdate = [] const createRose = (px, py, pz, rx, ry, rz) =>{ gltfLoader.load('/models/pieces/Rose.glb', (gltf) =>{ let rose = gltf.scene.children[0] rose.position.set(px, py, pz) rose.rotation.set(rx, ry, rz) scene.add(rose) // Cannon.js 物理体 - 移到回调内,确保rose已有效存在 const shape = new CANNON.Cylinder(2, 1, 5, 20) const body = new CANNON.Body({ mass: 1, position: new CANNON.Vec3(px, py, pz), // 使用传入的初始位置 shape: shape, material: defaultMaterial }) world.addBody(body) // 存入更新数组 - 此时rose是有效的模型对象 objectsToUpdate.push({ roseAndBody:{ rose: rose, body: body } }) }) }
你的tick函数代码不需要修改,现在objectsToUpdate里的每一项都包含有效的rose模型和对应的物理体,位置与四元数的同步逻辑就能正常运行了。
额外提示
- 如果你要加载多个玫瑰,这个逻辑依然适用,每个模型加载完成后才会绑定物理体,不会再出现未初始化的问题。
- 若尝试其他物理库(比如Ammo.js),核心逻辑完全一致:必须等待模型异步加载完成后,再创建物理体并建立关联。
- 可以在加载过程中添加简单的加载提示(比如一个旋转的Three.js网格),避免加载时的空白等待,提升体验。
内容的提问来源于stack exchange,提问作者Cody Luketic
相关产品推荐
相关产品推荐

