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

OpenGL ES 2.0中单个3D物体旋转后更新视图的ARCore实现问题

嘿,针对你在ARCore应用里想要实现「仅最后放置的物体可被选中操作,切换选中其他物体后原最后物体就无法再操作」的需求,我给你梳理一套清晰的实现方案,直接就能套进你的代码里:

1. 添加状态跟踪变量

首先在你的AR场景管理类(比如ArFragment的子类或者自定义的SceneView管理类)里,添加几个全局变量来跟踪物体状态:

// 存储所有已放置的自定义物体
private List<CustomObject> mPlacedObjects = new ArrayList<>();
// 当前选中的物体
private CustomObject mCurrentSelectedObject;
// 最后放置的物体
private CustomObject mLastPlacedObject;
// 标记最后放置的物体是否还能被操作(切换选其他物体后会设为false)
private boolean mLastObjectIsOperable = true;

同时,记得给你的CustomObject类补充几个必要属性和getter/setter:

public class CustomObject {
    private boolean isSelected;
    private Anchor anchor; // 物体绑定的ARCore锚点
    private Pose pose; // 物体的位姿(位置+旋转)
    private float scale = 1.0f; // 缩放比例

    // 原有draw()方法
    public void draw(Frame frame, Session session) {
        // 你的原有绘制逻辑...
    }

    // 生成getter和setter
    public boolean isSelected() { return isSelected; }
    public void setSelected(boolean selected) { isSelected = selected; }
    public Anchor getAnchor() { return anchor; }
    public void setAnchor(Anchor anchor) { this.anchor = anchor; }
    public Pose getPose() { return pose; }
    public void setPose(Pose pose) { this.pose = pose; }
    public float getScale() { return scale; }
    public void setScale(float scale) { this.scale = scale; }
}

2. 放置新物体时更新状态

每次你放置一个新的CustomObject时,更新状态变量,确保新物体是当前唯一可操作的候选:

// 假设你通过HitTest创建了新物体并绑定了锚点
CustomObject newObject = new CustomObject();
newObject.setAnchor(hitResult.createAnchor());
newObject.setPose(hitResult.getHitPose());

// 更新全局状态
mPlacedObjects.add(newObject);
mLastPlacedObject = newObject;
mLastObjectIsOperable = true; // 新放置的物体默认可操作

// 取消之前选中的物体(如果有的话)
if (mCurrentSelectedObject != null) {
    mCurrentSelectedObject.setSelected(false);
}
mCurrentSelectedObject = null;

3. 处理点击选中逻辑

在触摸事件中通过ARCore的HitTest检测点击的物体,并根据规则控制选中权限:

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_UP) {
        Frame frame = getArSceneView().getFrame();
        if (frame != null) {
            List<HitResult> hitResults = frame.hitTest(event);
            for (HitResult hitResult : hitResults) {
                // 通过锚点找到对应的CustomObject
                CustomObject clickedObject = findObjectByAnchor(hitResult.getAnchor());
                if (clickedObject != null) {
                    // 先取消之前选中的物体状态
                    if (mCurrentSelectedObject != null) {
                        mCurrentSelectedObject.setSelected(false);
                    }

                    // 核心规则判断
                    if (clickedObject == mLastPlacedObject && mLastObjectIsOperable) {
                        // 点击的是可操作的最后放置物体,允许选中
                        mCurrentSelectedObject = clickedObject;
                        mCurrentSelectedObject.setSelected(true);
                    } else {
                        // 点击了其他物体,标记最后放置的物体为不可操作
                        mLastObjectIsOperable = false;
                        mCurrentSelectedObject = null; // 不选中任何物体
                    }
                    return true;
                }
            }
        }
    }
    return super.onTouchEvent(event);
}

// 辅助方法:通过锚点匹配对应的CustomObject
private CustomObject findObjectByAnchor(Anchor anchor) {
    for (CustomObject obj : mPlacedObjects) {
        if (obj.getAnchor().equals(anchor)) {
            return obj;
        }
    }
    return null;
}

4. 修改draw()方法控制交互

在每个物体的draw()方法里,只有当它是当前选中的最后放置物体且仍可操作时,才执行旋转/位置调整逻辑:

public void draw(Frame frame, Session session) {
    // 先执行原有绘制逻辑(渲染物体到AR场景)
    // ...你的原有draw代码(比如更新模型矩阵、绘制网格等)...

    // 仅对符合条件的物体执行交互逻辑
    if (this.isSelected() && this == mLastPlacedObject && mLastObjectIsOperable) {
        // 这里放你的旋转、位置调整代码
        // 比如根据手势更新的pose/scale来调整物体状态
        updateObjectPose();
    }
}

5. 手势交互的权限控制

如果你用了ARCore的手势检测器(比如缩放、旋转、拖拽),记得在手势回调里加上权限判断,确保只有符合条件的物体能被操作:

// 示例:旋转手势的权限控制
private RotateGestureDetector mRotateDetector = new RotateGestureDetector(this, 
    new RotateGestureDetector.SimpleOnRotateGestureListener() {
        @Override
        public boolean onRotate(RotateGestureDetector detector) {
            // 只有当前选中的是可操作的最后放置物体,才处理旋转
            if (mCurrentSelectedObject != null 
                && mCurrentSelectedObject == mLastPlacedObject 
                && mLastObjectIsOperable) {
                float rotationDelta = detector.getRotationDelta();
                // 更新物体的旋转姿态
                Quaternion currentRot = mCurrentSelectedObject.getPose().getRotation();
                Quaternion newRot = Quaternion.multiply(
                    Quaternion.axisAngle(new Vector3(0, 1, 0), rotationDelta),
                    currentRot);
                mCurrentSelectedObject.setPose(Pose.makeRotation(newRot.x, newRot.y, newRot.z, newRot.w));
                return true;
            }
            return false;
        }
    });

核心逻辑总结

这套方案的核心是通过mLastPlacedObject和mLastObjectIsOperable两个变量控制权限:

  • 新放置的物体自动获得可操作权限
  • 只有点击这个最后放置的物体时,才能选中并操作它
  • 一旦点击了其他物体,立即剥夺最后放置物体的可操作权限,之后即使再点击它也无法操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:51:32