Viewer.rayIntersect未按预期忽略透明对象问题求助
看来你在Forge Viewer 3.1里用viewer.rayIntersect的时候碰到了两个头疼的问题:一是会命中透明对象,二是交点莫名其妙悬浮在空中——其实是命中了不可见的Room Geometry。从你贴的代码片段能找到问题根源,咱们一步步来解决:
问题根源分析
你贴的代码里,_modelQueue.rayIntersect确实支持ignoreTransparent参数来过滤透明对象,但后面调用的avp.VBIntersector.intersectObject完全没做过滤逻辑:它会递归检测sceneAfter下的所有对象,包括透明对象和不可见的Room Geometry,而且如果这部分检测到的交点距离更近,就会覆盖前面的正确结果,这就是你看到的交点悬浮、命中透明对象的原因。
解决方案1:过滤VBIntersector的检测结果
最简单的方法就是在获取intersects数组后,手动过滤掉不符合要求的对象,修改原代码即可:
// ... 原代码部分 if (this.sceneAfter.children.length) { var raycaster = new THREE.Raycaster(ray.origin, ray.direction, this.camera.near, this.camera.far); var intersects = []; avp.VBIntersector.intersectObject(this.sceneAfter, raycaster, intersects, true); // 新增:过滤掉不可见、透明和Room Geometry对象 const filteredIntersects = intersects.filter(intersect => { const obj = intersect.object; // 排除不可见对象 if (!obj.visible) return false; // 排除透明对象(注意考虑材质数组的情况) const isTransparent = Array.isArray(obj.material) ? obj.material.some(m => m.transparent) : obj.material?.transparent; if (isTransparent) return false; // 排除Room Geometry(根据实际对象的名称/标记调整判断条件) if (obj.name.includes('Room') || obj.userData?.isRoomGeometry) return false; return true; }); if (filteredIntersects.length) { if (!result || filteredIntersects[0].distance < result.distance) { result = filteredIntersects[0]; } } } // ... 原代码部分
解决方案2:自定义完整的射线检测逻辑
如果不想修改原viewer的代码逻辑,可以自己实现一套射线检测流程,严格控制要检测的对象:
function customRayIntersect(viewer, ray) { const allIntersects = []; // 1. 检测模型队列,忽略透明对象 viewer.impl.modelQueue.rayIntersect(ray.origin, ray.direction, true, null, null, allIntersects); // 2. 检测sceneAfter,只保留符合要求的对象 const raycaster = new THREE.Raycaster(ray.origin, ray.direction, viewer.camera.near, viewer.camera.far); const validSceneObjects = []; // 递归遍历sceneAfter,收集可见、非透明、非Room的对象 function collectValidObjects(obj) { if (!obj.visible) return; const isTransparent = Array.isArray(obj.material) ? obj.material.some(m => m.transparent) : obj.material?.transparent; if (isTransparent) return; if (obj.name.includes('Room') || obj.userData?.category === 'Room') return; validSceneObjects.push(obj); obj.children.forEach(collectValidObjects); } collectValidObjects(viewer.impl.sceneAfter); const sceneIntersects = raycaster.intersectObjects(validSceneObjects, true); // 3. 合并所有结果,取距离最近的交点 const combined = [...allIntersects, ...sceneIntersects]; if (combined.length === 0) return null; combined.sort((a, b) => a.distance - b.distance); return combined[0]; } // 使用示例:创建射线并调用自定义检测 const mouseX = viewer.canvas.clientX; const mouseY = viewer.canvas.clientY; const ray = viewer.impl.createRay(mouseX, mouseY); const hitResult = customRayIntersect(viewer, ray);
解决方案3:从根源隐藏干扰的Room Geometry
如果Room Geometry完全不需要参与任何交互,可以在模型加载完成后直接把它们设为不可见,从根源上避免被射线检测到:
// 隐藏所有Room Geometry的函数 function hideRoomGeometry(viewer) { function traverseScene(obj) { // 根据实际情况调整判断条件,比如名称包含Room,或者userData里的标记 if (obj.name.includes('Room') || obj.userData?.isRoom) { obj.visible = false; } obj.children.forEach(traverseScene); } traverseScene(viewer.impl.sceneAfter); } // 模型加载完成后执行 viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, () => { hideRoomGeometry(viewer); });
内容的提问来源于stack exchange,提问作者Naoric
相关产品推荐
相关产品推荐

