ARCoreを使用して画面をタップせずにオブジェクトを表示しようとしています。 Googleが提供するARCore Sceneformの基本的なサンプルでは、表面を検出した後で画面をタップする必要があります。
それを実装したいのですが、ARは画面をタップせずにオブジェクトを表示します。
Anchor newAnchor;
for (Plane plane : mSession.getAllTrackables(Plane.class)) {
if (plane.getType() == Plane.Type.HORIZONTAL_UPWARD_FACING
&& plane.getTrackingState() == TrackingState.TRACKING)
{
newAnchor = plane.createAnchor(plane.getCenterPose());
break;
}
}
画面をタップせずに表示してみました。
誰かがこれを行う方法を知っている場合は、私を助けてください。前もって感謝します
ユーザーが画面をタップした場所とタップした場所にオブジェクトを配置することをお勧めしますが、求めていることはこのようにして実現できます。 (この例はKotlinにあります)
オブジェクトを配置する前に、ModelRenderable
を作成する必要があります。 1つを宣言@Nullable
グローバル。
private var modelRenderable: ModelRenderable? = null
//Create the football renderable
ModelRenderable.builder()
//get the context of the ARFragment and pass the name of your .sfb file
.setSource(fragment.context, Uri.parse("FootBall.sfb"))
.build()
//I accepted the CompletableFuture using Async since I created my model on creation of the activity. You could simply use .thenAccept too.
//Use the returned modelRenderable and save it to a global variable of the same name
.thenAcceptAsync { modelRenderable -> [email protected] = modelRenderable }
プログラミングの主要な部分は、フレームのonUpdate
メソッドで行う必要があります。だからあなたはそのようなフレーム更新のためのリスナーをアタッチします
fragment.arSceneView.scene.addOnUpdateListener(this@MainActivity) //You can do this anywhere. I do it on activity creation post inflating the fragment
次に、リスナーへのオブジェクトの追加を処理します。
override fun onUpdate(frameTime: FrameTime?) {
//get the frame from the scene for shorthand
val frame = fragment.arSceneView.arFrame
if (frame != null) {
//get the trackables to ensure planes are detected
val var3 = frame.getUpdatedTrackables(Plane::class.Java).iterator()
while(var3.hasNext()) {
val plane = var3.next() as Plane
//If a plane has been detected & is being tracked by ARCore
if (plane.trackingState == TrackingState.TRACKING) {
//Hide the plane discovery helper animation
fragment.planeDiscoveryController.hide()
//Get all added anchors to the frame
val iterableAnchor = frame.updatedAnchors.iterator()
//place the first object only if no previous anchors were added
if(!iterableAnchor.hasNext()) {
//Perform a hit test at the center of the screen to place an object without tapping
val hitTest = frame.hitTest(frame.screenCenter().x, frame.screenCenter().y)
//iterate through all hits
val hitTestIterator = hitTest.iterator()
while(hitTestIterator.hasNext()) {
val hitResult = hitTestIterator.next()
//Create an anchor at the plane hit
val modelAnchor = plane.createAnchor(hitResult.hitPose)
//Attach a node to this anchor with the scene as the parent
val anchorNode = AnchorNode(modelAnchor)
anchorNode.setParent(fragment.arSceneView.scene)
//create a new TranformableNode that will carry our object
val transformableNode = TransformableNode(fragment.transformationSystem)
transformableNode.setParent(anchorNode)
transformableNode.renderable = [email protected]
//Alter the real world position to ensure object renders on the table top. Not somewhere inside.
transformableNode.worldPosition = Vector3(modelAnchor.pose.tx(),
modelAnchor.pose.compose(Pose.makeTranslation(0f, 0.05f, 0f)).ty(),
modelAnchor.pose.tz())
}
}
}
}
}
}
1つの拡張メソッドを使用しました
//A method to find the screen center. This is used while placing objects in the scene
private fun Frame.screenCenter(): Vector3 {
val vw = findViewById<View>(Android.R.id.content)
return Vector3(vw.width / 2f, vw.height / 2f, 0f)
}
実際の環境にオブジェクトを配置するためにhit-testing
またはbutton's action
メソッドを使用したくない場合は、たとえば、カメラのポーズを自動配置に使用できます(追加する必要があります) ARAnchor
、それに対応するNode
、およびARCameraの前にあるRenderable
、つまり-Z
方向に沿って):
if (this.anchorNode == null) {
Session session = arFragment.getArSceneView().getSession();
float[] position = { 0, 0, -0.75 }; // 75 cm away from camera
float[] rotation = { 0, 0, 0, 1 };
Anchor anchor = session.createAnchor(new Pose(position, rotation));
anchorNode = new AnchorNode(anchor);
anchorNode.setRenderable(yourModelRenderable);
anchorNode.setParent(arFragment.getArSceneView().getScene());
}
お役に立てれば。
オブジェクトを1つだけ配置する場合のコードスニペットを次に示します。ありがとう@clinkz
override fun onUpdate(frameTime: FrameTime?) {
arFragment?.let { fragment ->
fragment.arSceneView?.let { sceneView ->
sceneView.arFrame?.let { frame ->
if (!placed) {
val trackable = frame.getUpdatedTrackables(Plane::class.Java).iterator()
if (trackable.hasNext()) {
val plane = trackable.next() as Plane
if (plane.trackingState == TrackingState.TRACKING) {
fragment.planeDiscoveryController?.hide()
val hitTest =
frame.hitTest(frame.screenCenter().x, frame.screenCenter().y)
val hitTestIterator = hitTest.iterator()
if (hitTestIterator.hasNext()) {
val hitResult = hitTestIterator.next()
val modelAnchor = plane.createAnchor(hitResult.hitPose)
val anchorNode = AnchorNode(modelAnchor)
anchorNode.setParent(sceneView.scene)
val transformableNode =
TransformableNode(fragment.transformationSystem)
transformableNode.setParent(anchorNode)
transformableNode.renderable = [email protected]
transformableNode.worldPosition = Vector3(
modelAnchor.pose.tx(),
modelAnchor.pose.compose(
Pose.makeTranslation(
0f,
0.05f,
0f
)
).ty(),
modelAnchor.pose.tz()
)
placed = true
}
}
}
}
}
}
}
}
private fun Frame.screenCenter(): Vector3 {
val vw = findViewById<View>(Android.R.id.content)
return Vector3(vw.width / 2f, vw.height / 2f, 0f)
}