Android增强现实– Android ARCore示例

时间:2020-02-23 14:28:46  来源:igfitidea点击:

在本教程中,我们将讨论增强现实,并使用Sceneform在我们的android应用程序中实现一个hello world示例。

增强现实

增强现实正在日益普及。
它用于通过手机的摄像头向您展示真实世界中的虚拟3D模型/图形。
在演示现实世界中模拟的东西(例如您想在墙上看到的油漆/装饰)时非常有用。

增强现实位于虚拟现实和现实环境之间。

Android ARCore

Google提供了ARCore库来增强AR开发。

ARCore通过摄像头在现实世界中进行运动跟踪,以在平面/表面上创建路径,我们可以在上面放置3D模型和图形。

SceneForm是最近出现的3D框架,是OpenGL的更好替代方案。
OpenGL看起来令人胆怯。

SceneForm使我们能够快速渲染3d对象,而无需学习图形或者OpenGL。

我们可以在Android Studio中下载Google Sceneform Tools插件,以查看和渲染3D模型。

您可以访问https://poly.google.com/并下载示例模型。
不要忘记相信创作者!

通常,OBJ和GLTX格式用于渲染增强图像。

现在,我们构建第一个AR应用程序,在该应用程序中,我们将上述3D模型用作AR图像。

增强现实Android示例项目结构

在上述项目中,我们创建了一个" sampledata"目录,其中添加了先前下载的obj和mtl文件。

在项目的build.gradle中添加以下依赖项:

classpath 'com.google.ar.sceneform:plugin:1.0.1'

在您应用的build.gradle中添加以下内容:

implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.0.0'

您还需要在应用的Gradle文件中设置ar插件。
在依赖项下面添加以下内容:

apply plugin: 'com.google.ar.sceneform.plugin'

我们使用了以下图像,您可以从此链接下载它并将其放在sampledata目录中:

现在,右键单击obj文件,然后选择导入sceneform资产:

这将自动创建Renderable AR场景资产。
它将自动在应用程序的build.gradle末尾添加以下行:

sceneform.asset('sampledata/Coffee Cup_final.obj',
      'default',
      'sampledata/Coffee Cup_final.sfa',
      'src/main/assets/Coffee Cup_final')

该应用程序的build.gradle最终看起来像这样:

Android ARCore Sceneform需要Java 8或者更高版本。

sja和sjb是"场景资产描述"和"场景二进制文件"文件。

sjb文件在3D查看器中可见。
它与APK一起提供。

sja文件用于设置sjb文件的属性。

您可以在sja文件中更改模型的"比例"。

Android增强现实示例代码

要在您的应用程序中配置ARCore,请在AndroidManifest.xml文件中添加以下权限和元数据。

<uses-permission android:name="android.permission.CAMERA" 
  <uses-feature
      android:name="android.hardware.camera.ar"
      android:required="true" 

元数据位于应用程序标记内。

<meta-data
          android:name="com.google.ar.core"
          android:value="required" 

下面给出了activity_main.xml类的代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".MainActivity">

  <android.support.design.widget.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/AppTheme.AppBarOverlay">

      <android.support.v7.widget.Toolbar
          android:id="@+id/toolbar"
          android:layout_width="match_parent"
          android:layout_height="?android:attr/actionBarSize"
          android:background="?android:attr/colorPrimary"
          app:popupTheme="@style/AppTheme.PopupOverlay" 

  </android.support.design.widget.AppBarLayout>

  <include layout="@layout/content_main" 

  <android.support.design.widget.FloatingActionButton
      android:id="@+id/fab"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="bottom|end"
      android:layout_margin="@dimen/fab_margin"
      app:srcCompat="@android:drawable/ic_input_add" 

</android.support.design.widget.CoordinatorLayout>

