Sanal gerçeklik web'e geliyor, 2. bölüm

Kare döngüsü hakkında

Joe Medley
Joe Medley

Kısa süre önce, WebXR Device API'nin temel kavramlarını tanıtan Sanal gerçeklik web'e geliyor başlıklı bir makale yayınladım. Ayrıca, XR oturumu isteğinde bulunma, oturuma girme ve oturumu sonlandırmayla ilgili talimatlar da sağladım.

Bu makalede, içeriğin ekrana tekrar tekrar çizildiği, kullanıcı aracısı tarafından kontrol edilen sonsuz bir döngü olan kare döngüsü açıklanmaktadır. İçerik, kare adı verilen ayrı bloklar halinde çizilir. Karelerin art arda gelmesi hareket yanılsaması oluşturur.

Bu makale ne değildir?

WebGL ve WebGL2, bir WebXR uygulamasında kare döngüsü sırasında içerik oluşturmanın tek yoludur. Neyse ki birçok çerçeve, WebGL ve WebGL2'nin üzerine bir soyutlama katmanı sağlar. Bu çerçeveler three.js, babylonjs ve PlayCanvas içerir. A-Frame ve React 360 ise WebXR ile etkileşim için tasarlanmıştır.

Bu makale bir WebGL veya çerçeve eğitimi değildir. Bu makalede, Immersive Web Çalışma Grubu'nun Immersive VR oturumu örneği (demo, kaynak) kullanılarak kare döngüsünün temelleri açıklanmaktadır. WebGL veya çerçevelerden birini incelemek isterseniz internet, giderek büyüyen bir makale listesi sunar.

Oyuncular ve oyun

Kare döngüsünü anlamaya çalışırken ayrıntılarda kayboldum. Oyunda çok sayıda nesne vardır ve bunların bazıları yalnızca diğer nesnelerdeki referans özelliklerle adlandırılmıştır. Konuyu daha net anlayabilmeniz için "oyuncu" olarak adlandırdığım nesneleri açıklayacağım. Ardından, bu öğelerin nasıl etkileşimde bulunduğunu açıklayacağım. Buna "oyun" diyorum.

Oyuncular

XRViewerPose

Poz, bir nesnenin 3D uzaydaki konumu ve yönüdür. Hem izleyiciler hem de giriş cihazları bir duruşa sahiptir. Ancak burada izleyicinin duruşu önemlidir. Hem izleyici hem de giriş cihazı duruşlarının, konumunu bir vektör olarak ve orijine göre yönelimini bir dört boyutlu vektör olarak tanımlayan bir transform özelliği vardır. XRSession.requestReferenceSpace() çağrılırken kaynak, istenen referans alanı türüne göre belirtilir.

Referans alanları biraz açıklama gerektirir. Bunları artırılmış gerçeklik ile ayrıntılı olarak anlatıyorum. Bu makalenin temeli olarak kullandığım örnekte 'local' referans alanı kullanılmaktadır. Bu, orijinin, oturum oluşturulduğu sırada izleyicinin konumunda olduğu, iyi tanımlanmış bir zemin olmadığı ve tam konumunun platforma göre değişebileceği anlamına gelir.

XRView

Görünüm, sanal sahneyi görüntüleyen bir kameraya karşılık gelir. Görünümlerin, vektör olarak konumunu ve yönünü açıklayan bir transform özelliği de vardır. Bunlar hem vektör/dört boyutlu vektör çifti hem de eşdeğer matris olarak sağlanır. Kodunuza en uygun olan temsili kullanabilirsiniz. Her görüntüleme, görüntüyü izleyiciye sunmak için bir cihaz tarafından kullanılan bir ekrana veya ekranın bir bölümüne karşılık gelir. XRView nesneleri, XRViewerPose nesnesinden bir dizgede döndürülür. Dizideki görüntüleme sayısı değişiklik gösterir. Mobil cihazlarda AR sahnesinin tek bir görünümü vardır. Bu görünüm, cihaz ekranını kaplayabilir veya kaplamayabilir. Kulaklıklar genellikle her göz için iki görünüme sahiptir.

XRWebGLLayer

Katmanlar, bit eşlem resimleri için bir kaynak ve bu resimlerin cihazda nasıl oluşturulacağına ilişkin açıklamalar sağlar. Bu açıklama, oynatıcının işlevini tam olarak yansıtmıyor. Bunu bir cihaz ile WebGLRenderingContext arasında aracı olarak düşünmeye başladım. MDN de bu konuda benzer bir bakış açısına sahip olup bu iki öğe arasında "bağlantı sağladığını" belirtir. Bu nedenle, diğer oyunculara erişim sağlar.

Genel olarak WebGL nesneleri, 2D ve 3D grafikleri oluşturmak için durum bilgilerini depolar.

WebGLFramebuffer

Bir çerçeve arabelleği, WebGLRenderingContext görüntü verilerini sağlar. XRWebGLLayer bölümünden aldıktan sonra mevcut WebGLRenderingContext öğesine aktarmanız yeterlidir. bindFramebuffer()'ü çağırmanın dışında (bu konu hakkında daha fazla bilgiyi aşağıda bulabilirsiniz) bu nesneye hiçbir zaman doğrudan erişmezsiniz. Yalnızca XRWebGLLayer'ten WebGLRenderingContext'e iletmeniz yeterlidir.

