Πώς να δημιουργήσετε μια εφαρμογή Android Augmented Reality με το ARCore και το Android Studio

Αυτό το άρθρο δημοσιεύτηκε αρχικά εδώ

Στην προηγούμενη ανάρτηση, εξήγησα τι είναι το ARCore και πώς βοηθά τους προγραμματιστές να δημιουργήσουν εκπληκτικές εφαρμογές επαυξημένης πραγματικότητας χωρίς να χρειάζεται να κατανοήσουν τα μαθηματικά OpenGL ή Matrix .

Εάν δεν το έχετε ελέγξει ακόμη, σας συνιστώ να το κάνετε πριν προχωρήσετε σε αυτό το άρθρο και να εξερευνήσετε την ανάπτυξη εφαρμογών ARCore.

ΣΦΑΙΡΙΚΗ ΕΙΚΟΝΑ

Σύμφωνα με τη Wikipedia, το ARCore είναι ένα κιτ ανάπτυξης λογισμικού που αναπτύχθηκε από την Google και επιτρέπει την κατασκευή εφαρμογών επαυξημένης πραγματικότητας.

Η ARCore χρησιμοποιεί τρεις βασικές τεχνολογίες για την ενσωμάτωση εικονικού περιεχομένου στο πραγματικό περιβάλλον:

  1. Motion Tracking: επιτρέπει στο τηλέφωνο να κατανοήσει τη θέση του σε σχέση με τον κόσμο.
  2. Περιβαλλοντική κατανόηση: Αυτό επιτρέπει στο τηλέφωνο να εντοπίσει το μέγεθος και τη θέση όλων των τύπων επιφανειών, κάθετων, οριζόντιων και υπό γωνία.
  3. Εκτίμηση φωτός: επιτρέπει στο τηλέφωνο να εκτιμήσει τις τρέχουσες συνθήκες φωτισμού του περιβάλλοντος.

Ξεκινώντας

Για να ξεκινήσετε με την ανάπτυξη εφαρμογών ARCore , πρέπει πρώτα να ενεργοποιήσετε το ARCore στο έργο σας. Αυτό είναι απλό καθώς θα χρησιμοποιούμε το Android Studio και το Sceneform SDK. Υπάρχουν δύο σημαντικές λειτουργίες που εκτελεί αυτόματα το Sceneform:

  1. Έλεγχος για διαθεσιμότητα του ARCore
  2. Ζητώντας άδεια κάμερας

Δεν χρειάζεται να ασχοληθείτε με αυτά τα δύο βήματα κατά τη δημιουργία μιας εφαρμογής ARCore χρησιμοποιώντας το Sceneform SDK. Αλλά πρέπει να συμπεριλάβετε το Sceneform SDK στο έργο σας.

Δημιουργήστε ένα νέο έργο Android Studio και επιλέξτε μια κενή δραστηριότητα.

Προσθέστε την ακόλουθη εξάρτηση στο αρχείο build.gradle σε επίπεδο έργου:

dependencies { classpath 'com.google.ar.sceneform:plugin:1.5.0'}

Προσθέστε τα ακόλουθα στο αρχείο build.gradle σε επίπεδο εφαρμογής:

implementation "com.google.ar.sceneform.ux:sceneform-ux:1.5.0"

Τώρα συγχρονίστε το έργο με αρχεία Gradle και περιμένετε να ολοκληρωθεί η κατασκευή. Αυτό θα εγκαταστήσει το Sceneform SDK στο έργο και το Sceneform plugin στο AndroidStudio . Θα σας βοηθήσει να δείτε το. αρχεία sfb . Αυτά τα αρχεία είναι τα μοντέλα 3D που αποδίδονται στην κάμερά σας. Σας βοηθά επίσης στην εισαγωγή, προβολή και δημιουργία τρισδιάστατων στοιχείων .

Δημιουργία της πρώτης σας εφαρμογής ARCore

Τώρα με την ολοκλήρωση της εγκατάστασης του Android Studio και το Sceneform SDK, μπορούμε να ξεκινήσουμε με τη σύνταξη της πρώτης μας εφαρμογής ARCore.

