Sceneform-android-sdk: How to place 3D object at world center

Created on 14 May 2018  路  11Comments  路  Source: google-ar/sceneform-android-sdk

How to place object at center of world(0.0f,0.0f,0.0f) position without hitresult? I have tried following code but not works.

@Override
    public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onPostCreate(savedInstanceState, persistentState);

        // Create the Anchor.
        Anchor anchor = null;
        try {
            Frame arFrame = arFragment.getArSceneView().getArFrame();
            //Pose pose = arFrame.getCamera().getPose().compose(Pose.makeTranslation(0, 0, -0.5f)).extractTranslation();
            Pose pose = arFrame.getCamera().getDisplayOrientedPose().compose(Pose.makeTranslation(0, 0.2f, 0f)).extractTranslation();

            anchor = new Session(this).createAnchor(pose);
            //anchor = new Session(this).createAnchor(Pose.makeTranslation(0.0f,0.0f,-0.5f));
        } catch (UnavailableArcoreNotInstalledException e) {
            e.printStackTrace();
        } catch (UnavailableApkTooOldException e) {
            e.printStackTrace();
        } catch (UnavailableSdkTooOldException e) {
            e.printStackTrace();
        }
        AnchorNode anchorNode = new AnchorNode(anchor);
        anchorNode.setParent(arFragment.getArSceneView().getScene());
        //anchorNode.setWorldPosition(new Vector3(0,0,-1f));

        // Create the transformable andy and add it to the anchor.
        TransformableNode andy = new TransformableNode(arFragment.getTransformationSystem());
        andy.setParent(anchorNode);
        andy.setRenderable(andyRenderable);
        andy.select();
    }

Most helpful comment

The following code shows how you can place a Node that is anchored half a meter in front of the camera without depending on a hit result. Using an ARCore Anchor is important to ensure that tracking recovers if you lose tracking due to covering the camera with your hand.

// Find a position half a meter in front of the user.
Vector3 cameraPos = sceneView.getScene().getCamera().getWorldPosition();
Vector3 cameraForward = sceneView.getScene().getCamera().getForward();
Vector3 position = Vector3.add(cameraPos, cameraForward.scaled(0.5f));

// Create an ARCore Anchor at the position.
Pose pose = Pose.makeTranslation(position.x, position.y, position.z);
Anchor anchor sceneView.getSession().createAnchor(pose);

// Create the Sceneform AnchorNode
AnchorNode anchorNode = new AnchorNode(anchor);
anchorNode.setParent(sceneView.getScene());

// Create the node relative to the AnchorNode
Node node = new Node();
node.setParent(anchorNode);

Can you clarify what the 'center of the world' means for your use case? The position (0, 0, 0) is going to be the position of the camera at the time that the ARCore session is started.

Thanks,

Dan

All 11 comments

Are you getting any errors in the log?

I added similar code to place a "floating" andy in front of the camera as once tracking has started.
To the HelloSceneform sample, I added a member variable:

       private AnchorNode anchorNode;

At the end of onCreate() I added the listener for the scene update.

       arFragment.getArSceneView().getScene().setOnUpdateListener(this::onSceneUpdate);

Then implemented onSceneUpdate()

    private void onSceneUpdate(FrameTime frameTime) {
       // Let the fragment update its state first.
        arFragment.onUpdate(frameTime);

       // If there is no frame then don't process anything.
        if (arFragment.getArSceneView().getArFrame() == null) {
            return;
        }

        // If ARCore is not tracking yet, then don't process anything.
        if (arFragment.getArSceneView().getArFrame().getCamera().getTrackingState() != TrackingState.TRACKING) {
            return;
        }

        // Place the anchor 1m in front of the camera if anchorNode is null.
       if (this.anchorNode == null) {
          Session session = arFragment.getArSceneView().getSession();
          float[] pos = { 0,0,-1 };
          float[] rotation = {0,0,0,1};
          Anchor anchor =  session.createAnchor(new Pose(pos, rotation));
          anchorNode = new AnchorNode(anchor);
          anchorNode.setRenderable(andyRenderable);
          anchorNode.setParent(arFragment.getArSceneView().getScene());
       }
    }

You might also want to look at arFragment.getArSceneView().getScene().getCamera().getForward()
and then position using that as a ray so the object is in front of the user based on where they are looking. Placing objects at the same height as the camera is sometimes confusing since the user is typically looking down a little so the object at camera height is out of sight.

@claywilkinson your code works good.But the object not stay in same place.It is moving around the room sometimes.Similar repeating patterns may be the problem.Is it any other workaround to make Object stable in same place? Any idea how other apps making this possible?

