从科幻故事到科学现实,增强现实已经走了很长一段路。以如此高的技术进步速度,就像托尼·史塔克(Tony Stark)在他的实验室中所做的那样,我们还可以在这个真实的物理世界中操纵数字数据可能并不遥远。当我们将诸如声音,文本,图像之类的信息叠加到现实世界中时,还可以通过一种特殊的媒体(即增强现实)与之交互。举世闻名的“ Pokemon GO”应用程序只是增强现实应用程序的另一个示例。让我们使用Java在Android Studio中制作一个非常简单的增强现实应用程序。该应用程序显示使用手机摄像头定制或下载的3d模型。下面的样本GIF给出得到什么我们将在本文中做的想法。
术语
- ARCore:据Google称,ARCore是增强现实的平台。实际上,ARCore可以帮助手机感知环境并与世界互动。 ARCore主要使用3个关键原理-运动跟踪,理解环境和光照估计。这是Google提供的支持ARCore的手机列表。
- Sceneform:根据Google的说法,Sceneform是一个3d框架,可帮助开发人员在不了解OpenGL的情况下构建ARCore应用。 Sceneform具有许多功能,例如检查相机许可,操纵3d资产等等。
分步实施
步骤1:创建一个新项目
要在Android Studio中创建新项目,请参阅如何在Android Studio中创建/启动新项目。
Note:
- Select Java as the programming language.
- Note the location where the app is getting saved because we need that path later.
- Choose ‘Minimum SDK‘ as ‘API 24: Android 7.0(Nougat)‘
步骤2:取得3D模型
Scenform 1.16.0仅支持glTF文件。 glTF表示GL传输格式。现在, .glb文件是GL传输格式的二进制版本。这些类型的3d模型文件在VR,AR中使用,因为它支持运动和动画。
- 对于3D模型,您必须获得一个.glb文件。
- 有两种方法,您可以获取3D模型,从网上下载或自己制作3D模型。
- 如果您想从网络上下载它,请转到由Google,poly提供的3d模型库,然后搜索任何glb文件。为您的项目下载其中任何一个。
- 或者,获得3D计算机图形软件并自己制作3d模型。
- 我使用了完全免费下载的Blender ,并制作了GEEKS FOR GEEKS文本的3D模型。从这里获取此文件。
- 将模型作为.glb文件导出到特定文件夹,并且文件名必须包含small_letters或数字。
- 回到Android Studio。
- 在左侧面板上,右键单击res目录。转到“新建”>“ Android资源目录” 。将会弹出一个窗口。
- 将资源类型:更改为Raw 。单击确定。将在res目录下生成一个原始文件夹。
- 复制。保存该目录的glb文件,并将其粘贴到原始文件夹下。
步骤3:下载并设置SceneForm 1.16.0
好吧,对于AR应用程序,我们需要Sceneform SDK。 SceneForm 1.15.0非常有名,但是最近,在最新的Android Studio 4.1中获取“ Google Sceneform Tools(Beta)”插件时遇到了一些插件错误。所以我在这里,使用Sceneform 1.16.0 SDK并手动进行设置。
- 转到此GitHub链接。
- 下载“ sceneform-android-sdk-1.16.0.zip ”文件。
- 解压缩创建项目的“ sceneformsrc ”和“ sceneformux ”文件夹。 (对我来说是“ E:\ android \ ARApp”)
- 前往Android Studio
- 转到Gradle脚本> settings.gradle(项目设置)
- 添加这些行:
// this will add sceneformsrc folder into your project
include ‘:sceneform’
project(‘:sceneform’).projectDir = new File(‘sceneformsrc/sceneform’)
// this will add sceneformux folder into your project
include ‘:sceneformux’
project(‘:sceneformux’).projectDir = new File(‘sceneformux/ux’)
- 之后,转到Gradle脚本> build.gradle(Module:app)
- 在依赖关系块内添加此行。
api project(“:sceneformux”)
- 然后在“ android”块内的同一文件中,并在“ buildTypes”块之后添加以下行(如果尚不存在):
// to support java 8 in your project
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
- 毕竟,这些更改在上面的弹出窗口中单击“立即同步”。现在,Android文件结构将如下所示。
- 然后转到应用程序>清单> AndroidManifest.xml
- 将这些行添加到“ application ”块之前:
XML
XML
XML
XML
Java
// object of ArFragment Class
private ArFragment arCam;
Java
public static boolean checkSystemSupport(Activity activity) {
// checking whether the API version of the running Android >= 24
// that means Android Nougat 7.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String openGlVersion = ((ActivityManager) Objects.requireNonNull(activity.getSystemService(Context.ACTIVITY_SERVICE))).getDeviceConfigurationInfo().getGlEsVersion();
// checking whether the OpenGL version >= 3.0
if (Double.parseDouble(openGlVersion) >= 3.0) {
return true;
} else {
Toast.makeText(activity, "App needs OpenGl Version 3.0 or later", Toast.LENGTH_SHORT).show();
activity.finish();
return false;
}
} else {
Toast.makeText(activity, "App does not support required Build Version", Toast.LENGTH_SHORT).show();
activity.finish();
return false;
}
}
Java
// ArFragment is linked up with its respective id used in the activity_main.xml
arCam = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.arCameraArea);
Java
arCam.setOnTapArPlaneListener((hitResult, plane, motionEvent) -> {
clickNo++;
// the 3d model comes to the scene only the first time we tap the screen
if (clickNo == 1) {
Anchor anchor = hitResult.createAnchor();
ModelRenderable.builder()
.setSource(this, R.raw.gfg_gold_text_stand_2)
.setIsFilamentGltf(true)
.build()
.thenAccept(modelRenderable -> addModel(anchor, modelRenderable))
.exceptionally(throwable -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Somthing is not right" + throwable.getMessage()).show();
return null;
});
}
});
Java
private void addModel(Anchor anchor, ModelRenderable modelRenderable) {
// Creating a AnchorNode with a specific anchor
AnchorNode anchorNode = new AnchorNode(anchor);
// attaching the anchorNode with the ArFragment
anchorNode.setParent(arCam.getArSceneView().getScene());
TransformableNode transform = new TransformableNode(arCam.getTransformationSystem());
// attaching the anchorNode with the TransformableNode
transform.setParent(anchorNode);
// attaching the 3d model with the TransformableNode that is
// already attached with the node
transform.setRenderable(modelRenderable);
transform.select();
}
Java
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.ar.core.Anchor;
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.Objects;
public class MainActivity extends AppCompatActivity {
// object of ArFragment Class
private ArFragment arCam;
// helps to render the 3d model
// only once when we tap the screen
private int clickNo = 0;
public static boolean checkSystemSupport(Activity activity) {
// checking whether the API version of the running Android >= 24
// that means Android Nougat 7.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String openGlVersion = ((ActivityManager) Objects.requireNonNull(activity.getSystemService(Context.ACTIVITY_SERVICE))).getDeviceConfigurationInfo().getGlEsVersion();
// checking whether the OpenGL version >= 3.0
if (Double.parseDouble(openGlVersion) >= 3.0) {
return true;
} else {
Toast.makeText(activity, "App needs OpenGl Version 3.0 or later", Toast.LENGTH_SHORT).show();
activity.finish();
return false;
}
} else {
Toast.makeText(activity, "App does not support required Build Version", Toast.LENGTH_SHORT).show();
activity.finish();
return false;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkSystemSupport(this)) {
// ArFragment is linked up with its respective id used in the activity_main.xml
arCam = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.arCameraArea);
arCam.setOnTapArPlaneListener((hitResult, plane, motionEvent) -> {
clickNo++;
// the 3d model comes to the scene only
// when clickNo is one that means once
if (clickNo == 1) {
Anchor anchor = hitResult.createAnchor();
ModelRenderable.builder()
.setSource(this, R.raw.gfg_gold_text_stand_2)
.setIsFilamentGltf(true)
.build()
.thenAccept(modelRenderable -> addModel(anchor, modelRenderable))
.exceptionally(throwable -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Somthing is not right" + throwable.getMessage()).show();
return null;
});
}
});
} else {
return;
}
}
private void addModel(Anchor anchor, ModelRenderable modelRenderable) {
// Creating a AnchorNode with a specific anchor
AnchorNode anchorNode = new AnchorNode(anchor);
// attaching the anchorNode with the ArFragment
anchorNode.setParent(arCam.getArSceneView().getScene());
// attaching the anchorNode with the TransformableNode
TransformableNode model = new TransformableNode(arCam.getTransformationSystem());
model.setParent(anchorNode);
// attaching the 3d model with the TransformableNode
// that is already attached with the node
model.setRenderable(modelRenderable);
model.select();
}
}
- 之后,在“ activity ”块之前添加此行。
XML格式
以下是AndroidManifest.xml文件的完整代码。
XML格式
步骤4:错误更正
现在出现了一些无聊的部分。下载的文件夹sceneformsrc和sceneformux包含一些Java文件,该文件从较旧的android.support导入Java类。因此,现在,如果您构建项目,您将因此而看到很多错误。您现在所要做的就是将您的项目迁移到新的Androidx上。现在,您可以找到一种将整个项目迁移到Androidx的方法,也可以手动一个接一个地更改导入。我知道这很无聊,但是等待的人会遇到好事,对吗?
- 转到构建>重建项目
- 您会发现大量错误。因此,在“构建”部分中,双击程序包导入错误。将打开一个代码,突出显示错误部分。
- 每当您看到第一个导入路径将其更改为第二个导入路径时,只需更改下面给出的三种类型的导入路径:
- android.support.annotation。 -> androidx.annotation。
- androidx.core.app-> androidx.fragment.app。
- android.support.v7.widget。 -> androidx.appcompat.widget。
- 您必须继续执行此操作,直到没有其他错误为止。
步骤5:使用activity_main.xml 文件
- 转到res>布局> activity_main.xml文件。
- 这是该XML文件的代码:
XML格式
- ArFragment本身包含许多功能,例如,它要求您下载ARCore(如果尚未将其安装在手机中),或者要求它获得摄像头许可(如果尚未被授予)。因此, ArFragment是在此处使用的最佳方法。
- 编写此代码后,App UI将如下所示:
步骤6:使用MainActivity。 Java文件
- 转到Java > com.wheic.arapp (您的可能有所不同) > MainActivity。Java
- 在MainActivity类中,首先,我们必须创建一个ArFragment对象。
Java
// object of ArFragment Class
private ArFragment arCam;
- 现在,让我们创建的onCreate()函数之外的硬件检测函数。此函数将检查您手机的硬件是否满足运行此AR App的所有系统要求。它要检查:
- 是正在运行的Android> = 24的API版本,这意味着Android Nougat 7.0
- OpenGL版本是否> = 3.0
- 必须具备这些才能使用ARCore和Sceneform运行AR应用程序。这是该函数的代码:
Java
public static boolean checkSystemSupport(Activity activity) {
// checking whether the API version of the running Android >= 24
// that means Android Nougat 7.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String openGlVersion = ((ActivityManager) Objects.requireNonNull(activity.getSystemService(Context.ACTIVITY_SERVICE))).getDeviceConfigurationInfo().getGlEsVersion();
// checking whether the OpenGL version >= 3.0
if (Double.parseDouble(openGlVersion) >= 3.0) {
return true;
} else {
Toast.makeText(activity, "App needs OpenGl Version 3.0 or later", Toast.LENGTH_SHORT).show();
activity.finish();
return false;
}
} else {
Toast.makeText(activity, "App does not support required Build Version", Toast.LENGTH_SHORT).show();
activity.finish();
return false;
}
}
- 首先在onCreate()函数,我们需要检查手机的硬件。如果返回true,则该函数的其余部分将执行。
- 现在ArFragment链接了在activity_main.xml中使用其各自的ID。
Java
// ArFragment is linked up with its respective id used in the activity_main.xml
arCam = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.arCameraArea);
- 当我们点击屏幕时,将调用onTapListener来显示3d模型。
- 在setOnTapArPlaneListener内部,创建一个Anchor对象。锚实际上有助于将虚拟对象显示在屏幕上,并使它们在空间中保持相同的位置和方向。
- 现在,ModelRenderable类与一堆函数一起使用。此类用于通过将下载的或创建的3d模型附加到AnchorNode来呈现它。
- setSource()函数有助于获取3d模型的源。
- setIsFilamentGltf()函数检查它是否是glb文件。
- build()函数呈现模型。
- 然后在thenAccept()函数内部调用一个函数,以通过将AnchorNode附加到ModelRenderable来接收模型。
- 如果在构建模型时出现问题, exclusively ()函数将引发异常。
Java
arCam.setOnTapArPlaneListener((hitResult, plane, motionEvent) -> {
clickNo++;
// the 3d model comes to the scene only the first time we tap the screen
if (clickNo == 1) {
Anchor anchor = hitResult.createAnchor();
ModelRenderable.builder()
.setSource(this, R.raw.gfg_gold_text_stand_2)
.setIsFilamentGltf(true)
.build()
.thenAccept(modelRenderable -> addModel(anchor, modelRenderable))
.exceptionally(throwable -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Somthing is not right" + throwable.getMessage()).show();
return null;
});
}
});
- 现在,让我们看看addModel()函数:
- 它有两个参数,第一个是Anchor,另一个是ModelRenderable。
- 创建一个AnchorNode对象。它是场景的根节点。基于Anchor的AnchorNode自动定位在世界上。
- TransformableNode可帮助用户与3d模型进行交互,例如更改位置,调整大小,旋转等。
Java
private void addModel(Anchor anchor, ModelRenderable modelRenderable) {
// Creating a AnchorNode with a specific anchor
AnchorNode anchorNode = new AnchorNode(anchor);
// attaching the anchorNode with the ArFragment
anchorNode.setParent(arCam.getArSceneView().getScene());
TransformableNode transform = new TransformableNode(arCam.getTransformationSystem());
// attaching the anchorNode with the TransformableNode
transform.setParent(anchorNode);
// attaching the 3d model with the TransformableNode that is
// already attached with the node
transform.setRenderable(modelRenderable);
transform.select();
}
这是MainActivity的完整代码。 Java文件。在代码内部添加了注释,以更详细地了解代码。
Java
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.ar.core.Anchor;
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.Objects;
public class MainActivity extends AppCompatActivity {
// object of ArFragment Class
private ArFragment arCam;
// helps to render the 3d model
// only once when we tap the screen
private int clickNo = 0;
public static boolean checkSystemSupport(Activity activity) {
// checking whether the API version of the running Android >= 24
// that means Android Nougat 7.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String openGlVersion = ((ActivityManager) Objects.requireNonNull(activity.getSystemService(Context.ACTIVITY_SERVICE))).getDeviceConfigurationInfo().getGlEsVersion();
// checking whether the OpenGL version >= 3.0
if (Double.parseDouble(openGlVersion) >= 3.0) {
return true;
} else {
Toast.makeText(activity, "App needs OpenGl Version 3.0 or later", Toast.LENGTH_SHORT).show();
activity.finish();
return false;
}
} else {
Toast.makeText(activity, "App does not support required Build Version", Toast.LENGTH_SHORT).show();
activity.finish();
return false;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkSystemSupport(this)) {
// ArFragment is linked up with its respective id used in the activity_main.xml
arCam = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.arCameraArea);
arCam.setOnTapArPlaneListener((hitResult, plane, motionEvent) -> {
clickNo++;
// the 3d model comes to the scene only
// when clickNo is one that means once
if (clickNo == 1) {
Anchor anchor = hitResult.createAnchor();
ModelRenderable.builder()
.setSource(this, R.raw.gfg_gold_text_stand_2)
.setIsFilamentGltf(true)
.build()
.thenAccept(modelRenderable -> addModel(anchor, modelRenderable))
.exceptionally(throwable -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Somthing is not right" + throwable.getMessage()).show();
return null;
});
}
});
} else {
return;
}
}
private void addModel(Anchor anchor, ModelRenderable modelRenderable) {
// Creating a AnchorNode with a specific anchor
AnchorNode anchorNode = new AnchorNode(anchor);
// attaching the anchorNode with the ArFragment
anchorNode.setParent(arCam.getArSceneView().getScene());
// attaching the anchorNode with the TransformableNode
TransformableNode model = new TransformableNode(arCam.getTransformationSystem());
model.setParent(anchorNode);
// attaching the 3d model with the TransformableNode
// that is already attached with the node
model.setRenderable(modelRenderable);
model.select();
}
}
输出:在物理设备上运行
最后,我们使用Android Studio构建了一个简单的增强现实应用程序。您可以在此GitHub链接中检查该项目。