Πρώτον, πρέπει να προσθέσουμε το τμήμα Sceneform στο αρχείο διάταξής μας. Αυτή θα είναι η σκηνή όπου θα τοποθετήσουμε όλα τα τρισδιάστατα μοντέλα μας. Φροντίζει για την προετοιμασία της κάμερας και το χειρισμό αδειών.

Μεταβείτε στο κύριο αρχείο διάταξης. Στην περίπτωσή μου είναι activity_main.xml και προσθέστε το τμήμα Sceneform:

Έχω ρυθμίσει το πλάτος και το ύψος να ταιριάζει με τον γονέα, καθώς αυτό θα καλύψει ολόκληρη τη δραστηριότητά μου. Μπορείτε να επιλέξετε τις διαστάσεις σύμφωνα με τις απαιτήσεις σας.

Έλεγχος συμβατότητας

Αυτό είναι το μόνο που πρέπει να κάνετε στο αρχείο διάταξης. Τώρα κατευθυνθείτε προς το αρχείο java, στην περίπτωσή μου που είναι MainActivity.java. Προσθέστε την παρακάτω μέθοδο στην τάξη σας:

public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { Log.e(TAG, "Sceneform requires Android N or later"); Toast.makeText(activity, "Sceneform requires Android N or later", Toast.LENGTH_LONG).show(); activity.finish(); return false; } String openGlVersionString = ((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE)) .getDeviceConfigurationInfo() .getGlEsVersion(); if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) { Log.e(TAG, "Sceneform requires OpenGL ES 3.0 later"); Toast.makeText(activity, "Sceneform requires OpenGL ES 3.0 or later", Toast.LENGTH_LONG) .show(); activity.finish(); return false; } return true;}

Αυτή η μέθοδος ελέγχει εάν η συσκευή σας μπορεί να υποστηρίζει Sceneform SDK ή όχι. Το SDK απαιτεί Android API επίπεδο 27 ή νεότερο και OpenGL ES έκδοση 3.0 ή νεότερη. Εάν μια συσκευή δεν υποστηρίζει αυτά τα δύο, η Σκηνή δεν θα αποδοθεί και η εφαρμογή σας θα εμφανίσει μια κενή οθόνη.

Ωστόσο, μπορείτε να συνεχίσετε να παραδίδετε όλες τις άλλες δυνατότητες της εφαρμογής σας που δεν απαιτούν το Sceneform SDK.

Τώρα με τον έλεγχο συμβατότητας συσκευών ολοκληρωμένο, θα δημιουργήσουμε το τρισδιάστατο μοντέλο μας και θα το επισυνάψουμε στη σκηνή.

Προσθήκη στοιχείων

Θα χρειαστεί να προσθέσετε τα τρισδιάστατα μοντέλα που θα εμφανιστούν στην οθόνη σας. Τώρα μπορείτε να δημιουργήσετε αυτά τα μοντέλα μόνοι σας εάν είστε εξοικειωμένοι με τη δημιουργία μοντέλων 3D. Ή, μπορείτε να επισκεφθείτε το Poly.

Εκεί θα βρείτε ένα τεράστιο αποθετήριο τρισδιάστατων στοιχείων για να διαλέξετε. Είναι δωρεάν για λήψη. Απλώς πιστώστε τον δημιουργό και είστε έτοιμοι.

Στο Android Studio, αναπτύξτε τον φάκελο της εφαρμογής που είναι διαθέσιμος στο αριστερό τμήμα του έργου. Θα παρατηρήσετε ένα φάκελο " sampledata " . Αυτός ο φάκελος θα περιέχει όλα τα στοιχεία του μοντέλου 3D. Δημιουργήστε ένα φάκελο για το μοντέλο σας μέσα στο δείγμα φακέλου δεδομένων.

Όταν κατεβάζετε το αρχείο zip από το poly, πιθανότατα θα βρείτε 3 αρχεία.

  1. αρχείο .mtl
  2. αρχείο .obj
  3. αρχείο .png

