WebVR'de Dans Tonite Oyunu

Google Veri Sanatları ekibi, WebVR'nin sunduğu olanakları keşfetmek için birlikte çalışmak konusunda Moniker'le bir araya geldiğinde heyecanlandım. Yıllardır ekiplerinin çalışmalarını izledim ve projelerinin hep hoşuna gitti. Ortak çalışmamız sayesinde Dance Tonite, LCD Soundsystem ve hayranları ile sürekli değişen bir sanal gerçeklik dansı deneyimi sundu. İşte bunu nasıl başardığımızı.

Kavram

Tarayıcınızı kullanarak bir web sitesini ziyaret ederek VR'ye girmeyi mümkün kılan bir açık standart olan WebVR'yi kullanarak bir dizi prototip geliştirerek işe başladık. Amaç, hangi cihaza sahip olursa olsun herkesin sanal gerçeklik deneyimine girmesini kolaylaştırmak.

Bunu ciddiye aldık. Bulduğumuz şey Google'ın Daydream View, Cardboard ve Samsung'un Gear VR'ları gibi cep telefonlarıyla çalışan VR başlıklarından HTC VIVE ve Oculus Rift gibi oda ölçeğindeki sistemlere ve sanal ortamınızdaki fiziksel hareketlerinizi yansıtan Oculus Rift gibi tüm VR türlerinde işe yarayabilir. Belki de en önemlisi, kendi sanal gerçeklik cihazı olmayan herkesin işine yarayacak bir şey geliştirmenin web'in ruhunda olacağını düşündük.

1. Kendin yap hareket yakalama

Kullanıcıları yaratıcı bir şekilde dahil etmek istediğimiz için, sanal gerçeklikten yararlanarak katılımın ve kendini ifade etmenin mümkün olup olmadığını araştırmaya başladık. VR'da ne kadar hassas hareket edip etrafa bakabiliyorsunuz ve sanal gerçeklikte ne kadar mükemmel sonuçlar elde edebildiğinizden çok etkilendik. Bu bize bir fikir verdi. Kullanıcıların bir şeye bakmasını veya bir şey yaratmasını sağlamak yerine hareketlerini kaydetmeye ne dersiniz?

Dans Tonite'ta kendini kaydeden birisi. Kullanıcıların arkalarındaki ekranda,
  mikrofonlu kulaklıkta ne gördükleri gösteriliyor.

Dans ederken VR gözlüğümüzün ve denetleyicilerimizin konumlarını kaydettiğimiz bir prototip oluşturduk. Kaydedilen konumları soyut şekillerle değiştirdik ve elde ettiğimiz sonuçlar hayrete düştü. Son derece insani sonuçlar sunan sonuçlar, çok fazla kişiliği içeriyordu. Kısa sürede WebVR'yi kullanarak evde ucuz film yakalama yapabileceğimizi fark ettik.

WebVR ile geliştirici, VRPose nesnesi aracılığıyla kullanıcının baş konumuna ve yönüne erişebilir. Bu değer, VR donanımı tarafından her kareyi günceller. Böylece, kodunuz doğru bakış açısından yeni kareler oluşturabilir. Ayrıca WebVR özellikli GamePad API üzerinden GamepadPose nesnesi aracılığıyla kullanıcı denetleyicilerinin konumuna/yönüne de erişebiliriz. Tüm bu konum ve yön değerlerini sadece her karede saklarız, böylece kullanıcının hareketlerini bir "kaydet" olarak oluştururuz.

2. Minimalizm ve kostümler

Günümüzde oda ölçeğinde kullanılan VR ekipmanlarıyla, kullanıcının vücudunun üç noktasını (başı ve iki eli) izleyebiliyoruz. Dance Tonite'ta bu 3 noktanın uzaydaki hareketinde insanlığa odaklanmaya devam etmek istedik. Bu amaca ulaşmak için, hareketlere odaklanabilmek için estetiği mümkün olduğunca asgari düzeyde artırdık. İnsanların beyinlerini çalıştırma fikri hoşumuza gitti.

