在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元素并绑定坐标的方式实现:
- 创建图标DOM元素(如
<img>),设置绝对定位、z-index等样式,确保能覆盖在Viewer画布上 - 调用
viewer.worldToClient(worldPos)将点击得到的世界坐标转换为客户端屏幕坐标 - 将转换后的坐标赋值给图标的
left和top样式,完成定位 - 把图标添加到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
相关产品推荐
相关产品推荐

