GWT, Tarayıcınızda Artırılmış Gerçekliğin Kilidini Nasıl Açar?

Yayınlanan: 2022-03-11

GWT Web Araç Takımı hakkındaki önceki yazımızda, genel fikri hatırlamak için Java kaynak kodunu JavaScript'e aktarmamıza ve Java ve JavaScript kitaplıklarını sorunsuz bir şekilde karıştırmamıza izin veren GWT'nin güçlü yanlarını ve özelliklerini tartışmıştık. GWT tarafından oluşturulan JavaScript'in önemli ölçüde optimize edildiğini not ettik.

Bugünkü gönderide, biraz daha derine inmek ve GWT Toolkit'i çalışırken görmek istiyoruz. Özel bir uygulama oluşturmak için GWT'den nasıl yararlanabileceğimizi göstereceğiz: tarayıcıda gerçek zamanlı olarak, tamamen JavaScript'te çalışan bir artırılmış gerçeklik (AR) web uygulaması.

Tarayıcıda artırılmış gerçeklik? Düşündüğünden daha kolay.

Bu makalede, GWT'nin bize WebRTC ve WebGL gibi birçok JavaScript API'si ile kolayca etkileşim kurma yeteneğini nasıl sağladığına ve tarayıcıda asla kullanılması amaçlanmayan büyük bir Java kitaplığı olan NyARToolkit'i kullanmamıza nasıl izin verdiğine odaklanacağız. GWT'nin Jooink'teki ekibim ve benim, şu anda tarayıcınızda deneyebileceğiniz işaretçi tabanlı bir AR uygulaması olan evcil hayvan projemiz Picshare'yi oluşturmak için tüm bu parçaları bir araya getirmemize nasıl izin verdiğini göstereceğiz.

Bu gönderi, uygulamanın nasıl oluşturulacağına dair kapsamlı bir kılavuz olmayacak, bunun yerine, görünüşte ezici zorlukların kolaylıkla üstesinden gelmek için GWT'nin kullanımını gösterecek.

Projeye Genel Bakış: Gerçeklikten Artırılmış Gerçekliğe

WebRTC, WebGL ve ARToolKit ile GWT ile tarayıcıda işaretçi tabanlı artırılmış gerçeklik için işlem hattı.

Picshare , işaretçi tabanlı artırılmış gerçeklik kullanır. Bu tür AR uygulaması, sahnede bir işaretçi arar: bunun gibi belirli, kolayca tanınan bir geometrik desen. İşaretleyici, işaretlenen nesnenin konumu ve yönü hakkında bilgi sağlayarak, yazılımın görüntüye gerçekçi bir şekilde ek 3B manzara yansıtmasını sağlar. Bu süreçteki temel adımlar şunlardır:

  • Kameraya Erişin: Yerel masaüstü uygulamalarıyla uğraşırken, işletim sistemi, cihazın donanımının çoğuna G/Ç erişimi sağlar. Web uygulamalarıyla uğraştığımızda durum aynı değil. Tarayıcılar, internetten indirilen JavaScript kodu için bir tür "korumalı alan" olarak tasarlandı ve başlangıçta web sitelerinin çoğu cihaz donanımıyla etkileşime girmesine izin vermek için tasarlanmamıştı. WebRTC, HTML5'in medya yakalama özelliklerini kullanarak bu engeli aşar ve tarayıcının diğer şeylerin yanı sıra cihaz kamerasına ve akışına erişmesini sağlar.
  • Video Akışını Analiz Edin: Video akışımız var...şimdi ne olacak? İşaretçileri tespit etmek için her kareyi analiz etmemiz ve yeniden oluşturulmuş 3B dünyadaki işaretçinin konumunu hesaplamamız gerekiyor. Bu karmaşık görev, NyARToolkit'in işidir.
  • Videoyu Artırın: Son olarak, orijinal videoyu eklenen sentetik 3B nesnelerle görüntülemek istiyoruz. Web sayfasına son, artırılmış sahneyi çizmek için WebGL kullanıyoruz.

GWT ile HTML5'in API'lerinden Yararlanma

