Three.js 如何替换 Object3D 的模型且保留位置等原有属性?
Three.js Object3D模型替换(保留原有属性)实现方案
你原有代码直接给object变量重新赋值新克隆模型的写法是错误的:重新赋值只会改变变量指向的内存地址,既不会保留原有实例的位置等属性,也不会自动更新场景内已挂载的对象。
核心实现思路是:不替换绑定了变换属性的根实例,只替换根实例下的模型子节点,所有位置、旋转、缩放、可见性等属性都挂载在持久化的根容器上,替换时仅更新子节点和动画实例即可。
实现步骤
1. 调整初始化逻辑,拆分持久化根容器和模型子节点
// 创建持久化根容器,所有变换属性都绑定在这个容器上,永远不会被替换 const characterRoot = new THREE.Object3D(); characterRoot.position.set(100, 230, 15); scene.add(characterRoot); // 初始化挂载第一个角色模型 let currentCharacter = models.character[0].clone(); characterRoot.add(currentCharacter.scene); // 初始化动画 let mixer = new THREE.AnimationMixer(currentCharacter.scene); const idleClip = THREE.AnimationClip.findByName(currentCharacter.animations, 'idle'); let currentAction = mixer.clipAction(idleClip); currentAction.play();
2. 模型替换核心逻辑
function replaceModel(newModelIndex) { // 移除旧模型节点 characterRoot.remove(currentCharacter.scene); // 销毁旧动画实例,避免内存泄漏 currentAction.stop(); mixer.uncacheAction(currentAction); mixer.uncacheRoot(currentCharacter.scene); // 挂载新模型节点 currentCharacter = models.character[newModelIndex].clone(); characterRoot.add(currentCharacter.scene); // 初始化新模型动画 mixer = new THREE.AnimationMixer(currentCharacter.scene); const newIdleClip = THREE.AnimationClip.findByName(currentCharacter.animations, 'idle'); currentAction = mixer.clipAction(newIdleClip); currentAction.play(); } // 调用方法替换为第二个角色 replaceModel(1);
特殊场景适配
如果你的业务场景不能用根容器拆分,确实需要直接替换整个Object3D实例,可以手动拷贝旧实例的所有属性到新实例:
const oldModel = object; object = models.character[1].clone(); // 拷贝所有变换属性 object.position.copy(oldModel.position); object.rotation.copy(oldModel.rotation); object.scale.copy(oldModel.scale); // 拷贝其他自定义属性 object.visible = oldModel.visible; object.layers = oldModel.layers; object.userData = {...oldModel.userData }; // 更新场景挂载 scene.remove(oldModel.scene); scene.add(object.scene); // 后续再自行更新动画实例即可
该方案需要手动同步所有用到的自定义属性,容易漏项,非特殊情况不推荐使用。
内容的提问来源于stack exchange,提问作者Vardan Betikyan
相关产品推荐
相关产品推荐