Το πιο σημαντικό από αυτά τα 3 είναι το αρχείο .obj. Είναι το πραγματικό σας μοντέλο. Τοποθετήστε και τα 3 αρχεία μέσα στο sampledata -> "το πτυσσόμενο μοντέλο του μοντέλου σας ".

Τώρα κάντε δεξί κλικ στο αρχείο .obj . Η πρώτη επιλογή θα ήταν η Εισαγωγή περιουσιακού στοιχείου σκηνικού. Κάντε κλικ σε αυτό, μην αλλάξετε τις προεπιλεγμένες ρυθμίσεις, απλώς κάντε κλικ στο φινίρισμα στο επόμενο παράθυρο. Η διαβάθμιση θα συγχρονιστεί ώστε να περιλαμβάνει το στοιχείο στο φάκελο στοιχείων. Μόλις ολοκληρωθεί η κατασκευή του gradle, μπορείτε να πάτε.

Ολοκληρώσατε την εισαγωγή ενός στοιχείου 3D που χρησιμοποιείται από το Sceneform στο έργο σας. Στη συνέχεια , ας δημιουργήσουμε το στοιχείο από τον κώδικα μας και να το συμπεριλάβουμε στη σκηνή.

Δημιουργία του Μοντέλου

Προσθέστε τον ακόλουθο κώδικα στο αρχείο MainActivity.java (ή ό, τι είναι στην περίπτωσή σας). Μην ανησυχείτε, θα εξηγήσω όλη τη γραμμή κώδικα ανά γραμμή:

private static final String TAG = MainActivity.class.getSimpleName();private static final double MIN_OPENGL_VERSION = 3.0;
ArFragment arFragment;ModelRenderable lampPostRenderable;
@[email protected]({"AndroidApiChecker", "FutureReturnValueIgnored"})
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!checkIsSupportedDeviceOrFinish(this)) { return; } setContentView(R.layout.activity_main); arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment);
 ModelRenderable.builder() .setSource(this, Uri.parse("LampPost.sfb")) .build() .thenAccept(renderable -> lampPostRenderable = renderable) .exceptionally(throwable -> { Toast toast = Toast.makeText(this, "Unable to load andy renderable", Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); return null; });
}

First, we find the arFragment that we included in the layout file. This fragment is responsible for hosting the scene. You can think of it as the container of our scene.

Next, we are using the ModelRenderable class to build our model. With the help of setSource method, we load our model from the .sfb file. This file was generated when we imported the assets. thenAccept method receives the model once it is built. We set the loaded model to our lampPostRenderable.

For error handling, we have .exceptionally method. It is called in case an exception is thrown.

All this happens asynchronously, hence you don’t need to worry about multi-threading or deal with handlers XD

With the model loaded and stored in the lampPostRenderable variable, we’ll now add it to our scene.

Adding the Model to Scene

The arFragment hosts our scene and will receive the tap events. So we need to set the onTap listener to our fragment to register the tap and place an object accordingly. Add the following code to onCreate method:

arFragment.setOnTapArPlaneListener( (HitResult hitresult, Plane plane, MotionEvent motionevent) -> { if (lampPostRenderable == null){ return; }
 Anchor anchor = hitresult.createAnchor(); AnchorNode anchorNode = new AnchorNode(anchor); anchorNode.setParent(arFragment.getArSceneView().getScene());
 TransformableNode lamp = new TransformableNode(arFragment.getTransformationSystem()); lamp.setParent(anchorNode); lamp.setRenderable(lampPostRenderable); lamp.select(); });

We set the onTapArPlaneListener to our AR fragment. Next what you see is the Java 8 syntax, in case you are not familiar with it, I would recommend checking out this guide.

First, we create our anchor from the HitResult using hitresult.createAnchor() and store it in an Anchor object.

Next, create a node out of this anchor. It will be called AnchorNode. It will be attached to the scene by calling the setParent method on it and passing the scene from the fragment.

Now we create a TransformableNode which will be our lamppost and set it to the anchor spot or our anchor node. The node still doesn’t have any information about the object it has to render. We’ll pass that object using lamp.setRenderable method which takes in a renderable as it’s parameter. Finally call lamp.select();

