Taula de continguts

Realitat Augmentada amb Unity

La Realitat Augmentada, en el contexte d'aplicacions mòbils, són aquelles aplicacions que afegeixen informació digital a la realitat física que captura la càmera del nostre dispositiu mòbil.

Per altra banda, Unity és un software popular i gratuït (amb certes condicions) pel desenvolupament de jocs 2D i 3D, i ens propociorna una plataforma d'edició que ens ajudarà, i molt, a l'hora del desenvolupament d'aplicacions d'AR.

, , , , , , , ,

Objectiu

Al final d'aquest article haurem creat una app de Realitat Augmentada que obrirà la càmera per defecte del nostre dispositiu i ens dibuixarà sobre les imatges captades pel mòbil el model 3D que li diguem. A més a més podrem interactuar amb aquest model 3D.

Cal tenir instal·lats Unity i un editor per programar (aquí farem servir Visual Studio).

És molt recomanable que feu una ullada a aquest article, si no l'heu fet ja, abans de continuar.

Link a l'article d'iniciació a Unity

Setup d'Unity per la Realitat Augmentada

Obrim Unity Hub i cliquem a «New project». Als templates cerquem i seleccionem el template d'AR Core. La primera vegada que fem servir un template segurament us haureu de descarregar alguns paquets abans de poder crear el projecte.

Tingueu present quina versió de l'editor d'Unity fareu servir pel desenvolupament de la aplicació. És recomanable fer servir versions LTS que ens assegura que són versions a les que l'equip d'Unity donarà suport durant molt de temps.

Jo faré servir la versió 2021.3.5f1 LTS

A continuació donem un nom al nostre projecte, per exemple «DemoAR», indiquem la localització on es desarà el projecte al nostre PC i cliquem a «Create project»

unity_ar_image01.jpg

Si de moment hem fet tot correcte, se'ns obrirà un projecte d'Unity amb una escena on tindrem els elements bàsics per crear una realitat augmentada ja a l'escena (finestra de Hierarchy).

Ara modificarem i ens assegurarem que el projecte tingui la configuració correcta.

Començarem configurant el nostre projecte per assegurar-nos que la plataforma de desenvolupament sigui Android. Per això el que farem serà:

File -> Build Settings -> Android -> Switch Platform

Si l'opció d'Android ens surt inactiva vol dir que quan vam fer la instal·lació del Unity al nostre PC no vam afegir els mòduls necessaris per poder desenvolupar a Android. Si és el cas, tanqueu l'Unity i torneu a l'aplicació d'Unity Hub. Aneu a l'opció d'«Installs», a l'esquerra de la finestra i allà veureu totes les versions d'Unity que teniu instal·lades. Cliqueu a sobre de la rodeta de settings de la versió que ens interessa i a continuació «Add Modules» i allà seleccioneu la plataforma d'Android i els components que l'acompanyen si escau. Espereu a la completa instal·lació abans de continuar

unity_ar_image02.jpg

Ara, amb la plataforma Android seleccionada, passarem al gestor de paquets d'Unity per assegurar-nos que tot s'ha instal·lat i actualitzarem un paquet que no acostuma a venir actualitzat.

Anem a la finestra de gestor de paquets fent:

Window -> Package Manager

Seleccionem «Packages: In Project» a la barra superior esquerra de la finestra i ens assegurem que tenim el Package AR instal·lat.

També actualitzarem el Package «XR Plugin Management» per assegurar-nos que estem a la versió 4.2.1. Si no estem en aquesta versió, seleccioneu aquest paquet i cliqueu al botó d'Update a la part inferior dreta.

unity_ar_image03.jpg

Si esteu interessats en aquests Kit de desenvolupament d'AR podeu fer una ullada a aquest link: AR Core

Ja estem a prop d'acabar aquest primer punt farragós. Només falten configurar les opcions de Player en el project settings. Per treure aquesta finestra farem:

File -> Build Settings -> Player Settings

Se'ns obrirà la finestra de Project Settings amb l'opció de Player seleccionat.

