Kare döngüsü hakkında her şey
Kısa bir süre önce, WebXR Device API'nin ardındaki temel kavramları tanıtan Sanal gerçeklik web'e geliyor başlıklı bir makaleyi yayınladım. Ayrıca, bir XR oturumunu isteme, girme ve sonlandırmayla ilgili talimatları da sağladım.
Bu makalede, içeriğin sürekli olarak ekrana çizildiği, kullanıcı aracısı kontrollü bir sonsuz döngü olan çerçeve döngüsü açıklanmaktadır. İçerik, çerçeve adı verilen ayrı bloklar halinde çizilir. Karelerin arka arkaya çalışması hareket illüzyonu yaratır.
Bu makale ne değildir?
WebGL ve WebGL2, WebXR uygulamasında bir kare döngüsü sırasında içerik oluşturmak için kullanılan tek yöntemdir. Neyse ki birçok çerçeve, WebGL ve WebGL2'nin üzerine bir soyutlama katmanı sağlamaktadır. Bu çerçeveler arasında three.js, babylonjs ve PlayCanvas yer alır. A-Frame ve React 360 ise, WebXR ile etkileşim için tasarlanmıştır.
Bu makale bir WebGL veya çerçeve eğiticisi değildir. Bu kılavuzda, Immersive Web Working Group'un Immersive VR Oturumu örneği kullanılarak çerçeve döngüsünün temel bilgileri açıklanmaktadır (demo, kaynak). WebGL veya çerçevelerden birini ayrıntılı olarak incelemek isterseniz internette makalelerin sayısı giderek artmaktadır.
Oyuncular ve oyun
Kare döngüsünü anlamaya çalışırken sürekli ayrıntılarda kayboluyordum. Oyunda çok sayıda nesne vardır ve bunların bazıları yalnızca diğer nesnelerdeki referans özelliklerine göre adlandırılır. Düz bir çizgide kalmanıza yardımcı olmak için nesneleri, 'oyuncular' diyorum. Sonra, etkileşim kurduklarını açıklayacağım, buna 'oyun' adını veriyorum.
Oyuncular
XRViewerPose
Poz, bir şeyin 3D uzaydaki konumu ve yönüdür. Hem görüntüleyenlerin hem de giriş cihazlarının bir duruşu var, ancak burada asıl endişemiz görüntüleyen kişi durudur. Hem görüntüleyici hem de giriş cihazı pozisyonlarında, konumunu vektör olarak, yönünü ise kaynağa göre dörtlü olarak açıklayan bir transform
özelliği bulunur. Kaynak, XRSession.requestReferenceSpace()
çağrılırken istenen referans alanı türüne göre belirtilir.
Referans alanlarının açıklanması biraz zaman alabilir. Artırılmış gerçeklik'te bunları tüm ayrıntılarıyla ele alıyorum. Bu makalenin temeli olarak kullandığım örnekte 'local'
referans alanı kullanılıyor. Bu, kaynağın oturum oluşturulurken izleyicinin bulunduğu konumda olduğu ve iyi tanımlanmış bir taban bulunmadığı anlamına gelir. Ayrıca, tam konumu platforma göre değişebilir.
XRView
Görünüm, sanal sahneyi görüntüleyen bir kameraya karşılık gelir. Bir görünüm, konumunu vektör olarak ve yönünü açıklayan transform
özelliğine de sahiptir.
Bunlar hem vektör/kuterniyon çifti hem de eşdeğer bir matris olarak sağlanır ve kodunuza en uygun olan temsile bağlı olarak her iki temsili de kullanabilirsiniz. Her görünüm, bir cihaz tarafından izleyiciye görüntü sunmak için kullanılan bir ekrana veya ekranın bir bölümüne karşılık gelir. XRViewerPose
nesnesinden bir dizide XRView
nesne döndürülür. Dizideki görüntüleme sayısı değişiklik gösterir. Mobil cihazlarda bir AR sahnesi, cihazın ekranını kaplayan ya da kaplamayan tek bir görünüme sahiptir.
Mikrofonlu kulaklıklarda genellikle her bir göz için bir tane olmak üzere iki görünüm bulunur.
XRWebGLLayer
Katmanlar, bit eşlem resimler için bir kaynak ve bu resimlerin cihazda nasıl
oluşturulacağına ilişkin açıklamalar sağlar. Bu açıklama, bu oynatıcının ne yaptığını
tam olarak yansıtmıyor. Bunu, bir cihazla WebGLRenderingContext
arasındaki aracı
gibi düşünüyorum. MDN de hemen hemen aynı görünümü alarak ikisi arasında "bir bağlantı sağladığını" ifade eder. 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
Çerçeve arabelleği, resim verilerini WebGLRenderingContext
ürününe sağlar. XRWebGLLayer
öğesinden aldıktan sonra, bunu geçerli WebGLRenderingContext
öğesine geçirirsiniz. bindFramebuffer()
(daha sonra da bahsedilecek) işlevini çağırmak dışında, bu nesneye hiçbir zaman doğrudan erişemezsiniz. Bunu sadece XRWebGLLayer
ürününden WebGLRenderingContext'e aktarmanız yeterli.
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ı, tuval (üzerinde çizdiğimiz alan) için programatik erişim noktasıdır. Bunu yapmak için hem WebGLFramebuffer
hem de XRViewport gereklidir.
XRWebGLLayer
ile WebGLRenderingContext
arasındaki ilişkiye dikkat edin. Biri görüntüleyenin cihazına, diğeri web sayfasına karşılık gelir.
WebGLFramebuffer
ve XRViewport
, ilkinden ikincisine aktarılır.
Maç
Artık oyuncuların kim olduğunu öğrendiğimize göre oynadıkları oyunlara bakalım. Bu, her karede baştan başlayan bir oyun. Karelerin, temel donanıma bağlı bir hızda gerçekleşen bir çerçeve döngüsünün parçası olduğunu unutmayın. VR uygulamalarında saniyedeki kare sayısı 60 ile 144 arasında bir değer olabilir. Android için AR, saniyede 30 kare hızında çalışır. Kodunuz herhangi bir kare hızı tahmininde bulunmamalıdır.
Çerçeve döngüsüne ilişkin temel süreç şu şekildedir:
XRSession.requestAnimationFrame()
Hizmetleri İçin Arayın. Buna yanıt olarak, kullanıcı aracısı sizin tarafınızdan tanımlananXRFrameRequestCallback
yöntemini çağırır.- Geri çağırma işlevinizin içinde:
XRSession.requestAnimationFrame()
adlı kişiyi tekrar arayın.- İzleyicinin pozunu çekin.
WebGLFramebuffer
öğesiniXRWebGLLayer
ileWebGLRenderingContext
arasında aktarın ("bağlayın").- Her
XRView
nesnesini yineleme yaparakXRWebGLLayer
nesnesindenXRViewport
öğesini alın veWebGLRenderingContext
öğesine iletin. - Çerçeve arabelleğine bir şey çizin.
1. ve 2a. adımlar önceki makalede ele alındığından, adım 2b'den başlayacağım.
İzleyicinin duruşunu çekin
Söylemeye gerek yok. Artırılmış gerçeklik (AR) veya sanal gerçeklikte (VR) bir şey çizmek için görüntüleyenin
nerede olduğunu ve nereye baktığını bilmem gerekiyor. Görüntüleyenin konumu ve yönü bir XRViewerPose nesnesi tarafından sağlanır. İzleyicinin pozunu, mevcut animasyon karesinde XRFrame.getViewerPose()
çağrısı yaparak istiyorum. Bu e-postayı, oturumu oluştururken edindiğim referans alanına iletiyorum. Bu nesne tarafından döndürülen değerler her zaman geçerli oturumu girdiğimde istediğim referans alanına göre olur. Hatırlayacağınız üzere, poz isterken mevcut referans alanını iletmem 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 temsil eden bir izleyici pozu vardır. Diğer bir deyişle, akıllı telefonda görüntüleyen kişinin başı veya telefonun kamerası gösterilir.
Poz, uygulamanıza görüntüleyenin nerede olduğunu bildirir. Gerçek resim oluşturma işleminde XRView
nesneleri kullanılır. Bu konuyu birazdan ele alacağım.
Devam etmeden önce, sistemin izlemeyi kaybetmesi veya gizlilik nedeniyle pozu engellemesi ihtimaline karşı izleyici pozunun geri döndürülüp döndürülmediğini test ediyorum. İzleme, XR cihazının ortama göre nerede ve/veya giriş cihazlarının nerede olduğunu bilebilmesidir. İzleme, birkaç şekilde kaybolabilir ve izleme için kullanılan yönteme bağlı olarak değişir. Örneğin, mikrofonlu kulaklıktaki veya telefondaki kameralar takip etmek için kullanılırsa cihaz, ışığın az olduğu veya hiç olmadığı durumlarda nerede olduğunu ya da kameraların üzerinin kapalı olup olmadığını belirleyemeyebilir.
Gizlilik nedeniyle pozu engellemeye örnek olarak, başlıkta izin istemi gibi bir güvenlik iletişim kutusu gösteriliyorsa tarayıcı bu işlem gerçekleşirken uygulamaya poz vermeyi durdurabilir. Ama daha önce XRSession.requestAnimationFrame()
çağrısı yaptım. Böylece, sistem kurtarılabilirse çerçeve döngüsü devam eder. Aksi takdirde, kullanıcı aracısı oturumu sonlandırır ve end
etkinlik işleyicisini çağırır.
Rotadan kısa bir süre tali
Bir sonraki adım, oturum kurulumu sırasında oluşturulmuş nesneleri gerektirir. Hatırlayacağınız üzere bir tuval oluşturdum ve ona XR uyumlu bir Web GL oluşturma bağlamı oluşturma talimatı verdiğimi ve bunu canvas.getContext()
çağrısıyla aldığımı hatırlıyorum. Tüm çizimler WebGL API'sı, WebGL2 API'sı veya Three.js gibi WebGL tabanlı bir çerçeve kullanılarak yapılır. Bu bağlam, yeni XRWebGLLayer
örneğiyle birlikte updateRenderState()
aracılığıyla oturum nesnesine geçirildi.
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 öğesini geçirin ('bind')
XRWebGLLayer
, özellikle WebXR ile kullanılması ve oluşturma bağlamının varsayılan çerçeve arabelleğinin değiştirilmesi amacıyla sağlanan WebGLRenderingContext
için bir çerçeve arabelleği sağlar. Bu, WebGL'nin dilinde "bağlama" olarak adlandırılı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);
// Iterate over the views
}
}
Her XRView nesnesini yinele
Pozu aldıktan ve çerçeve arabelleğini bağladıktan sonra sıra görüntü alanlarını almaya gelir. XRViewerPose
, her biri bir ekranı veya ekranın bir kısmını temsil eden bir XRView arayüz dizisi içerir. Bunlar, cihaz ve izleyici için doğru şekilde konumlandırılmış içeriği oluşturmak için gereken bilgileri (ör. görüş alanı, göz uzaklığı ve diğer optik özellikler) içerir.
İki göz için çizdiğimden iki görünümüm var. Bunları döngüye alıp her biri için ayrı birer resim çiziyorum.
Telefon tabanlı artırılmış gerçeklik uygularken yalnızca bir görünüm kullanırdım ama yine de döngü kullanırdım. Tek bir görünümde yineleme yapmak anlamsız görünse de, bunu yapmak sürükleyici deneyimlerden oluşan bir yelpazesi için tek bir oluşturma yoluna sahip olmanıza olanak tanır. Bu, WebXR ile diğer kapsamlı 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 geçirme
XRView
nesnesi, ekranda gözlemlenebilen öğeleri ifade eder. Ancak, bu görünümü elde edebilmek için
cihazıma özgü koordinatlara ve boyutlara ihtiyacım var. Çerçeve arabelleğinde olduğu gibi, bunları da XRWebGLLayer
öğesinden istiyorum ve WebGLRenderingContext
'e iletiyorum.
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 birkaç iş arkadaşımla webGLRenContext
nesnesinin adlandırılması konusunda bir tartışma yaşadım. Örnek komut dosyaları ve çoğu WebXR kodu basitçe bu değişkeni gl
olarak adlandırır. Örnekleri anlamaya çalışırken, gl
ürününün neden bahsettiğini sürekli unuttum. Bunun bir WebGLRenderingContext
örneği olduğunu öğrenirken
size hatırlatmak için bu etiketi 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'deki karşılıkları gibi görünmesini sağlamasıdır. Bu, VR uygulamalarını OpenGL kullanarak yazdıysanız, ancak bu teknolojide tamamen yeni olup olmadığınız konusunda kafanızı karıştıran bir gerçektir.
Çerçeve arabelleğine bir şey çizin
Çok azimliyseniz doğrudan WebGL'yi kullanabilirsiniz ancak bunu önermem. En üstte listelenen çerçevelerden birini kullanmak çok daha basittir.
Sonuç
WebXR güncellemelerinin veya makalelerinin sonu değildir. MDN'de tüm WebXR arayüzleri ve üyeleri için referans bulabilirsiniz. Arayüzlerde yapılacak geliştirmeler için Chrome Durumu'ndaki her bir özelliği takip edin.
Fotoğraf: JESHOOTS.COM Unsplash'ta