WebGL ve WebRTC gibi JavaScript API'lerinin kullanılması, tarayıcı ve kullanıcı arasında beklenmedik ve olağandışı etkileşimlere olanak tanır.

Örneğin, WebGL donanım hızlandırmalı grafiklere izin verir ve yazılan dizi özelliğinin yardımıyla JavaScript motorunun neredeyse yerel performansla sayı kırma işlemini gerçekleştirmesini sağlar. Benzer şekilde, WebRTC ile tarayıcı, video (ve diğer verilere) akışlarına doğrudan bilgisayar donanımından erişebilir.

WebGL ve WebRTC, web tarayıcısında yerleşik olması gereken JavaScript kitaplıklarıdır. Çoğu modern HTML5 tarayıcısı, her iki API için de en azından kısmi desteğe sahiptir (burada ve burada görebileceğiniz gibi). Ancak bu araçları Java ile yazılmış GWT'de nasıl kullanabiliriz? Önceki gönderide tartışıldığı gibi, GWT'nin birlikte çalışabilirlik katmanı JsInterop (resmi olarak GWT 2.8'de yayınlandı) bunu çocuk oyuncağı yapıyor.

JsInterop'u GWT 2.8 ile kullanmak, derleyiciye argüman olarak -generateJsInteropExports eklemek kadar kolaydır. Kullanılabilir ek açıklamalar, gwt-user.jar içinde paketlenmiş jsinterop.annotations paketinde tanımlanır.

WebRTC

Örnek olarak, minimum kodlama çalışmasıyla, getUserMedia Chrome'da GWT ile kullanmak yazmak kadar basit hale gelir:

 Navigator.webkitGetUserMedia( configs, stream -> video.setSrc( URL.createObjectURL(stream) ), e -> Window.alert("Error: " + e) );

Navigator sınıfının aşağıdaki gibi tanımlanabileceği yerler:

 @JsType(namespace = JsPackage.GLOBAL, isNative = true, name="navigator") final static class Navigator { public static native void webkitGetUserMedia( Configs configs, SuccessCallback success, ErrorCallback error); }

İlgi çekici olan, her ikisi de yukarıdaki lambda ifadesi ile uygulanan ve @JsFunction ek açıklaması aracılığıyla Java'da tanımlanan SuccessCallback ve ErrorCallback arabirimlerinin tanımıdır:

 @JsFunction public interface SuccessCallback { public void onMediaSuccess(MediaStream stream); } @JsFunction public interface ErrorCallback { public void onError(DomException error); }

Son olarak, sınıf URL tanımı Navigator ile hemen hemen aynıdır ve benzer şekilde Configs sınıfı şu şekilde tanımlanabilir:

 @JsType(namespace = JsPackage.GLOBAL, isNative = true, name="Object") public static class Configs { @JsProperty public native void setVideo(boolean getVideo); }

Tüm bu işlevlerin gerçek uygulaması, tarayıcının JavaScript motorunda gerçekleşir.

Yukarıdaki kodu GitHub'da burada bulabilirsiniz.

Bu örnekte, basitlik adına, kullanımdan kaldırılan navigator.getUserMedia() API'si, Chrome'un mevcut kararlı sürümünde çoklu doldurma olmadan çalışan tek API olduğu için kullanılmıştır. Bir üretim uygulamasında, daha yeni navigator.mediaDevices.getUserMedia() API aracılığıyla akışa erişmek için tüm tarayıcılarda aynı şekilde Adapter.js'yi kullanabiliriz, ancak bu, mevcut tartışmanın kapsamı dışındadır.

WebGL

GWT'den WebGL'yi kullanmak, WebRTC'yi kullanmaktan çok farklı değildir, ancak OpenGL standardının içsel karmaşıklığı nedeniyle biraz daha sıkıcıdır.

Buradaki yaklaşımımız, önceki bölümde izlenen yaklaşımı yansıtmaktadır. Sarmanın sonucu, burada bulunabilecek Picshare'de kullanılan GWT WebGL uygulamasında görülebilir ve GWT tarafından üretilen sonuçların bir örneğini burada bulabilirsiniz.

WebGL'yi tek başına etkinleştirmek aslında bize 3D grafik yeteneği vermez. Gregg Tavares'in yazdığı gibi:

Pek çok kişinin bilmediği şey, WebGL'nin aslında bir 3D API değil, bir 2D API olduğudur.

3B aritmetik başka bir kodla yapılmalı ve WebGL için 2B görüntüye dönüştürülmelidir. 3D WebGL grafikleri için bazı iyi GWT kitaplıkları vardır. Benim favorim Paralaks, ancak Picshare'ın ilk sürümü için daha "kendin yap" yolunu izledik, basit 3B ağlar oluşturmak için küçük bir kitaplık yazdık. Kütüphane, bir perspektif kamera tanımlamamıza ve bir nesne sahnesini yönetmemize izin verir. Kontrol etmek için çekinmeyin, burada.

Üçüncü Taraf Java Kitaplıklarını GWT ile Derleme

NyARToolkit, artırılmış gerçeklik uygulamaları oluşturmaya yönelik bir yazılım kitaplığı olan ARToolKit'in saf Java bağlantı noktasıdır. Liman, Nyatla'daki Japon geliştiriciler tarafından yazılmıştır. Orijinal ARToolKit ve Nyatla sürümü, orijinal bağlantı noktasından bu yana biraz farklı olsa da, NyARToolkit hala aktif olarak korunur ve geliştirilir.

İşaretleyici tabanlı AR, özel bir alandır ve burada görüldüğü gibi bilgisayarla görme, dijital görüntü işleme ve matematikte yetkinlik gerektirir:

ARToolKit ile işaretleyici tabanlı artırılmış gerçeklik görüntü analizi.

ARToolKit belgelerinden çoğaltılmıştır.

ARToolKit ile işaretleyici tabanlı artırılmış gerçeklik ardışık düzeni.

ARToolKit belgelerinden çoğaltılmıştır.

Araç seti tarafından kullanılan tüm algoritmalar belgelenmiştir ve iyi anlaşılmıştır, ancak bunları sıfırdan yeniden yazmak uzun ve hataya açık bir süreçtir, bu nedenle ARToolKit gibi mevcut, kanıtlanmış bir araç setinin kullanılması tercih edilir. Ne yazık ki, web'i hedeflerken böyle bir şey mevcut değildir. En güçlü, gelişmiş araç setlerinin, öncelikle HTML belgelerini ve verilerini işlemek için kullanılan bir dil olan JavaScript'te uygulaması yoktur. GWT'nin paha biçilmez gücünü kanıtladığı yer burasıdır ve NyARToolkit'i JavaScript'e kolayca aktarmamızı ve çok az güçlükle bir web uygulamasında kullanmamızı sağlar.

GWT ile derleme

Bir GWT projesi aslında bir Java projesi olduğundan, NyARToolkit'i kullanmak, kaynak yolunuzdaki kaynak dosyaları içe aktarma meselesidir. Ancak, GWT kodunun JavaScript'e aktarılması kaynak kodu düzeyinde yapıldığından, derlenmiş sınıflarla birlikte yalnızca bir JAR'a değil, NyARToolkit kaynaklarına ihtiyacınız olduğunu unutmayın.

Picshare tarafından kullanılan kütüphane burada bulunabilir. Yalnızca burada arşivlenen NyARToolkit derlemesinden lib/src ve lib/src.markersystem içinde bulunan paketlere bağlıdır. Bu paketleri kopyalayıp GWT projemize aktarmalıyız.

Bu üçüncü taraf paketlerini kendi uygulamamızdan ayrı tutmalıyız, ancak NyARToolkit'in “GWT-ization” işlemine devam etmek için GWT derleyicisine kaynakları nerede arayacağını bildiren bir XML yapılandırma dosyası sağlamalıyız. jp.nyatla.nyartoolkit paketinde jp.nyatla.nyartoolkit dosyasını NyARToolkit.gwt.xml

 <module> <source path="core" /> <source path="detector" /> <source path="nyidmarker" /> <source path="processor" /> <source path="psarplaycard" /> <source path="markersystem" /> </module>

Şimdi, ana paketimiz com.jooink.gwt.nyartoolkit içinde, ana yapılandırma dosyası olan GWT_NyARToolKit.gwt.xml oluşturuyoruz ve derleyiciye, XML dosyasından miras alarak Nyatla'nın kaynağını sınıf yoluna dahil etmesi için talimat veriyoruz:

 <inherits name='jp.nyatla.nyartoolkit.NyARToolkit'/>

Aslında oldukça kolay. Çoğu durumda, gereken tek şey bu olabilir, ancak ne yazık ki henüz bitirmedik. Bu aşamada Super Dev Mode üzerinden derlemeye veya yürütmeye çalışırsak, oldukça şaşırtıcı bir şekilde şunu belirten bir hatayla karşılaşırız:

 No source code is available for type java.io.InputStream; did you forget to inherit a required module?

Bunun nedeni, NyARToolkit'in (yani, Java projeleri için tasarlanmış bir Java kitaplığı), GWT'nin Öykünülmüş JRE'si tarafından desteklenmeyen JRE sınıflarını kullanmasıdır. Bunu bir önceki gönderide kısaca tartışmıştık.

Bu durumda sorun InputStream ve ilgili IO sınıflarındadır. Olduğu gibi, bu sınıfların çoğunu kullanmamıza bile gerek yok, ancak derleyiciye bir miktar uygulama sağlamamız gerekiyor. Bu referansları NyARToolkit kaynağından manuel olarak kaldırmak için çok zaman harcayabiliriz, ancak bu çılgınlık olur. GWT bize daha iyi bir çözüm sunuyor: <super-source> XML etiketi aracılığıyla desteklenmeyen sınıfların kendi uygulamalarımızı sağlayın.

<super-source>

Resmi belgelerde açıklandığı gibi:

<super-source> etiketi, derleyiciye bir kaynak yolunu yeniden köklendirmesi talimatını verir. Bu, bir GWT projesi için mevcut bir Java API'sini yeniden kullanmak istediğiniz ancak orijinal kaynağın mevcut olmadığı veya çevrilemediği durumlarda kullanışlıdır. Bunun yaygın bir nedeni, GWT tarafından uygulanmayan JRE'nin bir bölümünü taklit etmektir.

Yani <super-source> tam olarak ihtiyacımız olan şey.

GWT projesinde bize sorun çıkaran sınıflar için uygulamalarımızı koyabileceğimiz bir jre dizini oluşturabiliriz:

 java.io.FileInputStream java.io.InputStream java.io.InputStreamReader java.io.StreamTokenizer java.lang.reflect.Array java.nio.ByteBuffer java.nio.ByteOrder

java.lang.reflect.Array hariç bunların hepsi gerçekten kullanılmamaktadır, bu yüzden sadece aptal uygulamalara ihtiyacımız var. Örneğin, FileInputStream aşağıdaki gibidir:

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

Window.alert ifadesi geliştirme sırasında yararlıdır. Sınıfı derleyebilmemiz gerekse de, onu asla gerçekten kullanmadığımızdan emin olmak istiyoruz, bu nedenle bu, sınıfın yanlışlıkla kullanılması durumunda bizi uyaracaktır.

java.lang.reflect.Array aslında ihtiyacımız olan kod tarafından kullanılıyor, bu nedenle tamamen aptal olmayan bir uygulama gerekiyor. Bu bizim kodumuz:

 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 <T> Object newInstance(Class<T> 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; } }

