You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js使用DragControls拖动时如何将相机子立方体转移至场景

解决方案

有两种无需修改DragControls源码的实现方式,优先推荐第二种:

方案1:手动修正DragControls内部偏移量

DragControls的_offset属性虽然是私有命名,但可以直接访问覆盖。你只需要在调整完对象父级和位置后,重新计算正确的偏移量覆盖原有值即可:

dragControls.addEventListener( 'dragstart', function (event) {
    orbitControls.enabled = false;
    const obj = event.object;
    const vec3 = new THREE.Vector3();

    if(obj.parent.type === "OrthographicCamera") {
        // 保存点击位置的世界坐标
        const clickWorldPos = dragControls._pickedPoint.clone();
        // 转移父级并更新位置
        scene.attach(obj);
        obj.position.set(5, 0, 0);
        obj.updateMatrixWorld(true);
        // 重新计算正确偏移量
        obj.getWorldPosition(vec3);
        dragControls._offset.copy(clickWorldPos).sub(vec3);
    }
} );

方案2:捕获阶段提前处理父级转移

利用DOM事件的捕获优先机制,在DragControls的mousedown事件触发前就完成对象父级转移和位置更新,这样DragControls计算偏移时用的就是最新的正确状态:

// 提前初始化射线和鼠标向量复用
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const targetCube = /* 你的立方体对象 */;

// 绑定捕获阶段的mousedown事件,优先级高于DragControls的冒泡阶段监听
renderer.domElement.addEventListener('mousedown', (e) => {
    // 计算鼠标标准化坐标
    mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
    // 射线检测判断是否点击了目标立方体
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObject(targetCube);
    
    if (intersects.length) {
        const obj = intersects[0].object;
        if (obj.parent.type === "OrthographicCamera") {
            scene.attach(obj);
            obj.position.set(5, 0, 0);
            obj.updateMatrixWorld(true);
        }
    }
}, true); // 第三个参数设为true表示启用捕获阶段监听

方案2完全使用Three.js公开API实现,不依赖DragControls的内部属性命名,后续版本升级也不会出现兼容性问题,是更稳定的选择。


内容的提问来源于stack exchange,提问作者David B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 12:54:04