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

在Autodesk平台实现点击位置放置图标及遮挡功能的技术咨询

Forge Viewer 点击位置放置图标及遮挡实现方案

1. 计算点击位置

通过Viewer内置的clientToWorld(x, y, ignoreTransparent)方法直接获取点击位置的世界坐标:

  • 监听Viewer的click事件,从事件对象中提取客户端坐标event.clientX和event.clientY
  • 调用viewer.clientToWorld(clientX, clientY, true),第三个参数设为true会忽略透明物体,确保点击到实体表面
  • 方法返回Autodesk.Viewing.IntersectResult对象,其中point属性就是点击位置的三维世界坐标(THREE.Vector3类型)

示例代码:

viewer.addEventListener('click', (event) => {
  const { clientX, clientY } = event;
  const intersectResult = viewer.clientToWorld(clientX, clientY, true);
  if (intersectResult) {
    const clickWorldPos = intersectResult.point;
    // 后续使用该坐标
  }
});

2. 在点击位置设置图标

通过创建DOM元素并绑定坐标的方式实现:

  1. 创建图标DOM元素(如<img>),设置绝对定位、z-index等样式,确保能覆盖在Viewer画布上
  2. 调用viewer.worldToClient(worldPos)将点击得到的世界坐标转换为客户端屏幕坐标
  3. 将转换后的坐标赋值给图标的left和top样式,完成定位
  4. 把图标添加到Viewer的容器元素中(viewer.container)

示例代码:

function addIconAtWorldPos(worldPos, iconUrl) {
  const icon = document.createElement('img');
  icon.src = iconUrl;
  icon.style.position = 'absolute';
  icon.style.width = '32px';
  icon.style.height = '32px';
  icon.style.zIndex = 100;
  icon.style.pointerEvents = 'none'; // 避免遮挡Viewer交互

  // 转换坐标并定位
  const clientPos = viewer.worldToClient(worldPos);
  icon.style.left = `${clientPos.x - 16}px`; // 减去图标一半宽度,居中显示
  icon.style.top = `${clientPos.y - 16}px`;

  viewer.container.appendChild(icon);
  return icon;
}

// 在click事件中调用
viewer.addEventListener('click', (event) => {
  const { clientX, clientY } = event;
  const intersectResult = viewer.clientToWorld(clientX, clientY, true);
  if (intersectResult) {
    addIconAtWorldPos(intersectResult.point, '/path/to/your/icon.png');
  }
});

3. 实现遮挡(Occlusion)功能

要让图标被模型遮挡时隐藏,可通过实时检测图标位置与相机之间是否有模型阻挡实现:

  • 监听Viewer的render事件,每次渲染时检查所有图标的可见性
  • 对每个图标,将其世界坐标与相机位置创建一条射线,调用viewer.impl.rayCast检测射线与模型的交点
  • 如果交点距离相机的距离小于图标到相机的距离,说明图标被遮挡,隐藏图标;反之则显示

示例代码:

// 存储所有添加的图标及其世界坐标
const icons = [];

function addIconAtWorldPos(worldPos, iconUrl) {
  const icon = document.createElement('img');
  // ... 图标样式设置(同之前代码)
  
  viewer.container.appendChild(icon);
  icons.push({ icon, worldPos });
  return icon;
}

// 监听render事件,实时更新图标可见性
viewer.addEventListener('render', () => {
  const camera = viewer.getCamera();
  icons.forEach(({ icon, worldPos }) => {
    // 创建从相机到图标位置的射线
    const ray = new THREE.Raycaster(camera.position, worldPos.clone().sub(camera.position).normalize());
    // 检测射线与模型的交点
    const intersects = viewer.impl.rayCast(ray, true);
    if (intersects.length > 0) {
      // 计算交点到相机的距离
      const intersectDist = camera.position.distanceTo(intersects[0].point);
      // 计算图标到相机的距离
      const iconDist = camera.position.distanceTo(worldPos);
      // 如果交点更近,说明被遮挡
      icon.style.visibility = intersectDist < iconDist - 0.1 ? 'hidden' : 'visible'; // 加小偏移避免精度问题
    } else {
      icon.style.visibility = 'visible';
    }
  });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 03:08:20