Hogyan készítsen kiterjesztett valóság Android alkalmazást az ARCore és az Android Studio segítségével

Ezt a cikket eredetileg itt tették közzé

Az előző bejegyzésben elmagyaráztam, hogy mi az ARCore, és hogyan segít a fejlesztőknek félelmetes kiterjesztett valóság-alkalmazások készítésében anélkül, hogy meg kellene értenünk az OpenGL vagy a Matrix matematikáját.

Ha még nem nézte meg, nagyon ajánlom, mielőtt ezt a cikket folytatja, és belemerül az ARCore alkalmazás fejlesztésébe.

Áttekintés

A Wikipedia szerint az ARCore a Google által kifejlesztett szoftverfejlesztő készlet, amely lehetővé teszi a kibővített valóság alkalmazásainak felépítését.

Az ARCore három kulcsfontosságú technológiát alkalmaz a virtuális tartalom integrálásához a valós környezettel:

  1. Mozgáskövetés: lehetővé teszi a telefon számára, hogy megértse helyzetét a világhoz képest.
  2. Környezeti megértés: Ez lehetővé teszi a telefon számára, hogy felismerje az összes típusú, függőleges, vízszintes és ferde felület felületét.
  3. Fény becslés: lehetővé teszi a telefon számára, hogy megbecsülje a környezet jelenlegi fényviszonyait.

Elkezdeni

Az ARCore alkalmazás fejlesztésének megkezdéséhez először engedélyeznie kell az ARCore alkalmazást a projektben. Ez egyszerű, mivel az Android Stúdiót és a Sceneform SDK-t fogjuk használni. A Sceneform két fő műveletet hajt végre:

  1. Az ARCore elérhetőségének ellenőrzése
  2. Kamera engedély kérése

Nem kell bajlódnia ezzel a két lépéssel, amikor ARCore alkalmazást hoz létre a Sceneform SDK segítségével. De be kell építenie a Sceneform SDK-t a projektjébe.

Hozzon létre egy új Android Studio projektet, és válasszon ki egy üres tevékenységet.

Adja hozzá a következő függőséget a projekt szintű build.gradle fájlhoz:

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

Adja hozzá a következőket az alkalmazásszintű build.gradle fájljához:

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

Most szinkronizálja a projektet a Gradle fájlokkal, és várja meg a build befejezését. Ez telepíti a Sceneform SDK-t a projektbe és a Sceneform plugint az AndroidStudio-ba . Ez segít megtekinteni a. sfb fájlokat. Ezek a fájlok a 3D-s modellek, amelyeket a fényképezőgépe renderel. Segít a 3D-s elemek importálásában, megtekintésében és felépítésében is .

Az első ARCore alkalmazás elkészítése

Most, hogy az Android Studio telepítése befejeződött és a Sceneform SDK telepítve van, elkezdhetjük az első ARCore alkalmazásunk megírását.

Először hozzá kell adnunk a Sceneform töredéket az elrendezési fájlunkhoz. Ez lesz az a jelenet, ahová az összes 3D-s modellünket elhelyezzük. Gondoskodik a kamera inicializálásáról és az engedélyek kezeléséről.

Lépjen a fő elrendezési fájlra. Az én esetemben ez a activity_main.xml, és adjuk hozzá a Sceneform töredéket:

A szélességet és magasságot úgy állítottam be, hogy megfeleljen a szülőnek, mivel ez az egész tevékenységemet lefedi. Kiválaszthatja a méreteket az Ön igényei szerint.

Kompatibilitás ellenőrzése

Mindössze annyit kell tennie az elrendezési fájlban. Most menj át a java fájlra, az én esetemben, ami a MainActivity.java. Adja hozzá az alábbi módszert az osztályához:

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;}

Ez a módszer ellenőrzi, hogy az eszköz képes-e támogatni a Sceneform SDK-t vagy sem. Az SDK-hoz Android 27. vagy újabb szintű API, valamint OpenGL ES 3.0 vagy újabb verzió szükséges . Ha egy eszköz nem támogatja ezt a kettőt, a Jelenet nem jelenik meg, és az alkalmazás üres képernyőt jelenít meg.