下面给出了content_main.xml的代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:layout_behavior="@string/appbar_scrolling_view_behavior"
  tools:context=".MainActivity"
  tools:showIn="@layout/activity_main">

  <fragment
      android:id="@+id/sceneForm"
      android:name="com.google.ar.sceneform.ux.ArFragment"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" 

</android.support.constraint.ConstraintLayout>

我们将片段设置为ArFragment。
" ArFragment"会检查手机是否与ARCore兼容。

此外,它还会检查是否授予了相机许可。
如果不是,它将自动要求它。

另外,它还会要求您通过Google Application下载ARCore。

该设备列表当前支持ARCore。

MainActivity.java类的代码如下:

package com.theitroad.androidarsceneform;

import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

import com.google.ar.core.Anchor;
import com.google.ar.core.Frame;
import com.google.ar.core.HitResult;
import com.google.ar.core.Plane;
import com.google.ar.core.Trackable;
import com.google.ar.sceneform.AnchorNode;
import com.google.ar.sceneform.rendering.ModelRenderable;
import com.google.ar.sceneform.ux.ArFragment;
import com.google.ar.sceneform.ux.TransformableNode;

import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

public class MainActivity extends AppCompatActivity {

  ArFragment arFragment;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
      setSupportActionBar(toolbar);

      FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
      fab.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {
              addObject(Uri.parse("Coffee Cup_Final.sfb"));
          }
      });

      arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.sceneForm);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
      //Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.menu_main, menu);
      return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
      //Handle action bar item clicks here. The action bar will
      //automatically handle clicks on the Home/Up button, so long
      //as you specify a parent activity in AndroidManifest.xml.
      int id = item.getItemId();

      //noinspection SimplifiableIfStatement
      if (id == R.id.action_settings) {
          return true;
      }

      return super.onOptionsItemSelected(item);
  }

  private void addObject(Uri parse) {
      Frame frame = arFragment.getArSceneView().getArFrame();
      Point point = getScreenCenter();
      if (frame != null) {
          List<HitResult> hits = frame.hitTest((float) point.x, (float) point.y);

          for (int i = 0; i < hits.size(); i++) {
              Trackable trackable = hits.get(i).getTrackable();
              if (trackable instanceof Plane && ((Plane) trackable).isPoseInPolygon(hits.get(i).getHitPose())) {
                  placeObject(arFragment, hits.get(i).createAnchor(), parse);
              }
          }
      }
  }

  private final void placeObject(final ArFragment fragment, final Anchor createAnchor, Uri model) {
      ModelRenderable.builder().setSource(fragment.getContext(), model).build().thenAccept((new Consumer() {
          public void accept(Object var1) {
              this.accept((ModelRenderable) var1);
          }

          public final void accept(ModelRenderable it) {
              if (it != null)
                  MainActivity.this.addNode(arFragment, createAnchor, it);
          }
      })).exceptionally((new Function() {
          public Object apply(Object var1) {
              return this.apply((Throwable) var1);
          }

          @Nullable
          public final Void apply(Throwable it) {
              AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
              builder.setMessage(it.getMessage()).setTitle("error!");
              AlertDialog dialog = builder.create();
              dialog.show();
              return null;
          }
      }));
  }

  private void addNode(ArFragment fragment, Anchor createAnchor, ModelRenderable renderable) {

      AnchorNode anchorNode = new AnchorNode(createAnchor);
      TransformableNode transformableNode = new TransformableNode(fragment.getTransformationSystem());
      transformableNode.setRenderable(renderable);
      transformableNode.setParent(anchorNode);
      fragment.getArSceneView().getScene().addChild(anchorNode);
      transformableNode.select();
  }

  private Point getScreenCenter() {
      View vw = findViewById(android.R.id.content);
      return new Point(vw.getWidth()/2, vw.getHeight()/2);
  }
}

锚点是模型或者节点在屏幕中的放置位置。
这是屏幕的中心。

在" addObject()"中,ARFragment使用运动跟踪获取飞机上的生命值。

placeObject()异步将节点设置为屏幕的中心。