Es considera de bona praxis identificar el desenvolupador de l'aplicació tot i que no és obligatori. Això es fa a l'slot de Company Name. En el meu cas sempre m'identifico com a «Dedalo»

Més abaix, a «Other Settings» busquem «Minimum API Level» i al desplegable seleccionem l' Api Level 26, que serà el requeriment mínim de la versió d'Android que tindrà que tenir instal·lat l'usuari de la nostre aplicació per a que funcioni correctament la Realitat Augmentada.

unity_ar_image04.jpg

Ja tenim, per fi, configurat el nostre projecte d'Unity per fer l'aplicació de Realitat Augmentada.

Anem a modificar l'escena per crear la nostra AR

L'Aplicació

Farem una Realitat Augmentada on a l'enfocar la càmera del mòbil a una imatge se'ns dibuixarà enganxat a aquesta imatge elements digitals.

Crear un nou AR Session Origin

Partirem de l'escena per defecte que s'ha obert a l'inici tot i que la modificarem una mica.

Seleccionem i esborrem el gameObject anomenat AR Session Origin de la nostra finestra Hierarchy. Aquest gameObject porta uns settings per fer una realitat augmentada de detecció de plànols i no és el que farem servir nosaltres.

Amb el ratolí sobre la finestra d'Hierarchy cliquem botó dret, seleccionem XR i allà seleccionem AR Session Origin per crear un nou gameObject d'AR però en aquest cas vindrà quasi net, només amb el mínim necessari per poder fer un AR, una càmera virtual (que quadrarà amb la càmera física del dispositiu) amb un Script per controlar la càmera i poc més.

unity_ar_image05.jpg

Amb aquest gameObject seleccionat ens assegurem que la seva posició i rotació a la finestra Inspector és tot a zero.

Afegim components i la imatge pel tracking

Com hem dit abans, aquest AR Session Origin està pràcticament buit pel que l'haurem d'afegir el component pensat per fet track d'imatge en AR. Per això, i amb l'AR Session Origin que acabem de crear seleccionat, anirem a la finestra d'Inspector i clicarem a «Add Component», buscarem un component d'Script anomenat «AR TRacked Image Manager». i l'afegim al gameObject.

Aquest script s'ha d'omplir amb una llibreria d'imatges (les imatges que vulguem fer servir per fer el Track) i un prefab. Els prefabs són objectes que creem i fem servir en runtime (temps d'execució de l'app). Els prefabs es fan servir per instanciar enemics que van apareixent mentres avancem a un joc, o les bales de la nostra arma quan disparem, o les pròpies armes, o les monedes de recompensa, etc.

En aquest cas el nostre prefab serà l'objecte que s'instanciarà quan la nostra aplicació detecti la imatge i activi el track

Abans de crear la llibreria d'imatges afegirem la imatge sobre la qual farem el track. Per això cercarem i arrossegarem una imatge al nostre projecte d'unity.

Podeu fer servir qualsevol imatge, jo faré servir aquesta:

Per afegir-la podeu obrir l'explorador de windows, seleccionar la imatge i arrossegar-la a la finestra d'Assets del nostre Editor Unity o, una altra manera d'importar assets al nostre projecte és clicant el botó dret del ratolí sobre la finestra d'Assets i seleccionant «Import New Asset».

Si feu servir una altra imatge tingueu en compte que, per facilitar el track, les imatges han de ser clares, ben contrastades i que no tinguin simetries.

Ara ja podem crear la llibreria d'imatges. A la finestra d'assets, cliquem botò dret:

Create -> XR -> Reference Image Library. 

Amb la llibreria seleccionada anirem a la finestra d'Inspector i clicarem a «Add Image». Ara arrossegarem la imatge d'abans a l'slot de Texture 2D.

Es recomanable donar-li el tamany de la nostra imatge en metres per una correcta escala a l'hora de fer servir l'AR. A la nostra imatge li posarem x:0.149 y:0.129, i finalment cliquem l'opció «Keep Texture at Runtime»

