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
相关产品推荐
相关产品推荐

