简体   繁体   中英

how to use persistent anchors with sceneform?

I have saved a persistent anchor (for 365 days) on the cloud. Now, I want to retrieve it. I can do it just fine using the code Google provided in one of its sample projects. However, I want to use Sceneform since I want to do some manipulations afterwards (drawing 3D shapes), that are much easier to do in Sceneform. However, I can't seem to resolve the persistent cloud anchors. All the examples I find online, don't deal with persistent cloud anchors and they only deal with the normal 24 hour cloud anchors.

@RequiresApi(api = VERSION_CODES.N)
    protected void onUpdateFrame(FrameTime frameTime) {
        Frame frame = arFragment.getArSceneView().getArFrame();

        // If there is no frame, just return.
        if (frame == null) {
            return;
        }

        if (session == null) {
            Log.d(TAG, "setup a session once");
            session = arFragment.getArSceneView().getSession();
            cloudAnchorManager = new CloudAnchorManager(session);
        }
        if (resolveListener == null && session != null) {
            Log.d(TAG, "setup a resolveListener once");
            resolveListener = new MemexViewingActivity.ResolveListener();
            // Encourage the user to look at a previously mapped area.
            if (cloudAnchorId != null && !gotGoodAnchor && cloudAnchorManager != null) {
                Log.d(TAG, "put resolveListener on cloud manager once");
                userMessageText.setText(R.string.resolving_processing);
                cloudAnchorManager.resolveCloudAnchor(cloudAnchorId, resolveListener);
            }
        }
        if (cloudAnchorManager != null && session != null) {
            try {
                Frame dummy = session.update();
                cloudAnchorManager.onUpdate();
            } catch (CameraNotAvailableException e) {
                e.printStackTrace();
            }
        }
    }

Is there anything wrong in the above update function that I have written? The CloudAnchorManager class is the same one Google uses in its Persistent Cloud Anchor example. Here, I will put its code too:

package com.memex.eu.helpers;

import android.util.Log;

import com.google.ar.core.Anchor;
import com.google.ar.core.Anchor.CloudAnchorState;
import com.google.ar.core.Session;
import com.google.common.base.Preconditions;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * A helper class to handle all the Cloud Anchors logic, and add a callback-like mechanism on top of
 * the existing ARCore API.
 */
public class CloudAnchorManager {

  /** Listener for the results of a host operation. */
  public interface CloudAnchorListener {

    /** This method is invoked when the results of a Cloud Anchor operation are available. */
    void onComplete(Anchor anchor);
  }

  private final Session session;
  private final Map<Anchor, CloudAnchorListener> pendingAnchors = new HashMap<>();

  public CloudAnchorManager(Session session) {
    this.session = Preconditions.checkNotNull(session);
  }

  /** Hosts an anchor. The {@code listener} will be invoked when the results are available. */
  public synchronized void hostCloudAnchor(Anchor anchor, CloudAnchorListener listener) {
    Preconditions.checkNotNull(listener, "The listener cannot be null.");
    // This is configurable up to 365 days.
    Anchor newAnchor = session.hostCloudAnchorWithTtl(anchor, /* ttlDays= */ 365);
    pendingAnchors.put(newAnchor, listener);
  }

  /** Resolves an anchor. The {@code listener} will be invoked when the results are available. */
  public synchronized void resolveCloudAnchor(String anchorId, CloudAnchorListener listener) {
    Preconditions.checkNotNull(listener, "The listener cannot be null.");
    Anchor newAnchor = session.resolveCloudAnchor(anchorId);
    pendingAnchors.put(newAnchor, listener);
  }

  /** Should be called after a {@link Session#update()} call. */
  public synchronized void onUpdate() {
    Preconditions.checkNotNull(session, "The session cannot be null.");
    for (Iterator<Map.Entry<Anchor, CloudAnchorListener>> it = pendingAnchors.entrySet().iterator();
         it.hasNext(); ) {
      Map.Entry<Anchor, CloudAnchorListener> entry = it.next();
      Anchor anchor = entry.getKey();
      if (isReturnableState(anchor.getCloudAnchorState())) {
        CloudAnchorListener listener = entry.getValue();
        listener.onComplete(anchor);
        it.remove();
      }
    }
  }

  /** Clears any currently registered listeners, so they won't be called again. */
  synchronized void clearListeners() {
    pendingAnchors.clear();
  }

  private static boolean isReturnableState(CloudAnchorState cloudState) {
    switch (cloudState) {
      case NONE:
      case TASK_IN_PROGRESS:
        return false;
      default:
        return true;
    }
  }
}

Also, here is another class I am using (this is also from the Google example project):

/* Listens for a resolved anchor. */
    private final class ResolveListener implements CloudAnchorManager.CloudAnchorListener {

        @Override
        public void onComplete(Anchor resolvedAnchor) {
            runOnUiThread(
                    () -> {
                        Anchor.CloudAnchorState state = resolvedAnchor.getCloudAnchorState();
                        if (state.isError()) {
                            Log.e(TAG, "Error resolving a cloud anchor, state " + state);
                            userMessageText.setText(getString(R.string.resolving_error, state));
                            return;
                        }
                        Log.e(TAG, "cloud anchor successfully resolved, state " + state);
                        anchor = resolvedAnchor;
                        userMessageText.setText(getString(R.string.resolving_success));
                        gotGoodAnchor = true;
                    });
        }
    }

when I run my app, I point the phone's camera at the physical space where I previously put an object but the anchor is never resolved. I think the problem might be in the update function but I can't seem to figure out what.

I guess I wasn't looking at the object properly. Now, it's working. This code is correct.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM