Android增强现实– Android ARCore示例
在本教程中,我们将讨论增强现实,并使用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()异步将节点设置为屏幕的中心。