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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:43:41