Şimdi GWT_NyARToolkit.gwt.xml modül dosyasına <super-source path="jre"/> yerleştirirsek, NyARToolkit'i projemizde güvenle derleyebilir ve kullanabiliriz!

Hepsini GWT ile Yapıştırmak

Şimdi şu durumdayız:

  • WebRTC, web kamerasından bir akış alabilen ve bunu bir <video> etiketinde görüntüleyebilen bir teknoloji.
  • WebGL, donanım hızlandırmalı grafikleri HTML <canvas> içinde değiştirebilen bir teknoloji.
  • NyARToolkit, bir görüntü alma (bir piksel dizisi olarak), bir işaretçi arama ve bulunursa bize işaretçinin 3B uzaydaki konumunu tam olarak tanımlayan bir dönüşüm matrisi verme yeteneğine sahip bir Java kitaplığı.

Şimdiki zorluk, tüm bu teknolojileri bir araya getirmek.

Bir 3B alanı kameraya yansıtma.

Bunu nasıl başaracağımıza derinlemesine girmeyeceğiz, ancak temel fikir, video görüntüsünü sahnemizin arka planı olarak kullanmak (yukarıdaki resimde "uzak" düzleme uygulanan bir doku) ve bir 3B veri yapısı oluşturmaktır. NyARToolkit'in sonuçlarını kullanarak bu görüntüyü uzaya yansıtmamıza izin veriyor.