Per saber el tamany de la imatge és tan fàcil com mesurar amb un regla la imatge impresa sobre la que volem fer l'AR. Les unitats que espera Unity és en metres.

Creem el Prefab

Ara crearem el nostre prefab que serà el que s'instanciarà al moment de detectar i fer track de la imatge.

Botó dret sobre la finestra Hierarchy,

3D Object -> Cylinder

Se'ns ha creat un cilindre a l'escena. Des de l'inspector el posem a la posició x:0 y:0 z:0 i l'escalem a x:0.1 y:0.1 z:0.1.

Li crearem un nou material. A la finestra d'Assets, botó dret

Create -> Material

A l'inspector modifiquem el color a un gris més o menys fosc i per aplicar el nou material al cilindre l'arrosseguem des de la finestra d'assets a sobre del nostre cilindre a l'escena.

Us animo a jugar amb les opcions del material per provar coses com ara la brillantor i efectes metàlics.

Ara, a la finestra d'Assets crearem una nova carpeta anomenada «Prefabs».

Botó dret del ratolí -> Create -> Folder

Finalment, per crear el prefab és tan senzill com agafar el nostre Cylinder de la finestra Hierarchy i arrossegar-lo fins a la carpeta que acabem de crear. El cylinder de la nostra escena (A Hierarchy) es posarà en color blau indicant-nos que és un prefab. De fet, l'esborrarem de l'escena ja que el crearem en temps d'execució, no cal que estigui a l'escena.

Aneu en compte i esborreu el cilindre de l'escena, no el de la carpeta prefab.

Afegim el Prefab i la llibreria d'imatges a l'AR Session Origin

Ara acabarem de configurar el GameObject «AR Session Origin» per poder donar-li tota la informació que necessita per poder fer el track sobre la imatge. Aquesta informació serà la llibreria d'imatges i l'objecte 3D que es pintarà al detectar la imatge de track.

Amb el «AR Session Origin» seleccionat arrosseguem la llibreria des d'Assets a l'Slot «Serialized Library». Per afegir el prefab no l'arrossegarem i aprendrem una altra manera. Clicarem a l'icone que hi ha a la dreta de l'slot de «Tracked Image Prefab» (el punt amb un circle al voltant) i a la finestra que s'obre seleccionarem el nostre cilindre.

El projecte hauria de tenir aquest aspecte:

unity_ar_image06.jpg

Ja tenim tot preparat per publicar i testejar la nostra primera aplicació d'AR.

Publiquem i instal·lem l'aplicació

Primer salvem l'escena per aplicar tots els canvis.

File -> Save

I a continuació el Build

File -> Build Settings -> Build 

Com a nom li podem posar «DemoAR» i continuem.

Per poder instal·lar aplicacions que no venen de Google Play o altres plataformes conegudes i que ens certifiquen que són segures hem de posar al nostre mòbil en mode de desenvolupador.

Per això seguiu aquest tutorial: Tutorial per posar el nostre Android a mode desenvolupador.

Ara, connectarem el nostre mòbil al PC amb un cable USB i copiarem l'arxiu DemoAR.apk al nostre mòbil. Una vegada al mòbil simplemente l'instal·lem, li diem que confiem en el desenvolupador, ja que són nosaltres mateixos, i ja la podem testejar.

Li donem permisos per fer servir la càmera i quan enfoquem a la nostra imatge de Track ens ha de sortir el nostre cilindre a sobre de la imatge.

Moveu el mòbil sense deixar d'enfocar la imatge per comprovar que el cilindre està ben enganxat al món físic.

Modifiquem l'Aplicació per a fer-ne un joc

Ja tenim la nostra primera aplicació feta però és una mica avorrida.

Farem unes modificacions i afegirem una mica de programació per fer una mica més entretinguda la nostra aplicació.

Afegir un nou GameObject

Començarem creant un nou GameObject a la nostra escena:

Botó dret del ratolí sobre //Hierarchy// -> Create Empty