XRViewport

Görüntü alanı, WebGLFramebuffer içindeki dikdörtgen bir bölgenin koordinatlarını ve boyutlarını sağlar.

WebGLRenderingContext

Oluşturma bağlamı, bir kanvas (üzerinde çizim yaptığımız alan) için programatik bir erişim noktasıdır. Bunun için hem WebGLFramebuffer hem de XRViewport gerekir.

XRWebGLLayer ile WebGLRenderingContext arasındaki ilişkiye dikkat edin. Biri görüntüleyenin cihazına, diğeri ise web sayfasına karşılık gelir. WebGLFramebuffer ve XRViewport, ilkinden ikincisine aktarılır.

XRWebGLLayer ile WebGLRenderingContext arasındaki ilişki
XRWebGLLayer ile WebGLRenderingContext arasındaki ilişki

Maç

Oyuncuların kim olduğunu öğrendiğimize göre, oynadıkları oyuna bakalım. Bu her karede baştan başlayan bir oyun. Karelerin, temel donanıma bağlı bir hızda gerçekleşen bir kare döngüsünün parçası olduğunu unutmayın. VR uygulamaları için saniyedeki kare sayısı 60 ila 144 arasında olabilir. Android için AR, saniyede 30 kare hızında çalışır. Kodunuz belirli bir kare hızını varsaymamalıdır.

Kare döngüsü için temel süreç şu şekildedir:

  1. XRSession.requestAnimationFrame() Hizmetleri İçin Arayın. Kullanıcı aracısı, yanıt olarak sizin tanımladığınız XRFrameRequestCallback öğesini çağırır.
  2. Geri çağırma işlevinizin içinde:
    1. XRSession.requestAnimationFrame() adlı kişiyi tekrar arayın.
    2. İzleyicinin pozunu alın.
    3. WebGLFramebuffer öğesini XRWebGLLayer'dan WebGLRenderingContext'ye iletin ("bağlayın").
    4. Her XRView nesnesini iterleyerek XRViewport değerini XRWebGLLayer'den alıp WebGLRenderingContext'a aktarın.
    5. Çerçeve arabelleğine bir şey çizin.

Önceki makalede 1. ve 2a. adımlar ele alındığı için 2b adımından başlayacağım.

İzleyicinin duruşunu alın

Bunu söylemeye gerek yok. Artırılmış gerçeklik (AR) veya sanal gerçeklikte (VR) bir şey çizmek için izleyicinin nerede olduğunu ve nereye baktığını bilmem gerekiyor. İzleyicinin konumu ve yönü bir XRViewerPose nesnesi tarafından sağlanır. Geçerli animasyon karesindeki XRFrame.getViewerPose() işlevini çağırarak izleyicinin duruşunu alıyorum. Oturum oluştururken edindiğim referans alanı iletirim. Bu nesne tarafından döndürülen değerler, her zaman mevcut oturuma girdiğimde istediğim referans alanına göre olur. Hatırlayacağınız üzere, pozu isterken mevcut referans alanını geçmem gerekiyor.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);
  if (xrViewerPose) {
    // Render based on the pose.
  }
}

Kullanıcının genel konumunu, yani akıllı telefonda kullanıcının kafasını veya telefon kamerasını temsil eden bir izleyici duruşu vardır. Poz, uygulamanıza izleyicinin nerede olduğunu söyler. Gerçek resim oluşturma işleminde XRView nesne kullanılır. Buna birazdan değineceğim.

Devam etmeden önce, sistemin izlemeyi kaybetmesi veya gizlilik nedeniyle pozu engellemesi ihtimaline karşı izleyicinin pozunun döndürülüp döndürülmediğini test ederim. Takip, XR cihazın kendisinin ve/veya giriş cihazlarının çevreye göre nerede olduğunu bilme özelliğidir. İzleme, çeşitli şekillerde kaybedilebilir ve izleme için kullanılan yönteme göre değişiklik gösterir. Örneğin, mikrofonlu kulaklıktaki veya telefondaki kameralar cihazı takip etmek için kullanılırsa ışığın az olduğu, hiç olmadığı ya da kameraların üstü kapalı olduğu durumlarda cihazın yerini belirleme yeteneğini kaybedebilir.

Gizlilik nedeniyle pozun engellenmesine örnek olarak, kulaklık izin istemi gibi bir güvenlik iletişim kutusu gösteriyorsa tarayıcı bu sırada uygulamaya poz sağlamayı durdurabilir. Ancak sistem kurtarılabilirse kare döngüsü devam etsin diye XRSession.requestAnimationFrame() numaralı telefonu aradım. Aksi takdirde kullanıcı aracısı oturumu sonlandırır ve end etkinlik işleyicisini çağırır.

Kısa bir ara