Bár továbbra is folytathatja alkalmazásának minden egyéb olyan funkciójának a nyújtását, amelyekhez nincs szükség a Sceneform SDK-ra.

Miután befejeződött az eszköz kompatibilitásának ellenőrzése, elkészítjük a 3D-s modellünket és csatoljuk a helyszínhez.

Az eszközök hozzáadása

Hozzá kell adnia a képernyőn megjelenített 3D modelleket. Most már saját maga is elkészítheti ezeket a modelleket, ha ismeri a 3D modell készítését. Vagy meglátogathatja Poly-t.

Itt hatalmas 3D-s eszközök tárháza található, amelyek közül választhat. Ingyenesen letölthetők. Csak nevezze az alkotót, és máris mehet.

Az Android Studióban bontsa ki a bal oldali projekt ablaktáblán elérhető alkalmazásmappát. Észre fog venni egy sampledata mappát. Ez a mappa fogja tárolni az összes 3D modelleszközt. Hozzon létre egy mappát a modelljének a minta adatmappában.

Amikor letölti a zip fájlt a poly-ból, valószínűleg 3 fájlt talál.

  1. .mtl fájl
  2. .obj fájl
  3. .png fájl

A legfontosabb ezek közül a .obj fájl. Ez a tényleges modelled. Helyezze mind a 3 fájlt a mintavételi adatokba -> „a modell hajtása ”.

Most kattintson a jobb gombbal az .obj fájlra . Az első lehetőség a Jelenetforma importálása lenne. Kattintson rá, ne módosítsa az alapértelmezett beállításokat, csak kattintson a Befejezés gombra a következő ablakban. A fokozata szinkronizálja az elemet az eszközök mappába. Amint befejeződik a fokozatgyártás, jó vagy.

Befejezte a Sceneform által a projektben használt 3D-s elemek importálását. Ezután építsük fel az eszközt a kódunkból, és foglaljuk bele a jelenetbe.

A modell felépítése

Adja hozzá a következő kódot a MainActivity.java fájljához (vagy bármi, ami az Ön esetében van). Ne aggódjon, soronként elmagyarázom az összes kódot:

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; });
}

Először is megkeressük az elFragmentet , amelyet az elrendezési fájlba illesztettünk. Ez a töredék felelős a jelenet befogadásáért. Úgy gondolhat rá, mint jelenetünk konténerére.

Ezután a ModelRenderable osztályt használjuk a modell felépítéséhez. A setSource módszer segítségével betöltjük a modellünket a. sfb fájl. Ez a fájl az eszközök importálásakor jött létre. thenAccept metódus megkapja a modellt, miután felépült. A betöltött modellt a lampPostRenderable értékre állítottuk.

A hibakezeléshez a .kivételes módszerünk van. Akkor hívják meg, ha kivételt dobnak.

Mindez aszinkron módon történik , ezért nem kell aggódnia a többszálas menetek miatt, vagy foglalkoznia az XD kezelőkkel

Ha a modell be van töltve és a lampPostRenderable változóban van tárolva, most hozzáadjuk a jelenetünkhöz.

A modell hozzáadása a jelenethez

Az arFragment tárolja jelenetünket, és megkapja a csap eseményeket. Tehát be kell állítanunk az onTap figyelőt a töredékünkhöz, hogy regisztrálja a csapot, és ennek megfelelően helyezzen el egy objektumot. Adja hozzá a következő kódot az onCreate metódushoz:

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(); });

Az onTapArPlaneListener- t AR töredékünkhöz állítottuk . A következő a Java 8 szintaxisa , ha nem ismeri azt, javasoljuk, hogy nézze meg ezt az útmutatót .

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.

Like what you read? Don’t forget to share this post on Facebook, Whatsapp and LinkedIn.

You can follow me on LinkedIn, Quora, Twitter and Instagram where I answer questions related to Mobile Development, especially Android and Flutter.