Modifiquem a l'inspector la seva posició (x:0 ; y:0; z:0) i canviem el nom a un que ens ajudi a reconèixer la seva funció. Posar noms ens ajudarà quan tinguem escenes grans amb molts elements.

Per canviar el nom tant ho podem fer clicant botò dret sobre l'objecte a Hierarchy o a la finestra de Inspector

Jo li he posat «BeetleSpawner»

Ara afegim un component nou de tipus script.

Finestra Inpector -> Add Component -> New Script -> Posem nom, per exemple "Spawner" -> Create and Add

Obrirem aquest script al nostre editor d'script, en el meu cas Visual Studio. Per a fer-ho és tan fàcil com clicar dos cops sobre el nom de l'script a la finestra Inspector

Modificarem el nostre script per a quedi d'aquesta manera

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Spawner : MonoBehaviour
{
    public GameObject beetle;

    // Start is called before the first frame update
    void Start()
    {
        InvokeRepeating("SpawnObject", 0.5f, 2);
    }
   
    void SpawnObject()
    {
         Instantiate(beetle, Vector3.zero, Quaternion.Euler(new Vector3(90, Random.Range(0f, 360f), 0)));
    }
} 

Aquest script declara una variable pública de tipus GameObject i anomenada beetle.

Després, a la funció Start() que és la funció que s'executa quan s'inicia l'script, hem posat el mètode InvokeRepeating que cridarà la funció anomenada «SpawnObject» quan passin 0.5 segons i després tornarà a cridar la funció de manera indefinida cada 2 segons.

Per últim, a la funció «SpawnObject» cridem el mètode Instantiate on en crea una instancia de l'objecte «beetle», amb una posició i una rotació a la nostra escena. Hem donat una rotació de 90 graus en l'eix de les x perquè volem que el cilindre s'instanciï tombat i la rotació a l'eix de les Y serà random.

Salvem l'script i tornem al Unity.

Veurem que ara, el nostre Script, te un nou slot anomenat Beetle i que és buit. Arrossegarem aqui el Cylinder que vam crear en la secció anterior i que tenim a la carpeta «Prefab»

Actualitzar el Prefab

Modificarem el prefab perquè es mogui per l'escenari, faci una acció quan detecti un touch a sobre i, per últim, s'esborri passat uns segons.

Anem a la carpeta «Prefab» i fem doble click sobre el nostre Cylinder

L'editor d'Unity se'ns modificará una mica per indicar-nos que ja no estem editant l'escena sinó que estem editant el prefab.

Si volem sortir d'edició del prefab i tornar a la nostra escena clicarem al signe «<» de la finestra Hierarchy

unity_ar_image07.jpg

Ara, afegirem un script al nostre prefab, jo l'he anomenat «BeetleBehaviour»

Editem aquest script amb el codi següent:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BeetleBehaviour : MonoBehaviour
{

    public float movementSpeed = 5.0f;

    // Start is called before the first frame update
    void Start()
    {
        Invoke("SelfDestroy", 10);
    }

    // Update is called once per frame
    void Update()
    {
        transform.position += transform.up * Time.deltaTime * movementSpeed;
    }

    void OnMouseDown()
    {
        // Aquest Objecte ha detectat un click over
        SelfDestroy();
    }


    private void SelfDestroy()
    {
        Destroy(gameObject);
    }
}

Repasem l'Script:

En primer lloc declarem una variable pública, per poder modificar el seu valor directament des de l'editor d'Unity, de tipus float. L'anomenem movementSpeed i li donem un valor de 5

Després a la funció Start(), que ja coneixem, cridem un métode nou però que molt semblant al que ja vam fer servir anteriorment. Aquest métode cridarà a la funció «SelfDestroy» passats 10 segons. Fem això perquè la nostra aplicació estarà instanciant objectes de manera infinita i per evitar problemes de memòria per instanciar centenars o milers d'objectes, fem aquest métode que cridarà a la funció de autodestrucció del nostre gameObject.