Phew!! Too much terminology there, but don’t worry, I’ll explain it all.

  1. Scene: This is the place where all your 3D objects will be rendered. This scene is hosted by the AR Fragment which we included in the layout. An anchor node is attached to this screen which acts as the root of the tree and all the other objects are rendered as its objects.
  2. HitResult: This is an imaginary line (or a ray) coming from infinity which gives the point of intersection of itself with a real-world object.
  3. Anchor: An anchor is a fixed location and orientation in the real world. It can be understood as the x,y,z coordinate in the 3D space. You can get an anchor’s post information from it. Pose is the position and orientation of the object in the scene. This is used to transform the object’s local coordinate space into real-world coordinate space.
  4. AnchorNode: This is the node that automatically positions itself in the world. This is the first node that gets set when the plane is detected.
  5. TransformableNode: It is a node that can be interacted with. It can be moved around, scaled rotated and much more. In this example, we can scale the lamp and rotate it. Hence the name Transformable.

There is no rocket science here. It’s really simple. The entire scene can be viewed as a graph with Scene as the parent, AnchorNode as its child and then branching out different nodes/objects to be rendered on the screen.

Your final MainActivity.java must look something like this:

package com.ayusch.arcorefirst;
import android.app.Activity;import android.app.ActivityManager;import android.content.Context;import android.net.Uri;import android.os.Build;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.Gravity;import android.view.MotionEvent;import android.widget.Toast;
import com.google.ar.core.Anchor;import com.google.ar.core.HitResult;import com.google.ar.core.Plane;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;
public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private static final double MIN_OPENGL_VERSION = 3.0;
 ArFragment arFragment; ModelRenderable lampPostRenderable;
 @Override @SuppressWarnings({"AndroidApiChecker", "FutureReturnValueIgnored"}) protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!checkIsSupportedDeviceOrFinish(this)) { return; } setContentView(R.layout.activity_main); arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment);
 ModelRenderable.builder() .setSource(this, Uri.parse("LampPost.sfb")) .build() .thenAccept(renderable -> lampPostRenderable = renderable) .exceptionally(throwable -> { Toast toast = Toast.makeText(this, "Unable to load andy renderable", Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); return null; });
 arFragment.setOnTapArPlaneListener( (HitResult hitresult, Plane plane, MotionEvent motionevent) -> { if (lampPostRenderable == null){ return; }
 Anchor anchor = hitresult.createAnchor(); AnchorNode anchorNode = new AnchorNode(anchor); anchorNode.setParent(arFragment.getArSceneView().getScene());
 TransformableNode lamp = new TransformableNode(arFragment.getTransformationSystem()); lamp.setParent(anchorNode); lamp.setRenderable(lampPostRenderable); lamp.select(); } );
 }
 public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { Log.e(TAG, "Sceneform requires Android N or later"); Toast.makeText(activity, "Sceneform requires Android N or later", Toast.LENGTH_LONG).show(); activity.finish(); return false; } String openGlVersionString = ((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE)) .getDeviceConfigurationInfo() .getGlEsVersion(); if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) { Log.e(TAG, "Sceneform requires OpenGL ES 3.0 later"); Toast.makeText(activity, "Sceneform requires OpenGL ES 3.0 or later", Toast.LENGTH_LONG) .show(); activity.finish(); return false; } return true; }}

Congratulations!! You’ve just completed your first ARCore app. Start adding objects and see them come alive in the real world!

This was your first look into how to create a simple ARCore app from scratch with Android studio. In the next tutorial, I would be going deeper into ARCore and adding more functionality to the app.

If you have any suggestions or any topic you would want a tutorial on, just mention in the comments section and I’ll be happy to oblige.

Σας αρέσει αυτό που διαβάζετε; Μην ξεχάσετε να μοιραστείτε αυτήν την ανάρτηση σε Facebook , Whatsapp και LinkedIn .

Μπορείτε να με ακολουθήσετε στο LinkedIn, το Quora, το Twitter και το Instagram όπου απαντώ σε ερωτήσεις που σχετίζονται με την ανάπτυξη κινητών συσκευών, ειδικά το Android και το Flutter .