Android 使用Arcore 實現多點測距
主要使用了Anchor(錨點),Pose (姿勢/姿態),Node(節點),Vector3(三維向量)
github源碼 點這裏 <==
1.準備
- 一臺支持Arcore的手機
- 依賴arcore和sceneform
implementation 'com.google.ar:core:1.4.0'
implementation 'com.google.ar.sceneform:core:1.4.0'
implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.4.0'
-佈局文件使用sceneform提供的fragment
<fragment
android:id="@+id/UI_ArSceneView"
android:name="com.gj.arcoredraw.MyArFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
import com.blankj.utilcode.util.ToastUtils;
import com.google.ar.core.exceptions.UnavailableApkTooOldException;
import com.google.ar.core.exceptions.UnavailableArcoreNotInstalledException;
import com.google.ar.core.exceptions.UnavailableDeviceNotCompatibleException;
import com.google.ar.core.exceptions.UnavailableException;
import com.google.ar.core.exceptions.UnavailableSdkTooOldException;
import com.google.ar.sceneform.ux.ArFragment;
//可以直接使用ArFragment 我這裏爲了中文提示
public class MyArFragment extends ArFragment {
@Override
protected void handleSessionException(UnavailableException sessionException) {
String message;
if (sessionException instanceof UnavailableArcoreNotInstalledException) {
message = "請安裝ARCore";
} else if (sessionException instanceof UnavailableApkTooOldException) {
message = "請升級ARCore";
} else if (sessionException instanceof UnavailableSdkTooOldException) {
message = "請升級app";
} else if (sessionException instanceof UnavailableDeviceNotCompatibleException) {
message = "當前設備部不支持AR";
} else {
message = "未能創建AR會話,請查看機型適配,arcore版本與系統版本";
String var3 = String.valueOf(sessionException);
}
ToastUtils.showLong(message);
}
}
2.監聽點擊 生成錨點
- 設置ArFragment的Tap監聽
(UI_ArSceneView as MyArFragment).setOnTapArPlaneListener { hitResult, plane, motionEvent ->
val currentAnchor=hitResult.createAnchor()
}
3.計算兩個錨點之間的距離
val startPose = endAnchor.pose
val endPose = startAnchor.pose
val dx = startPose.tx() - endPose.tx()
val dy = startPose.ty() - endPose.ty()
val dz = startPose.tz() - endPose.tz()
val length = Math.sqrt((dx * dx + dy * dy + dz * dz).toDouble())
anchorInfoBean.dataText = "距離爲${decimalFormat.format(length)}m"
4.UI 劃線 (兩個錨點在ui上連接劃線)
private fun drawLine(firstAnchor: Anchor, secondAnchor: Anchor) {
val firstAnchorNode = AnchorNode(firstAnchor)
val secondAnchorNode = AnchorNode(secondAnchor)
firstAnchorNode.setParent((UI_ArSceneView as MyArFragment).arSceneView.scene)
val firstWorldPosition = firstAnchorNode.worldPosition
val secondWorldPosition = secondAnchorNode.worldPosition
val difference = Vector3.subtract(firstWorldPosition, secondWorldPosition)
val directionFromTopToBottom = difference.normalized()
val rotationFromAToB = Quaternion.lookRotation(directionFromTopToBottom, Vector3.up())
MaterialFactory.makeOpaqueWithColor(this@MainActivity, com.google.ar.sceneform.rendering.Color(0f, 191f, 255f))
.thenAccept { material ->
val lineMode = ShapeFactory.makeCube(Vector3(0.01f, 0.01f, difference.length()), Vector3.zero(), material)
val lineNode = Node()
lineNode.setParent(firstAnchorNode)
lineNode.renderable = lineMode
lineNode.worldPosition = Vector3.add(firstWorldPosition, secondWorldPosition).scaled(0.5f)
lineNode.worldRotation = rotationFromAToB
}
}
UI這裏有點複雜,主要難點在Vector3(空間向量)這裏.用的是數學知識了.
1.先用兩個Anchor 獲得 世界座標(worldPosition)
2.使用向量計算兩點空間差
3.使用起始Anchor ,生成一個Node.附加到arSceneView上
4.使用MaterialFactory 創建一個Material.再創建一個 Node使用剛纔的材質,附加到之前的Node上.
github源碼 點這裏 <==