Tenim una nova funció, Update(). Aquesta funció es crida continuament abans de renderitzar el frame el nostre dispositiu.

Aquí posarem la programació que farà que el nostre prefab es posicioni a l'escena. Com es crida continuament aquesta posició anirà canviant continuament.

Una nova funció, OnMouseDown(). És la funció que es crida quan es clica a sobre de l'objecte que porta aquest script. Per al seu correcte funcionament ha d'anar acompanyat, l'script, d'un component Collider en el mateix GameObject. En el nostre cas porta un Capsule Collider que detecta les colisions sobre aquest objecte.

Dintre de la funció el que fem és cridar a la funció «SelfDestroy» ja que el que volem és destruir l'objecte si el cliquem a sobre.

Per últim la funció SelfDestroy() que crida al métode Destroy per esborrar l'objecte de l'escena.

Salvem l'script i tornem al Unity.

Provem que tot funciona

Tenim tot preparat per poder crear el nostre primer joc a Unity en Realitat Augmentada, però abans, farem un Play a l'editor per assegurar-nos que tot funciona.

Per això clicarem al botó de Play que hi ha a la part superior i al mig del nostre editor d'Unity.

Es molt possible que no es vegi res. Això és perquè la nostra càmera està posicionada al 0,0,0 com el nostra GameObject que instància cilindres. Per poder veure una mica millor mourem una mica el GameObject de «AR Session Origin»

Seleccionem aquest GameObject i a l'inspector i li donarem aquests valors:

Position: x:0; y:3; z:-6 Rotation: x:20; y:0; z:0

Hauríem de veure com es van instanciant cilindres cada 2 segons i en direccions randoms.

A més a més, si cliquem amb el ratolí a sobre el cilindre s'hauria d'esborrar.

Per acabar el testeig simplement tornem a clicar al botó de Play.

No ens hem de preocupar de tornar a posar el valors originals al nostre GameObject d'AR Session Origin perquè les modificacions que es fan en Play només s'apliquen en runtime, no es desan.

Creem un Prefab que instància Prefabs

Ara tenim un GameObject que instància prefabs però el que volem és que aquests prefabs s'instanciïn sobre la nostra imatge d'AR en temps d'execució.

Per això, el que farem, és convertir el nostre BeetleSpawner en un nou prefab i ja sabem crear Prefabs. Arrosseguem el GameObject des de la Hierarchy a la nostra carpeta de Prefab. Ara ja tenim un prefab que instància prefabs.

Ara, amb el nostre prefab desat a la carpeta podem esborrar el BeetleSpawner de la nostra escena.

Modifiquem l'AR Session Origin

L'últim pas que ens queda a fer és modificar el AR Session Origin perquè en comptes d'instanciar el cilindre en el moment de fer track a la imatge, instaciï el nostre spawner d'escarabat.

Per això seleccionem AR Session Origin del Hierarchy, busquem el nou prefab «BeetleSpawner» i l'arrosseguem sobre l'slot «Tracked Image Prefab» a la finestra Inspector

Publiquem de nou l'aplicació

Només ens queda fer un nou build, com ja sabem d'abans, i actualitzar-lo al nostre dispositiu.

Primer salvem l'escena:

File -> Save

Ara creem el build:

File -> Build Settings -> Build

Sobrescribim l'apk anterior i només queda passar-lo al nostre dispositiu a travès del cable USB i tornar a instal·lar-lo.

Innovacions a l'aplicació

Us proposo que modifiqueu el codi per fer coses noves com ara:

* Donar velocitat random als nostres escarabats (cilindres). Penseu que a la funció Start() podem donar valors a les variables del nostre Script.

* Quan cliquem a sobre dels escarabats en comptes d'esborrar-los modifiquem la direcció del moviment. Feu servir el codi:

transform.Rotate(0, 0, Random.Range(0f, 360f));

* Si teniu coneixements de 3D podeu provar d'importar al projecte un model vostre i canviar el cilindre pel vostre.