For it to stay in one place, you really want to create the anchor based on a Trackable object. For example a plane or Oriented Point. This was as you move, ARCore will update the position of the trackable so it appears to stay in the same place in the real world.

The steps would be

  1. Have the user tap a plane (or pick a point on the plane to perform a hittest). I would not recommend using the center of the plane since it can move as the plane dimensions shift.
  2. Create an AnchorNode from an anchor created from hittestResult.
  3. Attach another node and set its world position to 0,0,0 or whereever you want it then set the parent to the anchor node.

This will cause the node to be positioned in the same place relative to anchor.

Yes.but I need to place object without user click or hittest result.So the object should be placed at 0,0,0 whatever scene Contains. Sometimes it is not stay in same place. For example,in iOS ARKit object stick on same place,even we rotate mobile randomly or close camera by hand.I am trying to achieve like this. Also I am not willing to show some searching icons to detect surfaces.

The following code shows how you can place a Node that is anchored half a meter in front of the camera without depending on a hit result. Using an ARCore Anchor is important to ensure that tracking recovers if you lose tracking due to covering the camera with your hand.

// Find a position half a meter in front of the user.
Vector3 cameraPos = sceneView.getScene().getCamera().getWorldPosition();
Vector3 cameraForward = sceneView.getScene().getCamera().getForward();
Vector3 position = Vector3.add(cameraPos, cameraForward.scaled(0.5f));

// Create an ARCore Anchor at the position.
Pose pose = Pose.makeTranslation(position.x, position.y, position.z);
Anchor anchor sceneView.getSession().createAnchor(pose);

// Create the Sceneform AnchorNode
AnchorNode anchorNode = new AnchorNode(anchor);
anchorNode.setParent(sceneView.getScene());

// Create the node relative to the AnchorNode
Node node = new Node();
node.setParent(anchorNode);

Can you clarify what the 'center of the world' means for your use case? The position (0, 0, 0) is going to be the position of the camera at the time that the ARCore session is started.

Thanks,

Dan

@dsternfeld7 your are right. I mean "center of the world" is the position infront of the camera and this position should not change when the icon disappears. I have used following code,please ensure it is properly anchored. Is it any possibility,the object moves.Because it stays good,but sometimes like similar repeating patterns in background make the object move.

@Override
public void onUpdate(FrameTime frameTime) {
if(arSceneView.getArFrame() == null){
Log.d(TAG, "onUpdate: No frame available");
// No frame available
return;
}

    if(arSceneView.getArFrame().getCamera().getTrackingState() != TrackingState.TRACKING){
        Log.d(TAG, "onUpdate: Tracking not started yet");
        // Tracking not started yet
        return;
    }

        if (this.mAnchorNode == null && andyRenderable != null) {
            Log.d(TAG, "onUpdate: mAnchorNode is null");
            Session session = arSceneView.getSession();

            /*float[] position = {0, 0, -1};
            float[] rotation = {0, 0, 0, 1};
            Anchor anchor = session.createAnchor(new Pose(position, rotation));*/

            Vector3 cameraPos = arSceneView.getScene().getCamera().getWorldPosition();
            Vector3 cameraForward = arSceneView.getScene().getCamera().getForward();
            Vector3 position = Vector3.add(cameraPos, cameraForward.scaled(1.0f));

            // Create an ARCore Anchor at the position.
            Pose pose = Pose.makeTranslation(position.x, position.y, position.z);
            Anchor anchor = arSceneView.getSession().createAnchor(pose);

            mAnchorNode = new AnchorNode(anchor);
            mAnchorNode.setParent(arSceneView.getScene());


            Node node = new Node();
            node.setRenderable(andyRenderable);
            node.setParent(mAnchorNode);
            node.setOnTapListener(new Node.OnTapListener() {
                @Override
                public void onTap(HitTestResult hitTestResult, MotionEvent motionEvent) {
                    showBottomSheet();
                }
            });
        }
}

Your code looks correct to me. If you are still seeing significant tracking instability, then I suggest posting an issue here and including information about the environment you are testing in.

how can i rotate the node on x or y axis in sceneview

can anybody tell me if i can place an anchor at any given coordinate in android ndk?

can anybody tell me how to place 3D image in Ar without touching screen?

How can I place 3D object in ArSceneView onPeekTouch?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

khonakr picture khonakr  路  3Comments

yashvv picture yashvv  路  3Comments

StevenOttoG picture StevenOttoG  路  4Comments

LukasStancikas picture LukasStancikas  路  3Comments

JessHolle picture JessHolle  路  3Comments