İsveçli Psikolog Gunnar Johansson'un çalışmalarını gösteren bu video, bir şeyleri mümkün olduğunca azaltmayı düşünürken başvurduğumuz örneklerden biriydi. Bu model, hareketli beyaz noktaların hareket halindeyken neden cisim şeklinde algılandığını gösteriyor.

Margarete Hastings’in 1970 yılında Oskar Schlemmer’ın Triadic Balesi'ni geri çektiği bu kayıtta, görsel olarak renkli odalar ve geometrik kostümler bize ilham verdi.

Schlemmer’ın soyut geometrik kostümleri seçme nedeni, dansçılarının hareketlerini kuklaların ve kuklaların hareketleriyle sınırlamaktı. Ancak Dans Tonite için tam tersi bir hedefimiz vardı.

Sonuçta şekillerimizi, rotasyonla ne kadar bilgi aktardıklarına dayandırdık. Bir küre nasıl döndürüldüğünden bağımsız olarak aynı görünür, ancak bir koni aslında baktığı yönde işaret eder ve arkadan farklı görünür.

3. Hareket için döngü pedalı

Birbirleriyle dans eden ve hareket eden büyük kayıtlı kişileri göstermek istedik. Sanal gerçeklik cihazları yeteri kadar çok sayıda olmadığı için bu tür bir strateji geliştirmemiz mümkün olmazdı. Ama yine de hareket eden insan gruplarının birbirine tepki vermesini istedik. Aklımız Norman McClaren’ın 1964 tarihli "Canon" video parçasındaki yinelenen performansa gitti.

McClaren'ın performansında, her döngüden sonra birbiriyle etkileşim kurmaya başlayan koreografiye sahip bir dizi hareket bulunuyor. Müzisyenlerin farklı canlı müzik parçalarını üst üste kullanarak kendi kendilerine akın ettiği müzikte döngü pedalı gibi, kullanıcıların performansların daha serbest versiyonlarını özgürce doğaçlama yapabilecekleri bir ortam oluşturup oluşturamayacağımızı görmek istiyorduk.

4. Bağlantılı odalar

Bağlantılı odalar

Pek çok müzikte olduğu gibi, LCD Soundsystem'ın parçaları da hassas bir şekilde zamanlanmış ölçümlerle oluşturulur. Projemizde yer alan Tonite adlı parçanın uzunluğu tam olarak 8 saniyeydi. Kullanıcıların kanaldaki her 8 saniyelik döngü için bir performans göstermesini istedik. Bu ölçümlerin ritmi değişmese de müzik içerikleri değişiyor. Şarkı ilerledikçe sanatçıların farklı enstrüman ve vokallere farklı şekillerde tepki verebileceği anlar oluyor. Bu ölçümlerin her biri, kullanıcıların kendilerine uygun bir performans gösterebilecekleri bir oda olarak ifade edilir.

Performans optimizasyonları: Kare düşürme

Her cihaz veya platform için optimum performansla tek bir kod tabanında çalışan çok platformlu bir VR deneyimi oluşturmak kolay bir iş değildir.

VR'deyken en midenizi bulaştıran şeylerden biri, kare hızının hareketinize ayak uydurmamasıdır. Başınızı çevirirseniz ancak gözlerinizin gördüğü görüntüler iç kulağınızın hissettiği hareketle uyuşmazsa bu durum midenizi aniden döndürür. Bu nedenle, yüksek kare hızı gecikmelerinden kaçınmamız gerekiyordu. Uyguladığımız bazı optimizasyonları burada görebilirsiniz.

1. Örnek tampon geometrisi

Projemizin tamamı yalnızca birkaç 3 boyutlu nesne kullandığından Örnekli Tampon Geometrisi kullanarak büyük bir performans artışı elde edebildik. Temel olarak, nesnenizi GPU'ya bir kez yüklemenize ve tek bir çizim çağrısında istediğiniz kadar "örneğin" çekmenize olanak tanır. Dans Tonite'ta sadece 3 farklı nesne (bir koni, silindir ve delikli oda) olabilir, ancak bu nesnelerin yüzlerce kopyası olabilir. Örnek Arabelleği Geometrisi ThreeJS'nin bir parçasıdır, ancak Örnek Arabellek Geometrisi ile çalışmayı çok daha kolay hale getiren THREE.InstanceMesh özelliğini uygulayan Dusan Bosnjak’ın deneysel ve devam eden çatalını kullandık.

