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

如何开发模型放置工具,解决TransformationExtension类工具拖拽时光标偏移问题

问题原因

偏移问题由两个核心错误导致:

  1. 现有代码直接将选中模型的自身坐标系原点绑定到光标碰撞点,但绝大多数模型的自身原点和几何包围盒中心并不重合,自然会产生固定间隙
  2. 原有hitTest的排除列表填写错误,拖拽过程中会命中正在移动的模型本身,进一步放大偏移误差

调整后的完整实现

首先在作用域内新增两个状态变量,记录拖拽初始状态:

let dragOffset = new THREE.Vector3(); // 存储光标与模型中心的初始偏移
let isDragging = false;

补充拖拽开始/结束的状态逻辑:

// 拖拽开始逻辑,绑定鼠标按下事件
document.onmousedown = (event) => {
  if (!event.ctrlKey || !this.selectedModel) return;
  // 计算初始点击的命中点,排除当前拖拽模型避免命中自身
  const hitRes = this.viewer.impl.hitTest(
    event.clientX,
    event.clientY,
    true,
    null,
    [this.selectedModel.getModelId()]
  );
  if (!hitRes) return;
  isDragging = true;
  // 计算选中模型世界坐标系下的包围盒中心
  const localBox = this.selectedModel.getBoundingBox();
  const localCenter = localBox.center();
  const worldCenter = this.selectedModel.getPlacementTransform().applyPoint(localCenter);
  // 计算光标命中点和模型中心的初始偏移
  dragOffset.copy(hitRes.intersectPoint).sub(worldCenter);
}

// 拖拽结束重置状态
document.onmouseup = () => {
  isDragging = false;
}

修改原有的鼠标移动逻辑:

document.onmousemove = (event) => {
  if (!event.ctrlKey || !isDragging || !this.selectedModel) return;

  let res = this.viewer.impl.hitTest(
      event.clientX,
      event.clientY,
      true,
      null,
      [this.selectedModel.getModelId()] // 修正排除列表,跳过当前拖拽的模型
  );
  let pt = null;

  if (res) {
      pt = res.intersectPoint;
  } else {
      pt = viewer.impl.intersectGround(event.clientX, event.clientY);
  }

  // 命中点减去初始偏移,得到模型实际要放置的位置
  const targetPos = pt.clone().sub(dragOffset);
  let tr = this.selectedModel.getPlacementTransform();
  tr.elements[12] = targetPos.x;
  tr.elements[13] = targetPos.y;
  tr.elements[14] = targetPos.z;
  this.selectedModel.setPlacementTransform(tr);
  this.viewer.impl.invalidate(true, true, true);
};

内容的提问来源于stack exchange,提问作者surya kumara

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 16:36:03