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()异步将节点设置为屏幕的中心。

