ARKit, SceneKit i kako kontrolirati svijet

U prvom dijelu ove serije prošli smo kroz radni tijek u kojem smo obradili 3D model, kreirali AR projekt u Xcode-u, pokrenuli AR sesiju i svoj model postavili u našu pojačanu scenu.

U ovom postu započet ćemo stavljati naš model u akciju, koristeći različite metode SceneKit, i započet ćemo interakciju s objektima u našem svijetu.

Projekt za ovaj post možete pronaći na https://github.com/AbovegroundDan/ARTutorial_Part2

Akcije SceneKit

SceneKit pruža skup radnji koje se mogu primijeniti na čvor. Ove se radnje mogu koristiti za animiranje pokreta, rotacije, skaliranja i drugih svojstava čvorova. Oni se mogu grupirati da istodobno izvode, redoslijede jedno za drugim te ponoviti ili preokrenuti. Potpuni popis možete pronaći na https://developer.apple.com/documentation/scenekit/scnaction

Nastavit ćemo mijenjati trenutni projekt i započeti dodavati neke akcije našem objektu. Započnimo dodavanjem rotacije u našu sferu.

Nakon metode addSphere u našem HoverSceneu dodajte sljedeću metodu:

U ovom kodu stvaramo radnju koja opisuje rotaciju za 180 stupnjeva oko osi Y. Zakretanje bi trebalo trajati 5 sekundi. Zatim poduzimamo ovu radnju i dodamo je čvoru u koji je prešao. Sada ovu metodu trebamo nazvati iz naše addSphere metode. Na kraju metode, nakon retka u koji smo dodali podređeni čvor, dodajte sljedeći redak:

Ako pokrenemo ovaj kod, vidjet ćemo da se naša sfera okreće u drugom smjeru i zaustaviti. Ono što sada želimo je da se ova animacija ponovi, tako da se nastavlja rotirati.

Promijenimo naš addAnimation code na sljedeće:

Ovdje smo dodali ponavljanje zauvijek, koje u rotaciji uzima kao ulaz. Zatim umjesto akcije rotacije, u naš čvor dodamo akciju repeForever. Pokrenite kod ponovo i vidjet ćemo da se naša sfera sada kontinuirano okreće.

Dodajmo malo pizzazz-a u sferu. Neka i ona malo lebdi gore-dolje. Dodaćemo akciju pokazivača kretanja, radnju pokazivača prema dolje, slijediti te dvije radnje, a zatim ih grupirati s postojećom radnjom rotiranja. Ovo bi trebala izgledati metoda addAnimation:

Sada imamo rotirajuću, lebdeću sferu koju možemo smjestiti bilo gdje u našem svijetu.

HitTests i apstrakcije

Dodajmo na scenu interaktivnost. Postavimo cilj započeti scenu tako da korisnik postavi sfere u svijetu, a zatim dodirnite za njihovo aktiviranje. Budući da smo s našim kodom malo složeniji, vrijeme je da počnemo apstrahirati način na koji postupamo sa objektima naše scene. Stvorite novu grupu u našem projektu pod nazivom Objekti. U toj ćemo mapi stvoriti novu Swift datoteku pod nazivom SceneObject.swift.

Stvorit ćemo bazu klase, SceneObject, koja proizlazi iz SCNNode.

Želimo apstrahirati učitavanje objekta od ostatka koda, pa omogućuje izradu init () metode koja uzima naziv datoteke. U ovom inicijalizatoru pomaknut ćemo kôd koji imamo za učitavanje iz datoteke.

Sada možemo stvoriti klasu Sphere koja proizlazi iz SceneObject:

Sada imamo klasu objekta Sphere koja se može učitati. Budući da ćemo animirati sfere kad ih dodirnemo, uklonimo poziv AddAnimation iz metode addSphere u našem HoverSceneu. Također, budući da smo sada sav kôd za učitavanje premjestili u klasu Sphere, možemo samo inicijalizirati Sphere i dodati je izravno u korijenski čvor scene. Naša znatno pojednostavljena metoda sada izgleda ovako:

Puno čistije!

Sada ćemo pogledati kako možemo napraviti hit test. Već imamo prepoznavač geste za dodir u našem regulatoru prikaza, tako da se možemo priključiti, ali kako ćemo znati utječu li naši slavini u Sferu, drugi objekt ili uopće ništa?

Srećom, naš ARSCNView nam može pomoći u tome. Ima sljedeću metodu:

Možemo mu dodati mjesto u prikazu, a on će nam vratiti niz čvorova koji se nalaze ispod te točke, bez obzira koja je z-vrijednost ili dubina.

Budući da želimo zgrabiti samo Sphere objekte, omogućujemo stvaranje brzog filtra koji provjerava je li svaki čvor vraćen u hitTestu sferu. Da bismo to postigli moramo zgrabiti najviši nadređeni čvor za svaki čvor koji želimo provjeriti. Vratimo se našoj datoteci "Node + Extensions.swift" i dodajmo sljedeću metodu:

Budući da su svi predmeti u našoj sceni korijenski čvorovi scene, želimo se zaustaviti kad dođemo do tog čvora i ne provjeravamo više. Budući da je njegova rekurzivna metoda, zaustavljamo se i vraćamo se kad otkrijemo da je korijenski čvor roditelj našeg čvora.

Vratimo se našem ViewController i izmijenimo delegata prepoznavača geste dodira. Želimo nastaviti dodavati nove sfere ako dodirnemo prazan prostor, ali ako dodirnemo postojeću sferu, želimo pokrenuti njezinu animaciju.

