【问题标题】:how to use persistent anchors with sceneform?如何使用具有场景形式的持久锚?
【发布时间】:2021-04-12 12:53:22
【问题描述】:

我在云端保存了一个持久锚(365 天)。现在,我想找回它。使用 Google 在其示例项目之一中提供的代码,我可以做到这一点。但是,我想使用 Sceneform,因为我想在之后进行一些操作(绘制 3D 形状),这在 Sceneform 中更容易做到。但是,我似乎无法解决持久的云锚。我在网上找到的所有示例都没有处理持久云锚,它们只处理正常的 24 小时云锚。

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

上面我写的更新函数有什么问题吗? CloudAnchorManager 类与 Google 在其 Persistent Cloud Anchor 示例中使用的类相同。这里,我也放上它的代码:

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

另外,这是我正在使用的另一个类(这也是来自 Google 示例项目):

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

当我运行我的应用程序时,我将手机的摄像头指向我之前放置对象的物理空间,但锚点从未被解析。我认为问题可能出在更新功能上,但我似乎无法弄清楚是什么。

【问题讨论】:

    标签: java android-studio augmented-reality arcore sceneform


    【解决方案1】:

    我想我没有正确地看这个物体​​。现在,它正在工作。这段代码是正确的。

    【讨论】:

      猜你喜欢
      • 2015-12-13
      • 2018-10-27
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多