2. Çöp toplayıcıdan kaçınma

Diğer birçok kodlama dilinde olduğu gibi JavaScript, ayrılan nesnelerin artık kullanılmadığını bularak belleği otomatik olarak serbest bırakır. Bu sürece çöp toplama denir.

Geliştiricilerin bu durumun ne zaman gerçekleşeceği konusunda herhangi bir denetimi yoktur. Çöp toplayıcı her zaman kapımıza gelip çöpleri boşaltmaya başlayabilir. Bu da tatmaya zaman harcadıklarında karelerin düşmesine neden olabilir.

Bu sorunun çözümü, nesnelerimizi geri dönüştürerek mümkün olduğunca az çöp üretmektir. Her hesaplama için yeni bir vektör nesne oluşturmak yerine kazıma nesneleri yeniden kullanım için işaretledik. Referanslarımızı kendi kapsamımızın dışına taşıyarak bunları tuttuğumuzdan, kaldırılmak üzere işaretlenmediler.

Örneğin, kullanıcının kafasının ve ellerinin konum matrisini, her bir kareyi sakladığımız konum/döndürme değerleri dizisine dönüştürmek için kullandığımız kodu aşağıda bulabilirsiniz. SERIALIZE_POSITION, SERIALIZE_ROTATION ve SERIALIZE_SCALE yöntemlerini yeniden kullanarak işlev her çağrıldığında yeni nesneler oluşturmamız durumunda bellek ayırma ve atık toplama işlemlerinin önüne geçeriz.

const SERIALIZE_POSITION = new THREE.Vector3();
const SERIALIZE_ROTATION = new THREE.Quaternion();
const SERIALIZE_SCALE = new THREE.Vector3();
export const serializeMatrix = (matrix) => {
    matrix.decompose(SERIALIZE_POSITION, SERIALIZE_ROTATION, SERIALIZE_SCALE);
    return SERIALIZE_POSITION.toArray()
    .concat(SERIALIZE_ROTATION.toArray())
    .map(compressNumber);
};

3. Hareket ve progresif oynatma serileştiriliyor

VR'de kullanıcıların hareketlerini yakalamak için başlıkların ve kumandaların konumlarını ve dönüşlerini seri hale getirip bu verileri sunucularımıza yüklememiz gerekiyordu. Her kare için tam dönüşüm matrislerini tespit etmeye başladık. Bu, iyi bir performans gösterdi, ancak 16 sayının her biri saniyede 90 karede 3 konumla çarpılmasıyla ortaya çıkan çok büyük dosyalar, dolayısıyla verilerin yüklenmesi ve indirilmesi için uzun beklemeye yol açtı. Dönüşüm matrislerinden sadece konumsal ve dönen verileri çıkararak bu değerleri 16'dan 7'ye düşürmeyi başardık.

Web'deki ziyaretçiler genellikle tam olarak ne beklemeleri gerektiğini bilmeden bir bağlantıyı tıkladığından, görsel içeriği hızlı bir şekilde göstermemiz gerekir, aksi takdirde saniyeler içinde ayrılırlar.

Bu nedenle, projemizin mümkün olan en kısa sürede oynamaya başladığından emin olmak istedik. Başlangıçta, hareket verilerimizi yüklemek için bir biçim olarak JSON kullanıyorduk. Sorun, JSON dosyasını ayrıştırabilmek için tam dosyayı yüklememizdir. İlerleme değil.

Dance Tonite gibi bir projeyi mümkün olan en yüksek kare hızında görüntülemeye devam etmek amacıyla, tarayıcının JavaScript hesaplamaları için her bir kare için sadece kısa bir süresi vardır. Çok uzun sürerse animasyonlar takılmaya başlar. Başta, tarayıcı tarafından bu büyük JSON dosyalarının kodu çözüldüğü için kesintiler yaşıyorduk.

