How to place a object without tapping on the screen

时光总嘲笑我的痴心妄想 提交于 2019-12-03 09:39:04

问题


I am trying to show an object without tapping on the screen using ARCore. In the basic sample of ARCore Sceneform provided by Google, you need to tap on the screen after it detects the surface.

I want to implement that, AR shows the object without tapping on the screen.

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;
        }
    }

I tried this for displaying without tapping on the screen.

if Anyone know how to do this please help me. Thanks in Advance


回答1:


Although I suggest you place the object when a user taps & where s/he taps on the screen, what you're asking can be achieved like so. (this example is in Kotlin)

Before you begin placing an object, you need to create a ModelRenderable. Declare one @Nullable globally.

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 -> this@MainActivity.modelRenderable = modelRenderable }

The major chunk of the programming has to be done on the frame's onUpdate method. So you attach a listener for frame updates like so

 fragment.arSceneView.scene.addOnUpdateListener(this@MainActivity) //You can do this anywhere. I do it on activity creation post inflating the fragment

now you handle adding an object on the listener.

 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 = this@MainActivity.modelRenderable

                        //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())
                    }
                }
            }
        }
    }
}

I used one extension method

//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)
}

This is the end result




回答2:


If you don't want to use hit-testing or button's action methods for placing an object in a real environment, you can use, for instance, a camera's Pose for auto-placement (remember, you have to add an ARAnchor, its corresponding Node and a Renderable in front of the ARCamera i.e. along -Z direction):

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());
}

Hope this helps.



来源:https://stackoverflow.com/questions/51673733/how-to-place-a-object-without-tapping-on-the-screen

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!