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

WebXR图像追踪结合ThreeJS实现AR拖拽时交集数组为空问题

问题分析与解决方案

核心问题1:模型矩阵更新未同步到世界矩阵

你设置了mesh.matrixAutoUpdate = false并手动赋值矩阵,但没有标记世界矩阵需要更新,导致射线检测时模型的世界位置还是初始值,无法被射线命中。

修改代码:
在设置mesh.matrix.fromArray(pose.transform.matrix)后,添加:

mesh.matrixWorldNeedsUpdate = true;

同理,若启用mesh2,也要做同样修改。

核心问题2:射线检测未递归子对象

GLTF加载的模型是THREE.Scene实例,实际可交互的网格是它的子对象。你当前的射线检测raycaster.intersectObjects(group.children, false)第二个参数为false,不会递归检测子对象,只能检测到空的Scene容器,无法命中实际网格。

修改代码:
将getIntersections函数里的检测代码改为:

return raycaster.intersectObjects(group.children, true);

核心问题3:OrbitControls干扰AR相机姿态

AR模式下,相机姿态由WebXR会话控制,初始化的OrbitControls会覆盖相机的位置和旋转,导致射线计算的相机/控制器姿态错误。

修改代码:
在init函数中初始化OrbitControls后,添加会话状态监听:

// 初始化OrbitControls后添加
controls.enabled = !renderer.xr.isPresenting;
// 监听XR会话状态,自动禁用/启用控制器
renderer.xr.addEventListener('sessionstart', () => {
  controls.enabled = false;
});
renderer.xr.addEventListener('sessionend', () => {
  controls.enabled = true;
});

核心问题4:手持AR设备的射线适配错误

手机触屏的AR控制器,目标射线模式是screen,而非VR手柄的tracked-pointer,当前基于控制器世界矩阵计算射线的方式不适合触屏,需要适配屏幕触摸点生成射线。

修改代码:
修改getIntersections函数,根据控制器的targetRayMode调整射线计算逻辑:

function getIntersections(controller) {
  // 适配屏幕触摸模式
  if (controller.userData.targetRayMode === 'screen') {
    const frame = renderer.xr.getFrame();
    const inputSource = controller.userData.inputSource;
    if (frame && inputSource) {
      const pose = frame.getPose(inputSource.targetRaySpace, renderer.xr.getReferenceSpace());
      if (pose) {
        raycaster.ray.origin.setFromMatrixPosition(pose.transform.matrix);
        raycaster.ray.direction.set(0, 0, -1).applyQuaternion(new THREE.Quaternion().fromArray(pose.transform.orientation));
      }
    }
  } else {
    // VR手柄的射线计算逻辑
    controller.updateMatrixWorld();
    tempMatrix.identity().extractRotation(controller.matrixWorld);
    raycaster.ray.origin.setFromMatrixPosition(controller.matrixWorld);
    raycaster.ray.direction.set(0, 0, -1).applyMatrix4(tempMatrix);
  }
  return raycaster.intersectObjects(group.children, true);
}

同时修正onSelectStart中targetRayMode的获取方式:

function onSelectStart(event) {
  const controller = event.target;
  controller.userData.targetRayMode = event.data.inputSource.targetRayMode;
  const intersections = getIntersections(controller);
  // ... 后续代码
}

额外优化:模型尺寸适配

GLTF模型可能尺寸过大或过小,导致射线检测难以命中,建议添加合适的缩放:

mesh.scale.set(0.1, 0.1, 0.1); // 根据模型实际尺寸调整
mesh.matrixAutoUpdate = false;
mesh.updateMatrix(); // 手动更新矩阵

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 20:45:53