Bir sonraki adım için oturum oluşturma sırasında oluşturulan nesneler gerekir. Bir kanvas oluşturduğumu ve canvas.getContext() çağrısını yaparak XR uyumlu bir Web GL oluşturma bağlamı oluşturmasını istediğimi hatırlayın. Tüm çizimler WebGL API, WebGL2 API veya Three.js gibi WebGL tabanlı bir çerçeve kullanılarak yapılır. Bu bağlam, yeni bir XRWebGLLayer örneğiyle birlikte updateRenderState() aracılığıyla oturum nesnesine aktarıldı.

let canvas = document.createElement('canvas');
// The rendering context must be based on WebGL or WebGL2
let webGLRenContext = canvas.getContext('webgl', { xrCompatible: true });
xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(xrSession, webGLRenContext)
  });

WebGLFramebuffer'ı iletme ("bağlama")

XRWebGLLayer, WebXR ile kullanılmak üzere özel olarak sağlanan ve oluşturma bağlamlarının varsayılan çerçeve önbelleğini değiştiren WebGLRenderingContext için bir çerçeve önbelleği sağlar. WebGL dilinde buna "bağlama" denir.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);
  if (xrViewerPose) {
    let glLayer = xrSession.renderState.baseLayer;
    webGLRenContext.bindFramebuffer(webGLRenContext.FRAMEBUFFER, glLayer.framebuffer);
    // Iterate over the views
  }
}

Her XRView nesnesini iterasyonla gezme

Pozisyonu aldıktan ve çerçeve önbelleğini bağladıktan sonra görüntüleme alanlarını almanız gerekir. XRViewerPose, her biri bir ekranın bir ekranını veya bir kısmını temsil eden bir XRView arayüzleri dizisi içerir. Bu veriler, cihaz ve izleyici için doğru şekilde konumlandırılmış içerikleri oluşturmak için gereken bilgileri (ör. görüş alanı, göz ofseti ve diğer optik özellikler) içerir. İki göz için çizim yaptığımdan iki görünümüm var. Bu görünümleri döngüden geçirip her biri için ayrı bir resim çiziyorum.

Telefon tabanlı artırılmış gerçeklik için uygulama yaparken yalnızca bir görünümüm olur ancak yine de döngü kullanırım. Tek bir görünümde yineleme yapmak anlamsız görünse de, farklı etkileyici deneyimler için tek bir oluşturma yolunuz olmasını sağlar. Bu, WebXR ile diğer sürükleyici sistemler arasındaki önemli bir farktır.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);
  if (xrViewerPose) {
    let glLayer = xrSession.renderState.baseLayer;
    webGLRenContext.bindFramebuffer(webGLRenContext.FRAMEBUFFER, glLayer.framebuffer);
    for (let xrView of xrViewerPose.views) {
      // Pass viewports to the context
    }
  }
}

XRViewport nesnesini WebGLRenderingContext'e aktarma

XRView nesnesi, ekranda gözlemlenebilir olan öğeleri ifade eder. Ancak bu görünümde çizim yapmak için cihazıma özgü koordinatlara ve boyutlara ihtiyacım var. Görüntü çerçevesi gibi, bunları XRWebGLLayer'ten isteyip WebGLRenderingContext'a iletirim.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);
  if (xrViewerPose) {
    let glLayer = xrSession.renderState.baseLayer;
    webGLRenContext.bindFramebuffer(webGLRenContext.FRAMEBUFFER, glLayer.framebuffer);
    for (let xrView of xrViewerPose.views) {
      let viewport = glLayer.getViewport(xrView);
      webGLRenContext.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
      // Draw something to the framebuffer
    }
  }
}

webGLRenContext

Bu makaleyi yazarken webGLRenContext nesnesinin adlandırması konusunda birkaç iş arkadaşımla tartışma yaşadım. Örnek komut dosyaları ve çoğu WebXR kodu, bu değişkeni gl olarak adlandırır. Sana gönderdiğim örnekleri anlamaya çalışırken gl ne anlama geliyordu? Bunun WebGLRenderingContext örneği olduğunu öğrenirken size hatırlatmak için webGLRenContext olarak adlandırdım.

Bunun nedeni, gl kullanıldığında yöntem adlarının derlenmiş dillerde VR oluşturmak için kullanılan OpenGL ES 2.0 API'sindeki benzerlerine benzemesidir. OpenGL kullanarak VR uygulamaları yazdıysanız bu durum açıktır ancak bu teknolojiye tamamen yeniyseniz kafa karıştırıcı olabilir.

Çerçeve arabelleğine bir öğe çizin

Çok azimliyseniz doğrudan WebGL'yi kullanabilirsiniz, ama bunu önermem. En üstte listelenen çerçevelerden birini kullanmak çok daha kolaydır.

Sonuç

WebXR güncellemeleri veya makaleleri burada sona ermiyor. WebXR'ın tüm arayüzleri ve üyelerine dair referansları MDN'de bulabilirsiniz. Arayüzlerde yapılacak yenilikler için Chrome Durumu'nda ilgili özellikleri takip edin.

Fotoğraf: JESHOOTS.COM, Unsplash'te