NDJSON veya Newline ile sınırlandırılmış JSON adlı kullanışlı bir akış veri biçimiyle karşılaştık. Buradaki püf noktası, her biri kendi satırında bulunan bir dizi geçerli JSON dizesi içeren bir dosya oluşturmaktır. Bu işlem, dosyayı yüklenirken ayrıştırmanızı sağlar. Böylece, performansları dosyalar tam olarak yüklenmeden önce görüntülememize olanak tanır.

Kayıtlarımızdan birinin nasıl göründüğüne bakalım:

{"fps":15,"count":1,"loopIndex":"1","hideHead":false}
[-464,17111,-6568,-235,-315,-44,9992,-3509,7823,-7074, ... ]
[-583,17146,-6574,-215,-361,-38,9991,-3743,7821,-7092, ... ]
[-693,17158,-6580,-117,-341,64,9993,-3977,7874,-7171, ... ]
[-772,17134,-6591,-93,-273,205,9994,-4125,7889,-7319, ... ]
[-814,17135,-6620,-123,-248,408,9988,-4196,7882,-7376, ... ]
[-840,17125,-6644,-173,-227,530,9982,-4174,7815,-7356, ... ]
[-868,17120,-6670,-148,-183,564,9981,-4069,7732,-7366, ... ]
...

NDJSON kullanılması, performansların bağımsız karelerinin veri temsilini dize olarak tutmamıza olanak tanır. Gerekli süreye ulaşana kadar bekledikten sonra bunları konumsal verilere dönüştürerek gerekli işlemi zaman içinde dağıttık.

4. İnterpolasyon hareketi

Aynı anda 30 ila 60 performans göstermeyi beklediğimiz için veri hızımızı sahip olduğumuzdan daha da düşürmemiz gerekiyordu. Veri Sanatları Ekibi, Tilt Brush'ı kullanarak sanatçıların sanal gerçeklikte resim yaptıkları Sanal Sanat Oturumları projesinde de aynı sorunu ele aldı. Bu sorunu, kullanıcı verilerinin daha düşük kare hızlarına sahip ara sürümlerini oluşturarak ve bunları oynatırken kareler arasında interpolasyon yaparak çözdüler. 15 FPS'de çalışan interpolasyonlu bir kayıt ile orijinal 90 FPS'lik kayıt arasındaki farkın çok zor olduğunu görmek bizi şaşırttı.

Kendiniz görmek için Dance Tonite'ı ?dataRate= sorgu dizesini kullanarak verileri çeşitli oranlarda oynatmaya zorlayabilirsiniz. Bunu, kaydedilen hareketi saniyede 90 kare, saniyede 45 kare veya saniyede 15 kare hızında karşılaştırmak için kullanabilirsiniz.

Konum için, animasyon kareleri arasında zamanda ne kadar yakın olduğumuza bağlı olarak bir önceki animasyon karesi ile sonraki arasında doğrusal bir interpolasyon yaparız (oran):

const { x: x1, y: y1, z: z1 } = getPosition(previous, performanceIndex, limbIndex);
const { x: x2, y: y2, z: z2 } = getPosition(next, performanceIndex, limbIndex);
interpolatedPosition = new THREE.Vector3();
interpolatedPosition.set(
    x1 + (x2 - x1) * ratio,
    y1 + (y2 - y1) * ratio,
    z1 + (z2 - z1) * ratio
    );

Yön için, animasyon kareleri arasında küresel doğrusal interpolasyon (slerp) yaparız. Yön, Quaternions olarak depolanır.

const quaternion = getQuaternion(previous, performanceIndex, limbIndex);
quaternion.slerp(
    getQuaternion(next, performanceIndex, limbIndex),
    ratio
    );

5. Hareketler müzikle senkronize ediliyor