Bu yapı bize işaretçi tanıma için NyARToolkit'in kitaplığı ile etkileşime geçmek ve kamera sahnesinin üstüne 3D modeli çizmek için doğru yapıyı verir.

Kamera akışını kullanılabilir hale getirmek biraz zor. Video verileri yalnızca bir <video> öğesine çizilebilir. HTML5 <video> öğesi opaktır ve görüntü verilerini doğrudan çıkarmamıza izin vermez, bu nedenle videoyu <canvas> ara öğesine kopyalamak, görüntü verilerini çıkarmak, bir piksel dizisine dönüştürmek ve son olarak NyARToolkit'in Sensor.update() yöntemine itin. Ardından NyARToolkit, görüntüdeki işaretçiyi belirleme ve 3B alanımızdaki konumuna karşılık gelen bir dönüşüm matrisi döndürme işini yapabilir.

Bu öğelerle, canlı video akışında tam olarak işaretçinin üzerinde 3D olarak sentetik bir nesneyi sıralayabiliriz! GWT'nin yüksek performansı sayesinde, çok sayıda hesaplama kaynağına sahibiz, bu nedenle, WebGL sahnesi için arka plan olarak kullanmadan önce, sepya veya bulanıklık gibi bazı video efektlerini tuval üzerine uygulayabiliriz.

