V našem prejšnja objava na spletnem orodju GWT smo razpravljali o močeh in značilnostih GWT , ki nam v spomin na splošno idejo omogoča, da izvorno kodo Java transpiliramo v JavaScript in brezhibno mešamo Java in JavaScript knjižnice. Opazili smo, da je JavaScript, ki ga ustvarja GWT, dramatično optimiziran.
V današnji objavi bi radi šli malo globlje in videli, kako deluje GWT Toolkit. Predstavili bomo, kako lahko GWT izkoristimo za izdelavo posebne aplikacije: razširjena resničnost (AR) spletna aplikacija, ki se v brskalniku izvaja v realnem času, v celoti v JavaScript.
V tem članku se bomo osredotočili na to, kako nam GWT omogoča enostavno interakcijo s številnimi API-ji JavaScript, kot sta WebRTC in WebGL, in nam omogoča, da izkoristimo veliko knjižnico Java, NyARToolkit, ki nikoli ni bila uporabljena v brskalniku. Pokazali bomo, kako je GWT dovolil moji ekipi in jaz na Jooink da sestavijo vse te koščke in ustvarijo naš projekt za hišne ljubljenčke, Picshare , aplikacija AR na osnovi markerja, ki jo lahko preizkusite v brskalniku takoj zdaj .
Ta objava ne bo izčrpna predstavitev, kako zgraditi aplikacijo, temveč bo prikazala uporabo GWT za lažje premagovanje na videz ogromnih izzivov.
Picshare uporablja razširjeno resničnost na osnovi markerja. Ta vrsta aplikacije AR išče prizorišče za marker : poseben, lahko prepoznaven geometrijski vzorec, Všečkaj to . Oznaka ponuja informacije o položaju in usmerjenosti označenega predmeta, kar omogoča programski opremi, da na realističen način projicira dodatne 3D pokrajine v sliko. Osnovni koraki v tem postopku so:
Uporaba API-jev JavaScript, kot sta WebGL in WebRTC, omogoča nepričakovane in nenavadne interakcije med brskalnikom in uporabnikom.
Na primer, WebGL omogoča strojno pospešeno grafiko in s pomočjo vneseno polje specifikacija, omogoča mehanizmu JavaScript, da izvede drobljenje številk s skoraj domačo zmogljivostjo. Podobno lahko z WebRTC brskalnik dostopa do video (in drugih podatkovnih) tokov neposredno iz računalniške strojne opreme.
WebGL in WebRTC sta knjižnici JavaScript, ki ju je treba vgraditi v spletni brskalnik. Večina sodobnih brskalnikov HTML5 ima vsaj delno podporo za oba API-ja (kot vidite tukaj in tukaj ). Toda kako lahko izkoristimo ta orodja v GWT, ki je napisan v Javi? Kot razpravljali v prejšnjem prispevku , Plast interoperabilnosti GWT, JsInterop (uradno izdano v GWT 2.8) naredi to kos torte.
Uporaba JsInterop z GWT 2.8 je tako enostavna kot dodajanje -generateJsInteropExports
kot argument prevajalniku. Razpoložljivi pripisi so opredeljeni v paketu jsinterop.annotations
, ki je priložen gwt-user.jar
.
Kot primer z minimalnim delom kodiranja uporabimo getUserMedia
WebRTC v Chromu z GWT postane tako preprosto kot pisanje:
Navigator.webkitGetUserMedia( configs, stream -> video.setSrc( URL.createObjectURL(stream) ), e -> Window.alert('Error: ' + e) );
Kjer je razred Navigator
lahko opredelimo na naslednji način:
@JsType(namespace = JsPackage.GLOBAL, isNative = true, name='navigator') final static class Navigator { public static native void webkitGetUserMedia( Configs configs, SuccessCallback success, ErrorCallback error); }
Zanimiva je opredelitev vmesnikov SuccessCallback
in ErrorCallback
, oba izvedena z lambda izrazom zgoraj in definirana v Javi s pomočjo @JsFunction
opomba:
@JsFunction public interface SuccessCallback { public void onMediaSuccess(MediaStream stream); } @JsFunction public interface ErrorCallback { public void onError(DomException error); }
Na koncu še definicija razreda URL
je skoraj enak tistemu iz Navigator
in podobno Configs
razred lahko definiramo z:
@JsType(namespace = JsPackage.GLOBAL, isNative = true, name='Object') public static class Configs { @JsProperty public native void setVideo(boolean getVideo); }
Dejanska izvedba vseh teh funkcij poteka v brskalnikovem mehanizmu JavaScript.
Zgornjo kodo najdete na GitHub tukaj .
V tem primeru je zaradi poenostavitve opuščeno navigator.getUserMedia()
API se uporablja, ker je edini, ki deluje brez poliranja v trenutni stabilni izdaji Chroma. V produkcijski aplikaciji lahko uporabljamo adapter.js za dostop do toka skozi novejšo navigator.mediaDevices.getUserMedia()
API, enakomerno v vseh brskalnikih, vendar to presega sedanjo razpravo.
Uporaba WebGL-a od GWT-a se v primerjavi z uporabo WebRTC-ja ne razlikuje dosti, vendar je nekoliko bolj dolgočasna zaradi notranje zapletenosti standarda OpenGL.
Naš pristop zrcali pristop, ki smo ga uporabili v prejšnjem poglavju. Rezultat ovijanja je razviden iz izvedbe GWT WebGL, ki se uporablja v Picshare , ki ga lahko najdete tukaj in primer rezultatov GWT tukaj .
Če samo omogočimo WebGL, nam dejansko ne omogočamo 3D grafike. Kot piše Gregg Tavares :
Marsikdo ne ve, da je WebGL pravzaprav 2D API in ne 3D API.
3D aritmetiko mora izvesti neka druga koda in jo spremeniti v 2D sliko za WebGL. Obstaja nekaj dobrih knjižnic GWT za 3D grafiko WebGL. Moja najljubša je Parallax , vendar za prvo različico Picshare sledili smo bolj 'naredi si sam' pot in napisali majhno knjižnico za upodabljanje preprostih 3D mrež. Knjižnica nam omogoča, da določimo a perspektivna kamera in upravljanje prizora predmetov. Vas prosimo, da preverite, tukaj .
NyARToolkit je vrata s čisto Java ARToolKit , knjižnica programske opreme za izdelavo aplikacij razširjene resničnosti. Pristanišče so napisali japonski razvijalci na Nyatla . Čeprav sta se prvotna ARToolKit in različica Nyatla nekoliko razlikovala od prvotnih vrat, se NyARToolkit še vedno aktivno vzdržuje in izboljšuje.
AR na osnovi markerjev je specializirano področje in zahteva usposobljenost za računalniški vid, digitalno obdelavo slik in matematiko, kot je razvidno tukaj:
Reproducirano iz Dokumentacija ARToolKit .
Reproducirano iz Dokumentacija ARToolKit .
Vsi algoritmi, ki jih uporablja komplet orodij, so dokumentirani in dobro razumljeni, vendar je njihovo ponovno pisanje iz nič dolgotrajen in nagnjen k napakam, zato je bolje uporabiti obstoječ, preizkušen nabor orodij, kot je ARToolKit. Na žalost pri ciljanju na splet take stvari ni na voljo. Najmočnejši, napredni kompleti orodij nimajo izvedbe v JavaScript, jeziku, ki se uporablja predvsem za manipulacijo z dokumenti in podatki HTML. Tu GWT dokazuje svojo neprecenljivo moč in nam omogoča, da NyARToolkit preprosto prenesemo v JavaScript in ga uporabimo v spletni aplikaciji z zelo malo težav.
Ker je projekt GWT v bistvu projekt Java, je uporaba NyARToolkita le stvar uvoza izvornih datotek v izvorno pot. Upoštevajte pa, da ker je prevajanje kode GWT v JavaScript izvedeno na ravni izvorne kode, potrebujete vire NyARToolkit in ne samo JAR s sestavljenimi razredi.
Knjižnica, ki jo uporablja Picshare mogoče najti tukaj . Odvisno je samo od paketov, ki jih najdete v lib/src
in lib/src.markersystem
iz gradnje NyARToolkit arhivirano tukaj . Te pakete moramo kopirati in uvoziti v naš projekt GWT.
Te neodvisne pakete bi morali držati ločeno od lastne izvedbe, toda za nadaljevanje »GWT-izacije« NyARToolkita moramo zagotoviti konfiguracijsko datoteko XML, ki prevajalniku GWT sporoči, kje naj išče vire. V paketu jp.nyatla.nyartoolkit
dodamo datoteko NyARToolkit.gwt.xml
com.jooink.gwt.nyartoolkit
Zdaj v našem glavnem paketu, GWT_NyARToolKit.gwt.xml
, ustvarimo glavno konfiguracijsko datoteko, No source code is available for type java.io.InputStream; did you forget to inherit a required module?
, in prevajalniku naročimo, naj Nyatlin vir vključi v učilno pot tako, da podeduje iz svoje datoteke XML:
InputStream
Pravzaprav precej enostavno. V večini primerov bi bilo to vse, kar pa še ni potrebno, žal pa še nismo končali. Če poskusimo zbrati ali izvršiti skozi Način Super Dev na tej stopnji naletimo na napako, ki je presenetljivo navedla:
jre
Razlog za to je, da NyARToolkit (torej knjižnica Java, namenjena projektom Java) uporablja razrede JRE, ki jih GWT ne podpira Posnemali JRE . Mi o tem na kratko razpravljali v prejšnjem prispevku.
V tem primeru je težava v java.io.FileInputStream java.io.InputStream java.io.InputStreamReader java.io.StreamTokenizer java.lang.reflect.Array java.nio.ByteBuffer java.nio.ByteOrder
in s tem povezani razredi IO. Takrat nam večine teh razredov niti ni treba uporabiti, temveč moramo prevajalniku zagotoviti nekaj izvedbe. No, veliko časa bi lahko vložili v ročno odstranjevanje teh referenc iz vira NyARToolkit, toda to bi bilo noro. GWT nam daje boljšo rešitev: z oznako XML zagotovite lastne izvedbe nepodprtih razredov.
Kot je opisano v uradna dokumentacija :
Thetag naroči prevajalniku, da znova ukorenini izvorno pot. To je uporabno za primere, ko želite ponovno uporabiti obstoječi Java API za projekt GWT, vendar izvirni vir ni na voljo ali ga ni mogoče prevesti. Pogost razlog za to je posnemanje dela JRE, ki ga GWT ne izvaja.
Torej točno tisto, kar potrebujemo.
Ustvarimo lahko java.lang.reflect.Array
imenik v projektu GWT, kjer lahko postavimo svoje izvedbe za razrede, ki nam povzročajo težave:
FileInputStream
Vsi ti, razen package java.io; import java.io.InputStream; import com.google.gwt.user.client.Window; public class FileInputStream extends InputStream { public FileInputStream(String filename) { Window.alert('WARNING, FileInputStream created with filename: ' + filename ); } @Override public int read() { return 0; } }
, so res neuporabljeni, zato potrebujemo le neumne izvedbe. Na primer, naš Window.alert
se glasi:
java.lang.reflect.Array
The package java.lang.reflect; import jp.nyatla.nyartoolkit.core.labeling.rlelabeling.NyARRleLabelFragmentInfo; import jp.nyatla.nyartoolkit.markersystem.utils.SquareStack; import com.google.gwt.user.client.Window; public class Array { public static Object newInstance(Class c, int n) { if( NyARRleLabelFragmentInfo.class.equals(c)) return new NyARRleLabelFragmentInfo[n]; else if(SquareStack.Item.class.equals(c)) return new SquareStack.Item[n]; else Window.alert('Creating array of size ' + n + ' of ' + c.toString()); return null; } }
stavek v konstruktorju je koristen med razvojem. Čeprav moramo biti sposobni sestaviti razred, želimo zagotoviti, da ga nikoli ne bomo dejansko uporabljali, zato nas bo to opozorilo, če bomo razred nenamerno uporabili.
GWT_NyARToolkit.gwt.xml
dejansko uporablja koda, ki jo potrebujemo, zato je potrebna ne povsem neumna izvedba. To je naša koda:
Sensor.update()
Zdaj, če postavimo // given a drawing context with appropriate width and height // and a where the mediastream is drawn ... // for each video frame // draw the video frame on the canvas ctx.drawImage(video, 0, 0, w, h); // extract image data from the canvas ImageData capt = ctx.getImageData(0, 0, w, h); // convert the image data in a format acceptable by NyARToolkit ImageDataRaster input = new ImageDataRaster(capt); // push the image in to a NyARSensor sensor.update(input); // update the NyARMarkerSystem with the sensor nyar.update(sensor); // the NyARMarkerSystem contains information about the marker patterns and is able to detect them. // After the call to update, all the markers are detected and we can get information for each // marker that was found. if( nyar.isExistMarker( marker_id ) ) { NyARDoubleMatrix44 m = nyar.getMarkerMatrix(marker_id); // m is now the matrix representing the pose (position and orientation) of // the marker in the scene, so we can use it to superimpose an object of // our choice ... } ...
modul, lahko varno sestavimo in uporabimo NyARToolkit v našem projektu!
Zdaj smo v položaju, da imamo:
Zdaj je izziv združiti vse te tehnologije skupaj.
Ne bomo se poglobili v to, kako to doseči, vendar je osnovna ideja uporabiti video posnetke kot ozadje našega prizora (teksturo, ki je na zgornji sliki nanesena na 'daleč' ravnino) in zgraditi 3D podatkovno strukturo nam omogoča, da to sliko projiciramo v vesolje z uporabo rezultatov NyARToolkit.
Ta konstrukcija nam daje pravo strukturo za interakcijo s knjižnico NyARToolkit za prepoznavanje markerjev in risanje 3D modela na vrhu scene kamere.
Uporaba fotoaparata je nekoliko težavna. Video podatke je mogoče črpati samo v element. Element HTML5 je nepregleden in nam ne dovoljuje, da slikovne podatke izvlečemo neposredno, zato smo prisiljeni kopirati videoposnetek v vmesno sliko, izvleči slikovne podatke, jih pretvoriti v niz slikovnih pik in na koncu potisniti v NyARToolkit's
|_+_|metoda. Nato lahko NyARToolkit identificira marker na sliki in vrne matriko preoblikovanja, ki ustreza njenemu položaju v našem 3D prostoru.
S temi elementi lahko združimo sintetični predmet natančno nad oznako, v 3D, v video tok v živo! Zahvaljujoč visoki zmogljivosti GWT imamo na voljo veliko računskih virov, tako da lahko na platno uporabimo celo nekatere video učinke, na primer sepijo ali zamegljenost, preden jo uporabimo kot ozadje za sceno WebGL.
Naslednja skrajšana koda opisuje jedro procesa:
|_+_|
S to tehniko lahko ustvarimo rezultate, kot je ta:
To je postopek, ki smo ga nekoč ustvarjali Picshare , kamor ste vabljeni natisniti marker oz prikažite na svojem mobilnem telefonu in se v brskalniku igrajte z AR, ki temelji na oznakah. Uživajte!
Picshare je za nas pri Jooinku dolgoročni projekt za hišne ljubljenčke. Prva izvedba sega v preteklost nekaj let in že takrat je bila dovolj hitra, da je bila impresivna. Ob to povezavo lahko vidite enega naših prejšnjih poskusov, ki je bil sestavljen leta 2012 in se ga nikoli ni dotaknil. Upoštevajte, da je v vzorcu samo ena. Druga dva okna sta elementa, ki prikazujeta rezultate obdelave.
GWT je bil dovolj močan tudi leta 2012. Z izdajo GWT 2.8 smo z JsInteropom pridobili precej izboljšan sloj interoperabilnosti, ki še povečuje zmogljivost. Prav tako smo na praznovanje mnogih pridobili veliko boljše okolje za razvoj in odpravljanje napak, Super Dev Mode. Oh ja, in podpora za Java 8.
Veselimo se GWT 3.0!