Kaydedilen animasyonların hangi karesinde oynatılacağını bilmek için müziğin geçerli zamanını milisaniyeye kadar bilmemiz gerekir. HTML Ses öğesi, aşamalı olarak yükleme ve ses çalma için mükemmel olsa da, sağladığı zaman özelliği, tarayıcının kare döngüsüyle senkronize olarak değişmemiştir. Bu durum her zaman biraz sapmadır. Bazen 1 ms.lik bir bölüm çok erken, bazen de çok geç bir bölümdür.

Bu, her ne pahasına olursa olsun engellemek istediğimiz güzel dans kayıtlarımızda kepenklere neden oluyor. Bu durumu düzeltmek için JavaScript'te kendi zamanlayıcımızı uyguladık. Bu şekilde, kareler arasındaki geçiş süresinin tam olarak son kareden bu yana geçen süre olduğundan emin olabiliriz. Zamanlayıcımızın müzikle senkronizasyonu 10 ms'yi aştığında tekrar senkronize ederiz.

6. Yokuşlar ve sis

Her hikayenin iyi bir sonla bitmesi gerekir. Bu nedenle, deneyimimizin sonuna kadar ulaşan kullanıcılar için şaşırtıcı bir şey yapmak istedik. Son odadan çıkarken koniler ve silindirlerden oluşan sessiz bir manzaraya giriyorsunuz. "Bu son mu?" diye merak ediyorsunuz. Sahada ilerledikçe aniden müziğin tonları farklı koni grupları ve silindirlerle dansçılara dönüşür. Kendinizi büyük bir partinin ortasında buluyorsunuz. Sonra müzik aniden durduğunda her şey yere düşüyor.

Bu durum bir izleyici olarak çok iyi hissetse de performansla ilgili bazı engelleri ortadan kaldırdı. Oda ölçeğinde VR cihazları ve ileri teknoloji oyun araçları, yeni sonu için gereken 40 tuhaf ekstra performansla mükemmel bir performans gösterdi. Ancak bazı mobil cihazlardaki kare hızları yarıya indi.

Bu sorunu önlemek için sisli havayı kullanmaya başladık. Belirli bir mesafeden sonra her şey yavaşça kararmaya başlıyor. Görünmeyen bir şeyi hesaplamamız veya çizmemiz gerekmediği için, görünür olmayan odalardaki performansları keseriz ve bu da hem CPU hem de GPU için yapılan işlerden tasarruf etmemizi sağlar. Peki doğru mesafeye nasıl karar vereceksiniz?

Bazı cihazlar onlara attığınız her şeyi işleyebilir, bazıları ise daha kısıtlıdır. Bir kayan ölçek uygulamayı tercih ettik. Saniyedeki kare miktarını sürekli olarak ölçerek sis mesafemizi buna göre ayarlayabiliriz. Kare hızımız sorunsuz çalıştığı sürece sisi uzaklaştırarak daha fazla oluşturma işi üstlenmeye çalışırız. Kare hızı yeterince pürüzsüz değilse sisi yaklaştırırız. Böylece karanlıkta görüntü oluşturma performansını atlayabiliriz.

// this is called every frame
// the FPS calculation is based on stats.js by @mrdoob
tick: (interval = 3000) => {
    frames++;
    const time = (performance || Date).now();
    if (prevTime == null) prevTime = time;
    if (time > prevTime + interval) {
    fps = Math.round((frames * 1000) / (time - prevTime));
    frames = 0;
    prevTime = time;
    const lastCullDistance = settings.cullDistance;

    // if the fps is lower than 52 reduce the cull distance
    if (fps <= 52) {
        settings.cullDistance = Math.max(
        settings.minCullDistance,
        settings.cullDistance - settings.roomDepth
        );
    }
    // if the FPS is higher than 56, increase the cull distance
    else if (fps > 56) {
        settings.cullDistance = Math.min(
        settings.maxCullDistance,
        settings.cullDistance + settings.roomDepth
        );
    }
    }

    // gradually increase the cull distance to the new setting
    cullDistance = cullDistance * 0.95 + settings.cullDistance * 0.05;

    // mask the edge of the cull distance with fog
    viewer.fog.near = cullDistance - settings.roomDepth;
    viewer.fog.far = cullDistance;
}

