ArCore Sceneform中计算3个锚点节点A→B→C夹角度数的方法
实现步骤
- 第一步:获取三个锚点节点的世界坐标
Sceneform 中所有 AnchorNode 都可以通过getWorldPosition()方法获取三维世界坐标,返回值为com.google.ar.sceneform.math.Vector3类型,分别获取三个节点的坐标即可:Vector3 posA = aNode.getWorldPosition(); Vector3 posB = bNode.getWorldPosition(); Vector3 posC = cNode.getWorldPosition(); - 第二步:生成以B为原点的两个方向向量
向量BA等于A的坐标减去B的坐标,向量BC等于C的坐标减去B的坐标:Vector3 vecBA = posA.subtract(posB); Vector3 vecBC = posC.subtract(posB); - 第三步:归一化处理两个向量
避免向量长度影响夹角计算结果,归一化后两个向量的长度都为1:vecBA.normalize(); vecBC.normalize(); - 第四步:计算夹角
先通过点积运算得到余弦值,再通过反余弦运算转弧度,最后转换为角度即可:// 计算点积 float dotProduct = Vector3.dot(vecBA, vecBC); // 钳制点积范围,避免浮点误差导致反余弦计算报错 dotProduct = Math.max(-1.0f, Math.min(1.0f, dotProduct)); // 转角度 float angleInDegrees = (float) Math.toDegrees(Math.acos(dotProduct));
完整可复用代码
import com.google.ar.sceneform.math.Vector3; import com.google.ar.sceneform.ux.ArFragment; import com.google.ar.sceneform.ux.AnchorNode; public float calculateBAngle(AnchorNode aNode, AnchorNode bNode, AnchorNode cNode) { // 校验锚点状态 if (aNode.getAnchor() == null || bNode.getAnchor() == null || cNode.getAnchor() == null || aNode.getAnchor().getTrackingState() != TrackingState.TRACKING || bNode.getAnchor().getTrackingState() != TrackingState.TRACKING || cNode.getAnchor().getTrackingState() != TrackingState.TRACKING) { return -1f; // 锚点未跟踪,返回无效值 } Vector3 posA = aNode.getWorldPosition(); Vector3 posB = bNode.getWorldPosition(); Vector3 posC = cNode.getWorldPosition(); Vector3 vecBA = posA.subtract(posB); Vector3 vecBC = posC.subtract(posB); vecBA.normalize(); vecBC.normalize(); float dot = Vector3.dot(vecBA, vecBC); dot = Math.max(-1f, Math.min(1f, dot)); return (float) Math.toDegrees(Math.acos(dot)); }
注意事项
- 该方法返回的是0°~180°之间的最小无向夹角,如果需要带方向的有向角,需要额外通过叉积计算符号位
- ArCore锚点存在定位漂移误差,建议连续取3~5次计算结果做均值平滑,提升数值稳定性
- 不要错用Android系统或其他图形库的
Vector3类,必须使用Sceneform内置的com.google.ar.sceneform.math.Vector3
内容的提问来源于stack exchange,提问作者Jaswant Singh
相关产品推荐
相关产品推荐