Aşağıdaki kısaltılmış kod, sürecin özünü açıklar:

 // given a <canvas> drawing context with appropriate width and height // and a <video> 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 ... } ...

Bu teknikle aşağıdaki gibi sonuçlar üretebiliriz:

Picshare tarayıcı içi artırılmış gerçeklik uygulamasının sonuçları.

Birden çok işaretleyici ile tarayıcı içi artırılmış gerçeklik uygulamasının Picshare sonuçları.

Bu, bir işaretleyiciyi yazdırmaya veya cep telefonunuzda görüntülemeye ve tarayıcınızda işaretçi tabanlı AR ile oynamaya davet edildiğiniz Picshare'i oluşturmak için kullandığımız işlemdir. Eğlence!

Son Açıklamalar

Picshare , Jooink'te bizim için uzun vadeli bir evcil hayvan projesidir. İlk uygulama birkaç yıl öncesine dayanıyor ve o zaman bile etkileyici olacak kadar hızlıydı. Bu bağlantıda, 2012'de derlenmiş ve hiç dokunulmamış daha önceki deneylerimizden birini görebilirsiniz. Örnekte yalnızca bir <video> olduğuna dikkat edin. Diğer iki pencere, işleme sonuçlarını gösteren <canvas> öğeleridir.

GWT, 2012'de bile yeterince güçlüydü. GWT 2.8'in piyasaya sürülmesiyle, performansı daha da artıran JsInterop ile çok daha iyileştirilmiş bir birlikte çalışabilirlik katmanı kazandık. Ayrıca, birçoğunu kutlamak için, çok daha iyi bir geliştirme ve hata ayıklama ortamı olan Süper Geliştirme Modu'nu da kazandık. Ah evet ve Java 8 desteği.

GWT 3.0'ı dört gözle bekliyoruz!