Herkes için bir şeyler: Web için VR geliştirme

Çoklu platform ve asimetrik deneyimler tasarlamak ve geliştirmek, her kullanıcının cihazlarına bağlı olarak ihtiyaçlarını dikkate almak anlamına gelir. Her tasarım kararında, bunun diğer kullanıcıları nasıl etkileyebileceğini görmemiz gerekiyordu. VR'de gördüklerinizin, sanal gerçeklik olmadan olduğu kadar heyecan verici olmasını nasıl sağlarsınız?

1. Sarı küre

Yani, oda ölçeğindeki VR kullanıcılarımız performansları gerçekleştirirdi. Peki, mobil VR cihazlarının (Cardboard, Daydream View veya Samsung Gear gibi) kullanıcıları projeyi nasıl deneyimleyecek? Bunun için çevremize yeni bir öğe sunduk: sarı küre.

Sarı küre
Sarı küre

Projeyi sanal gerçeklikte izlediğinizde, bunu sarı kürenin bakış açısından yaparsınız. Odadan odaya süzülürken dansçılar varlığınıza tepki verir. Size jestler yapar, etrafınızda dans eder, arkanızdan komik hareketler yapar ve size çarpmamaları için hızlıca yolunuzdan çekilirler. Sarı küre her zaman dikkatin merkezindedir.

Bunun nedeni, bir performans kaydedilirken sarı kürenin müzikle senkronize olarak odanın ortasında hareket etmesi ve döngüye geri dönmesidir. Kürenin konumu, sanatçıya zamanında nerede oldukları ve döngülerinde ne kadar zamanları kaldığına dair fikir verir. Çevresinde bir performans oluşturmaları için doğal bir odak noktası sağlar.

2. Başka bir bakış açısı

Özellikle de büyük kitlemiz büyük olasılıkla, VR'ye sahip olmayan kullanıcıları oyun dışında bırakmak istemedik. Gerçekmiş bir VR deneyimi oluşturmak yerine, ekran tabanlı cihazlara kendi deneyimlerini sunmak istedik. Yukarıdan performansları izometrik bir bakış açısıyla göstermeyi düşünmüştük. Bu bakış açısı, bilgisayar oyunlarında zengin bir geçmişe sahip. İlk olarak 1982'den kalma bir uzay nişan oyunu olan Zaxxon'da kullanılmıştır. Ancak sanal gerçeklik kullanıcıları bambaşka bir bakış açısı sunarken izometrik bakış açısı, aksiyonu tanrısal bir bakış açısıyla gösteriyor. Modellerin ölçeğini biraz artırmayı ve oyuncak bebek evi estetiğine katkı sağlamayı seçtik.

3. Gölgeler: yapana kadar taklit et

Bazı kullanıcılarımızın izometrik bakış açısının derinliğini görmekte zorlandığını fark ettik. Bu nedenle Zaxxon'un aynı zamanda tarihte uçan nesnelerin altında dinamik bir gölge yansıtan ilk bilgisayar oyunlarından biri olması da çok eminim.

Gölgeler

3D modda gölge oluşturmanın zor olduğu ortaya çıktı. Özellikle cep telefonları gibi kısıtlanmış cihazlar için. Başlangıçta bunları denklemden çıkarmak için zor bir karar vermemiz gerekiyordu, ancak Three.js'nin yazarından ve deneyimli demo bilgisayar korsanı Mr Doob'un tavsiyelerini istedikten sonra, onları taklit etme gibi yeni bir fikir buldu.

Yüzen nesnelerimizin her birinin ışıklarımızı nasıl engellediğini ve böylece farklı şekillerde gölgeler attığını hesaplamak zorunda kalmadan her birinin altına aynı dairesel bulanık doku resmini çizeriz. Görsellerimiz gerçeği taklit etmeye çalışmadığı için, yalnızca birkaç küçük ayarla çok kolay bir şekilde başa çıkmayı başardık. Nesneler zemine yaklaştıkça dokular daha koyu ve küçülür. Yukarı hareket ettiklerinde, dokuları daha şeffaf ve büyütür hale getiririz.