Kad nas dotakne, želimo vidjeti točku našeg pogleda na sceni, proslijediti je metodi HitTest prizora i vidjeti što ćemo se vratiti. Budući da se želimo baviti samo jednim objektom odjednom, hvatamo prvi (ako ima učitavanja), a zatim pomoću našeg gornjeg () proširenja iskoristimo najviši roditelj i provjerimo je li njegova sfera. Ako jest, onda tome dodamo našu animaciju. Ako nismo postigli nijedan pogodak svog testa, onda to radimo kao i prije, dodajući novu Sferu ispred kamere.

Samo napred i ponovno pokrenite aplikaciju. Možemo dodirnuti da dodamo sferu, a zatim bilo koju sferu da bismo je pokrenuli. Međutim, imamo bugu koju smo uveli. Možemo nastaviti kucati po sferi i animacije će stalno biti dodavane objektu. Možete ga testirati i vidjeti kako se sfera brže okreće i kreće gore i dolje svaki put kada je dodirnete.

Budući da je animacija specifična za sferu, premjestimo kod AddAnimation u sferu i preimenovamo je u samo animiranje (). Umjesto node.addAnimation, možemo jednostavno nazvati addAnimation. Također ćemo dodati zastavu u klasu Sphere, koju ćemo provjeriti prije dodavanja animacije i postaviti je na istinito kad prvi put bude dodana:

Sve što preostaje je promijeniti kod u povratnom pozivu kretnje da biste pokrenuli ovaj novi poziv na samoj sferi.

Svi smo sada spremni za ovaj dio. Imamo sferu koju možemo smjestiti u svijet, dodali smo interakciju kako bismo započeli animaciju i malo očistili kôd.

Dodatni kredit

Način na koji postavljamo sferu u svijetu prilično je nagli. Dotaknemo se i iznenada je. Dodajmo malo pizzazz-a ovoj funkciji i animiramo sferu kada je postavimo.

U našoj metodi addSphere u HoverSceneu dodajmo učinak razmjera. Kada dodamo sferu, animirat ćemo njenu ljestvicu i umjesto korištenja standardne linearne razmjere postavićemo efekt odskoka ili pop-up.

Promijenimo našu addSphere metodu u sljedeće i dodajmo funkciju easyOutElastic timing, koja će nam pružiti taj udarac:

Sada kada taknemo da postavimo sferu, dobivamo prilično cool animirani efekt.

Dodatni kredit, dio deux

Mnogo smo stvari radili sa SceneKitom, ali samo smo iskusili površinu nekih stvari koje ARKit može učiniti. Kao brzi teaser prije nego što dodjemo do više ARKit funkcionalnosti, dodajmo malo zabave na scenu stvarajući kuglu da "pogleda" kameru. Već imamo udice u metodi updateAtTime izvođača, a tamo imamo i referencu na kameru. Započnimo dodavanjem metode klasi Sphere, da bismo je pogledali u određenom smjeru. "Oko" sfere je već okrenuto negativnom Z, što je smjer predmeta prema naprijed. Ono što ćemo učiniti je stvoriti metodu koja uzima vektor koji označava točku u prostoru s kojim će se suočiti naše „oko“.

U ovom kodu gledamo udaljenost između sfere i ciljanog položaja (kamere). Ako je manji od određenog iznosa, animirat ćemo oko da se suoči s metom. Ako je oko bilo okrenuto prema kameri i korisnik se odmiče dalje od ove postavljene udaljenosti, tada ćemo ući u našu "patrolu" animaciju. Jedna stvar koju treba napomenuti kod ovog koda je da budući da ne postoji zgodna SCNAkcija za primjenu animacije "LookAt", naš izgled (na :) poziv smo zaključili u SCNTransaction, koji nam omogućava animiranje pokreta. Namjenski motori za 3D igre poput Unity ili Unreal imaju praktične funkcije za te stvari, ali SceneKit još nije na toj razini.

Možda ćete primijetiti da se na ciljanom poslušniku SCNVector3 koji se proslijedio nalazi na daljinu, ali ta metoda ne postoji za SCNVector3. Ono što ćemo učiniti je dodati novo proširenje za ovaj daljinski poziv.

Stavio sam taj kôd u novu UtilityExtensions.swift datoteku, ali slobodno je stavite gdje god želite.

Zatim ćemo morati promijeniti našu metodu updateAtTime kako bismo uklonili provjeru zastava i pozvali metodu u našem kadru kontrolera za svaki kadar. Naš kontrolor scene bit će zadužen za slanje poruke svim objektima sfere u našoj sceni.

U našem HoverSceneu kreirat ćemo metodu makeUpdateCameraPos koja će filtrirati samo u Sferne objekte i pozvati metodu patrole.

Promijenimo i način postavljanja kako bismo kuglice malo dalje odstranili. Napravimo metodu didTapScreen da naša sfera bude smještena 5 metara umjesto 1:

U našoj klasi Sphere napravimo prag za aktiviranje pogleda na 4,85 metara:

Promijenimo i našu Sphere animaciju tako da se malo osvrće oko sebe, a ne lebdi.

Float.random je još jedno proširenje koje je jednostavno:

Pozovite to i postavite neke sfere. Sada bi trebali animirati sami, bez potrebe da ih taknete. Priđite bliže svakom i trebali biste ih vidjeti kako gledaju prema vama. Hodajte dalje i trebali bi se vratiti patroliranju svojim područjem. Sada imamo prizor ravno iz distopijske budućnosti, lebdeći pogled promatrajući svaki naš pokret.

Pratite više sadržaja ARKit!