Three.js raycasting检测时if else判断未按预期执行问题求助
Raycaster射线检测异常排查
问题现象
- 鼠标未指向目标物体时,代码正常打印
didnt touch日志 - 射线移动到目标物体范围后,
didnt touch日志停止输出,但预期的touch日志未打印 - 原有判断逻辑仅包含全等匹配、else两个分支,理论上仅存在两种执行结果,与实际运行表现不符
原实现代码:
function animate(){ renderer.render(scene,camera); sLightHelper.update(); rayCaster.setFromCamera(mousePosition,camera); var intersects = rayCaster.intersectObjects(scene.children); if ( house != undefined ){ for(let i = 0; i < intersects.length; i++){ if(intersects[0].object.id === house.ID){ console.log("touch"); } else{ console.log("didnt touch"); } } console.log("finished"); } else{ console.log('not ready') } }
根因分析
代码一共存在3个逻辑问题,共同导致了异常现象:
- 射线检测未开启递归遍历:
intersectObjects方法第二个参数默认值为false,仅检测场景的直接子节点,不会递归遍历Group等容器对象下的子网格。如果你的house是导入的模型组(Group类型本身无几何体,无法被射线直接命中),当鼠标指向house时,射线无法识别组内的子网格,返回的intersects为空数组,for循环完全不执行,自然不会打印任何分支的日志。而鼠标指向其他直接挂在场景下的独立模型时,intersects有值,就会进入else分支打印didnt touch,和观察到的现象完全吻合。 - 属性名大小写不匹配:Three.js所有Object3D实例的唯一自增id属性为全小写的
.id,判断时写的house.ID为大写,如果没有手动给house添加过大写ID属性,该值为undefined,永远不可能和数字类型的物体id相等,就算射线命中了house也不会进入touch分支。 - 循环逻辑错误:for循环定义了遍历索引
i,但判断时永远固定取intersects[0](最近的第一个命中物体),完全没有用到遍历索引,写了循环也不会遍历所有命中结果;且把日志打印放在循环内部,会导致一次检测命中多个物体时重复打印多次日志。
修复后代码
function animate(){ renderer.render(scene,camera); sLightHelper.update(); rayCaster.setFromCamera(mousePosition,camera); // 第二个参数传true开启递归,检测所有层级的子物体 const intersects = rayCaster.intersectObjects(scene.children, true); let isTouchHouse = false; if (house != undefined){ // 遍历所有命中物体,判断是否命中house或house的子物体 for(let i = 0; i < intersects.length; i++){ let curObj = intersects[i].object; // 向上查找父节点,匹配到house就标记为命中,适配Group类型的模型 while(curObj) { if(curObj.id === house.id) { // 统一用小写id做匹配 isTouchHouse = true; break; } curObj = curObj.parent; } if(isTouchHouse) break; } if(isTouchHouse) { console.log("touch"); } else { console.log("didnt touch"); } console.log("finished"); } else{ console.log('not ready') } }
内容的提问来源于stack exchange,提问作者Noone
相关产品推荐
相关产品推荐