Bunları oluşturmak için bu dokuyu yumuşak beyazdan siyaha bir gradyanla (alfa şeffaflığı olmadan) kullandık. Malzemeyi şeffaf olarak ayarlıyoruz ve çıkarma yaparak karıştırmayı kullanıyoruz. Böylece üst üste binen kişileri harmanlamak mümkün olur:

function createShadow() {
    const texture = new THREE.TextureLoader().load(shadowTextureUrl);
    const material = new THREE.MeshLambertMaterial({
        map: texture,
        transparent: true,
        side: THREE.BackSide,
        depthWrite: false,
        blending: THREE.SubtractiveBlending,
    });
    const geometry = new THREE.PlaneBufferGeometry(0.5, 0.5, 1, 1);
    const plane = new THREE.Mesh(geometry, material);
    return plane;
    }

4. Orada olmak

VR videosu olmayan ziyaretçiler, bir sanatçının kafasını tıklayarak dansçının bakış açısından bunları izleyebilir. Bu açıdan bakıldığında çok sayıda küçük ayrıntı ortaya çıkıyor. Birlikte performans göstermeye çalışan dansçılar birbirlerine hızlıca bakıyorlar. Küre odaya girerken gergin bir şekilde başka yöne bakıyor. İzleyici olarak bu hareketleri etkileyemeseniz de içeriye girme hissini şaşırtıcı derecede iyi yansıtıyor. Yine, bunu kullanıcılarımıza fare kontrollü yalan bir sahte VR sürümü sunmak yerine yapmayı tercih ettik.

5. Kayıtları paylaşma

Birbirine tepki veren 20 katmanın olduğu koreografiye sahip karmaşık bir kaydı hazırlarken ne kadar gurur duyabileceğinizi çok iyi biliyoruz. Kullanıcılarımızın muhtemelen bunu arkadaşlarına göstermek isteyeceklerini biliyorduk. Ancak bu başarının hareketsiz bir resmi yeterince anlatıcı olmaz. Bunun yerine, kullanıcılarımızın performanslarının videolarını paylaşmalarını istedik. Aslına bakarsan neden GIF olmasın? Animasyonlarımız düz gölgelendirildiğinden, biçimin sınırlı renk paletleri için mükemmeldir.

Kayıtları paylaşma

Tarayıcıdan animasyonlu GIF'leri kodlamanıza olanak tanıyan bir JavaScript kitaplığı olan GIF.js'yi kullanmayı tercih ettik. Çerçevelerin kodlanmasını, arka planda ayrı işlemler olarak çalışabilen web çalışanlarına boşaltır. Böylece yan yana çalışan birden fazla işlemciden yararlanabilir.

Ne yazık ki animasyonlar için ihtiyacımız olan kare sayısı göz önünde bulundurulduğunda kodlama işlemi de çok yavaştı. GIF, sınırlı bir renk paleti kullanarak küçük dosyalar oluşturabilir. Çoğunlukla, her bir piksel için en yakın rengi bulmakla harcandığını gördük. Küçük bir kısa sürede saldırarak bu işlemi on kat optimize edebildik: Pikselin rengi bir öncekiyle aynıysa Paletteki rengin aynısını kullanın.

Artık hızlı kodlamalar yapıyorduk ancak ortaya çıkan GIF dosyalarının boyutu çok büyüktü. GIF biçimi, atma yöntemini tanımlayarak her bir karenin bir öncekinin üzerinde nasıl görüntüleneceğini belirtmenize olanak tanır. Daha küçük dosyalar almak için her bir kareyi her bir pikseli güncellemek yerine, yalnızca değişen pikselleri güncelleriz. Kodlama sürecini yeniden yavaşlatırken bu işlem dosya boyutlarımızı da iyi bir şekilde düşürdü.

6. Sağlam bir temel: Google Cloud ve Firebase

