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

Android Studio(Java)中ARCore如何实现3D对象点击事件处理

ARCore Android(Java)3D对象/增强图像点击事件实现

AR场景下无法响应3D对象、增强图像点击的核心原因是:3D内容是渲染在GL Surface上的,不存在原生Android View的点击事件体系,直接给渲染对象、Fragment设置普通点击监听不会生效,必须通过射线碰撞检测+渲染对象映射的方式实现。

核心实现流程

  • 拦截AR场景视图的触摸事件,获取触摸点的屏幕坐标
  • 调用ARCore的hitTest()接口做从屏幕点到AR空间的射线碰撞检测,过滤跟踪状态无效的命中结果
  • 维护锚点/增强图像和对应渲染3D对象的映射表,命中后匹配到对应对象,触发业务层点击逻辑

可直接复用的Java代码

1. 全局变量初始化

// 锚点和3D渲染对象的映射表,用于手动放置的永久锚点场景
private final HashMap<Anchor, Object> anchorModelMap = new HashMap<>();
// 增强图像和3D渲染对象的映射表,用于AugmentedImage场景
private final HashMap<Integer, Object> augImageModelMap = new HashMap<>();
private ArFragment arFragment;

2. 触摸事件监听注册

在onCreate中完成ArFragment初始化后注册触摸监听,不要在视图未加载完成时注册:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_ar);
    arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ar_fragment);

    arFragment.getArSceneView().setOnTouchListener((view, motionEvent) -> {
        // 仅响应手指抬起事件,避免滑动误触发
        if (motionEvent.getAction() != MotionEvent.ACTION_UP) return false;
        Frame currentFrame = arFragment.getArSceneView().getArFrame();
        if (currentFrame == null) return false;

        // 执行碰撞检测
        List<HitResult> hitResultList = currentFrame.hitTest(motionEvent.getX(), motionEvent.getY());
        for (HitResult hit : hitResultList) {
            Trackable hitTrackable = hit.getTrackable();
            // 匹配手动放置的永久锚点对象
            if (hitTrackable instanceof Anchor) {
                Anchor hitAnchor = (Anchor) hitTrackable;
                if (hitAnchor.getTrackingState() != TrackingState.TRACKING) continue;
                Object targetModel = anchorModelMap.get(hitAnchor);
                if (targetModel != null) {
                    // 这里写3D对象点击后的业务逻辑,比如弹信息框、播放动画
                    onModelClick(targetModel);
                    return true;
                }
            }
            // 匹配增强图像对象
            if (hitTrackable instanceof AugmentedImage) {
                AugmentedImage hitImage = (AugmentedImage) hitTrackable;
                if (hitImage.getTrackingState() != TrackingState.TRACKING) continue;
                Object targetModel = augImageModelMap.get(hitImage.getIndex());
                if (targetModel != null) {
                    // 这里写增强图像点击后的业务逻辑
                    onAugImageClick(hitImage, targetModel);
                    return true;
                }
            }
        }
        // 未命中任何可交互对象,事件向下传递
        return false;
    });
}

3. 放置锚点时绑定映射关系

放置永久锚点、加载3D模型时,必须把锚点和对应的模型对象存入映射表,否则碰撞检测后无法匹配到对应业务对象:

// 平面点击放置模型的示例逻辑
private void placePermanentAnchor(HitResult hitResult, ModelRenderable model) {
    Anchor newAnchor = hitResult.createAnchor();
    AnchorNode anchorNode = new AnchorNode(newAnchor);
    anchorNode.setRenderable(model);
    arFragment.getArSceneView().getScene().addChild(anchorNode);
    // 关键:存入映射表,value可以替换成你自己封装的业务模型类
    anchorModelMap.put(newAnchor, model);
}

4. 增强图像检测时绑定映射关系

在增强图像更新回调中,检测到可跟踪的图像并挂载3D内容时,同样要存入映射表:

@Override
public void onUpdate(FrameTime frameTime) {
    Frame frame = arFragment.getArSceneView().getArFrame();
    if (frame == null) return;
    Collection<AugmentedImage> updatedImages = frame.getUpdatedTrackables(AugmentedImage.class);
    for (AugmentedImage image : updatedImages) {
        if (image.getTrackingState() == TrackingState.TRACKING 
            && !augImageModelMap.containsKey(image.getIndex())) {
            // 挂载3D模型的常规逻辑
            Anchor imgAnchor = image.createAnchor(image.getCenterPose());
            AnchorNode imgNode = new AnchorNode(imgAnchor);
            imgNode.setRenderable(augImageModel);
            arFragment.getArSceneView().getScene().addChild(imgNode);
            // 关键:存入映射表
            augImageModelMap.put(image.getIndex(), augImageModel);
        }
    }
}

常见避坑点

  • 不要直接依赖Sceneform节点自带的setOnClickListener,低版本SDK存在事件穿透、跟踪丢失后仍响应点击的bug,手动实现hitTest匹配稳定性更高
  • 所有命中判断必须加TrackingState.TRACKING校验,否则跟踪丢失的锚点、未识别成功的图像也会被判定为命中,出现点空白区域触发点击的异常
  • 锚点移除、增强图像跟踪丢失超过3秒后,要及时从映射表中移除对应条目,避免内存泄漏
  • 触摸事件不要拦截ACTION_DOWN和ACTION_MOVE,否则会导致场景旋转、平移手势失效

内容的提问来源于stack exchange,提问作者Paterne K.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:24:16