📌  相关文章
📜  如何构建一个简单的增强现实Android应用程序?

📅  最后修改于: 2021-05-09 16:54:55             🧑  作者: Mango

从科幻故事到科学现实,增强现实已经走了很长一段路。以如此高的技术进步速度,就像托尼·史塔克(Tony Stark)在他的实验室中所做的那样,我们还可以在这个真实的物理世界中操纵数字数据可能并不遥远。当我们将诸如声音,文本,图像之类的信息叠加到现实世界中时,还可以通过一种特殊的媒体(即增强现实)与之交互。举世闻名的“ Pokemon GO”应用程序只是增强现实应用程序的另一个示例。让我们使用JavaAndroid Studio中制作一个非常简单的增强现实应用程序。该应用程序显示使用手机摄像头定制或下载的3d模型。下面的样本GIF给出得到什么我们将在本文中做的想法

构建一个简单的增强现实Android应用

术语

  • ARCore:据Google称,ARCore是增强现实的平台。实际上,ARCore可以帮助手机感知环境并与世界互动。 ARCore主要使用3个关键原理-运动跟踪,理解环境和光照估计。这是Google提供的支持ARCore的手机列表。
  • Sceneform:根据Google的说法,Sceneform是一个3d框架,可帮助开发人员在不了解OpenGL的情况下构建ARCore应用。 Sceneform具有许多功能,例如检查相机许可,操纵3d资产等等。

分步实施

步骤1:创建一个新项目

要在Android Studio中创建新项目,请参阅如何在Android Studio中创建/启动新项目。

构建一个简单的增强现实Android应用

步骤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数字

用于GEEKS GLB文件的GEEKS

  • 回到Android Studio。
  • 在左侧面板上,右键单击res目录。转到“新建”>“ Android资源目录” 。将会弹出一个窗口。

构建一个简单的增强现实Android应用

  • 资源类型:更改为Raw 。单击确定。将在res目录下生成一个原始文件夹。

构建一个简单的增强现实Android应用

  • 复制保存该目录的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(项目设置)
  • 添加这些行:
  • 之后,转到Gradle脚本> build.gradle(Module:app)
  • 依赖关系块添加此行
  • 然后在“ android”块内的同一文件中,并在“ buildTypes”块之后添加以下行(如果尚不存在):
  • 毕竟,这些更改在上面的弹出窗口中单击“立即同步”。现在,Android文件结构将如下所示。

构建一个简单的增强现实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:错误更正

现在出现了一些无聊的部分。下载的文件夹sceneformsrcsceneformux包含一些Java文件,该文件从较旧的android.support导入Java类。因此,现在,如果您构建项目,您将因此而看到很多错误。您现在所要做的就是将您的项目迁移到新的Androidx上。现在,您可以找到一种将整个项目迁移到Androidx的方法,也可以手动一个接一个地更改导入。我知道这很无聊,但是等待的人会遇到好事,对吗?

  • 转到构建>重建项目
  • 您会发现大量错误。因此,在“构建”部分中,双击程序包导入错误。将打开一个代码,突出显示错误部分。
  • 每当您看到第一个导入路径将其更改为第二个导入路径时,只需更改下面给出的三种类型的导入路径:
    • android.support.annotation。 -> androidx.annotation。
    • androidx.core.app-> androidx.fragment.app。
    • android.support.v7.widget。 -> androidx.appcompat.widget。

构建一个简单的增强现实Android应用构建一个简单的增强现实Android应用

  • 您必须继续执行此操作,直到没有其他错误为止。

步骤5:使用activity_main.xml  文件

  • 转到res>布局> activity_main.xml文件。
  • 这是该XML文件的代码:

XML格式



  
    
    
  

  • ArFragment本身包含许多功能,例如,它要求您下载ARCore(如果尚未将其安装在手机中),或者要求它获得摄像头许可(如果尚未被授予)。因此, ArFragment是在此处使用的最佳方法。
  • 编写此代码后,App UI将如下所示:

构建一个简单的增强现实Android应用

步骤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链接中检查该项目。

想要一个节奏更快,更具竞争性的环境来学习Android的基础知识吗?
单击此处,前往由我们的专家精心策划的指南,以使您立即做好行业准备!