"Kullanıcı tarafından oluşturulan içerik" sitelerinin arka ucu genellikle karmaşık ve kırılgan olabilir. Ancak Google Cloud ve Firebase sayesinde basit ve sağlam bir sistem bulduk. Bir sanatçı sisteme yeni bir dans yüklediğinde, kimliği Firebase Authentication tarafından anonim olarak doğrulanır. Kullanıcılara, Cloud Storage for Firebase'i kullanarak kayıtlarını geçici bir alana yükleme izni verilir. Yükleme tamamlandığında istemci makinesi, Firebase jetonunu kullanarak bir Cloud Functions for Firebase HTTP tetikleyicisi çağırır. Bu işlem, gönderimi doğrulayan, veritabanı kaydı oluşturan ve kaydı Google Cloud Storage'daki herkese açık bir dizine taşıyan bir sunucu işlemini tetikler.

Düz zemin

Herkese açık içeriklerimizin tamamı, bir Cloud Storage Paketinde bir dizi düz dosya içinde depolanır. Bu sayede verilerimize dünyanın her yerinden hızlıca erişilebiliyor ve veri kullanılabilirliğini etkileyen yüksek trafik yükleri hakkında endişelenmemize gerek yok.

Her yeni gönderimi VR'da izlememize ve herhangi bir cihazdan yeni oynatma listeleri yayınlamamıza olanak tanıyan basit bir moderasyon/seçme aracı geliştirmek için Firebase Realtime Database ve Cloud Function uç noktaları kullandık.

7. Hizmet Çalışanları

Hizmet çalışanları, web sitesi öğelerinin önbelleğe alınmasını yönetmeye yardımcı olan oldukça yeni bir yeniliktir. Örneğimizde hizmet işçileri, içeriğimizi geri gelen ziyaretçiler için ışık hızında yüklüyor ve hatta sitenin çevrimdışı çalışmasına olanak tanıyor. Ziyaretçilerinizin birçoğu çeşitli kalitelerde mobil bağlantılar kullanacağı için bunlar önemli özelliklerdir.

Zor işlerin çoğunu üstlenen kullanışlı bir web paketi eklentisi sayesinde projeye Service Worker eklemek çok kolay oldu. Aşağıdaki yapılandırmada, tüm statik dosyalarımızı otomatik olarak önbelleğe alacak bir hizmet çalışanı oluşturuyoruz. Oynatma listesi sürekli güncelleneceği için, varsa ağdan en son oynatma listesi dosyasını alır. Hiçbir zaman değişmeyeceğinden, tüm kayıt json dosyaları varsa önbellekten çekilmelidir.

const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
config.plugins.push(
    new SWPrecacheWebpackPlugin({
    dontCacheBustUrlsMatching: /\.\w{8}\./,
    filename: 'service-worker.js',
    minify: true,
    navigateFallback: 'index.html',
    staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
    runtimeCaching: [{
        urlPattern: /playlist\.json$/,
        handler: 'networkFirst',
    }, {
        urlPattern: /\/recordings\//,
        handler: 'cacheFirst',
        options: {
        cache: {
            maxEntries: 120,
            name: 'recordings',
        },
        },
    }],
    })
);

Şu anda eklenti, müzik dosyalarımız gibi kademeli olarak yüklenen medya öğelerini işlememektedir. Bu yüzden, bu dosyalardaki Cloud Storage Cache-Control başlığını public, max-age=31536000 olarak ayarlayarak tarayıcının dosyayı bir yıla kadar önbelleğe almasını sağladık.

Sonuç

Sanatçıların bu deneyime nasıl katkıda bulunacağını ve bunu, hareketi kullanarak yaratıcı bir şekilde ifade etmek için bir araç olarak kullanacaklarını görmekten heyecan duyuyoruz. Açık kaynaklı tüm kodları kullanıma sunduk. Bunları https://github.com/puckey/dance-tonite adresinde bulabilirsiniz. VR'nin ve özellikle WebVR'nin bu ilk günlerinde, bu yeni ortamın ne gibi yeni yaratıcı ve beklenmedik yönleri görmeyi sabırsızlıkla bekliyoruz. Dansınıza başlayın.