Google Veri Sanatları ekibi, Moniker'e ve bana WebVR'nin sunduğu olanakları keşfetmek üzere birlikte çalışma konusunda yaklaştığında heyecan duydum. Ekiplerinin yıllar içinde ortaya koyduğu çalışmaları izledim ve projeleri her zaman ilgimi çekti. Ortak çalışmamız, LCD Soundsystem ve takipçilerinin yer aldığı, sürekli değişen bir VR dans deneyimi olan Dance Tonite'i ortaya çıkardı. Bunu nasıl başardığımızı burada açıklıyoruz.
Kavram
Tarayıcınızı kullanarak bir web sitesini ziyaret ederek VR'ye girmenizi sağlayan açık bir standart olan WebVR'yi kullanarak bir dizi prototip geliştirmeye başladık. Amacımız, hangi cihazı kullandığınızdan bağımsız olarak herkesin VR deneyimlerine erişmesini kolaylaştırmaktır.
Bu konuyu dikkate aldık. Geliştirdiğimiz özellikler, Google Daydream View, Cardboard ve Samsung Gear VR gibi cep telefonlarıyla çalışan VR başlıklardan HTC VIVE ve Oculus Rift gibi sanal ortamınızdaki fiziksel hareketlerinizi yansıtan oda ölçekli sistemlere kadar tüm VR türlerinde çalışmalıdır. Belki de en önemlisi, VR cihazı olmayan herkes için de çalışacak bir şey üretmenin web'in ruhuna uygun olacağını düşündük.
1. Kendin yap hareket yakalama
Kullanıcıları yaratıcı bir şekilde dahil etmek istediğimizden, VR'yi kullanarak katılım ve kendini ifade etme olanaklarını araştırmaya başladık. VR'de ne kadar hassas bir şekilde hareket edebileceğinize ve etrafınıza bakabildiğinize, ayrıca ne kadar gerçekçi bir deneyime sahip olduğunuza hayran kaldık. Bu durum bize bir fikir verdi. Kullanıcıların bir şeye bakmasını veya bir şey oluşturmasını sağlamak yerine hareketlerini kaydetmeye ne dersiniz?
Dans sırasında VR gözlüklerimizin ve kumandalarımızın pozisyonlarını kaydettiğimiz bir prototip hazırladık. Kayıtlı konumları soyut şekillerle değiştirdik ve sonuçları hayrete düşürdük. Sonuçlar çok gerçekçi ve çok kişilikliydi. WebVR'yi kullanarak evde düşük maliyetli hareket yakalama yapabileceğimizi kısa sürede fark ettik.
WebVR ile geliştirici, VRPose nesnesi aracılığıyla kullanıcının kafasının konumuna ve yönüne erişebilir. Bu değer, kodunuzun doğru bakış açısından yeni kareler oluşturabilmesi için her karede VR donanımı tarafından güncellenir. WebVR ile GamePad API aracılığıyla, GamepadPose nesnesi üzerinden kullanıcıların kontrol cihazlarının konumuna/yönüne de erişebiliriz. Bu konum ve yön değerlerinin tümünü her karede depolarız. Böylece kullanıcının hareketlerinin "kaydı" oluşturulur.
2. Minimalizm ve kostümler
Günümüzde oda ölçekli VR ekipmanlarıyla kullanıcının vücudundaki üç noktayı (kafa ve iki el) izleyebiliyoruz. Dance Tonite'te, odak noktamızı bu 3 noktanın uzayda hareketindeki insaniliğe odaklamak istedik. Bu amaç doğrultusunda, harekete odaklanabilmek için estetiği mümkün olduğunca minimum seviyeye getirdik. Kullanıcıların beyinlerini kullanma fikrini sevdik.
İsveçli psikolog Gunnar Johansson'un çalışmalarını gösteren bu video, mümkün olduğunca sade bir tasarım oluşturmak için yararlandığımız örneklerden biriydi. Bu grafik, yüzen beyaz noktaların hareket halindeyken nasıl anında cisim olarak tanınabildiğini göstermektedir.
Margarete Hastings’in 1970'te Oskar Schlemmer’ın Triadic Bale'sini yeniden yorumladığı bu kayıtta görsel olarak renkli odalar ve geometrik kostümler bize ilham verdi.
Schlemmer'in soyut geometrik kostümleri seçmesinin nedeni, dansçılarının hareketlerini kukla ve kuklaların hareketleriyle sınırlamaktı. Dance Tonite için ise tam tersini hedefledik.
Şekil seçimimizi, döndürüldüklerinde ne kadar bilgi aktardıklarına göre yaptık. Küre nasıl döndürüldüğünden bağımsız olarak aynı görünür ancak koni gerçekte baktığı yönde işaret eder ve arkadan farklı görünür.
3. Hareket için döngü pedalı
Birlikte dans eden ve hareket eden kalabalık grupların yer aldığı kayıtlar kullanmak istedik. VR cihazlar yeterince yaygın olmadığından bunu canlı olarak yapmak mümkün değil. Ama yine de, bir grubun hareket aracılığıyla birbirine tepki vermesini istiyorduk. Norman McClaren'ın 1964 tarihli "Canon" adlı video eserinde yaptığı yinelemeli performans aklımıza geldi.
McClaren'ın performansında, her döngüden sonra birbirleriyle etkileşime geçmeye başlayan, son derece koreografili bir dizi hareket yer alıyor. Müzikte, müzisyenlerin farklı canlı müzik parçalarını katmanlayarak kendileriyle birlikte doğaçlama yaptığı bir döngü pedalı gibi, kullanıcıların performansların daha rahat versiyonlarını özgürce doğaçlayabileceği bir ortam oluşturmayı denemek istedik.
4. Birbirine bağlı odalar
Birçok müzik gibi LCD Soundsystem'in parçaları da tam olarak zamanlanmış ölçüler kullanılarak oluşturulur. Projemizde yer alan Tonite adlı parçalarında tam 8 saniye uzunluğunda ölçümler kullanılıyor. Kullanıcıların parçadaki her 8 saniyelik döngü için performans göstermesini istedik. Bu ölçümlerin ritmi değişmese de müzik içeriği değişmektedir. Şarkı ilerledikçe farklı enstrümanlar ve vokallerin kullanıldığı, sanatçıların farklı şekillerde tepki verebileceği anlar vardır. Bu ölçümlerin her biri, kullanıcıların uygun performansı sergileyebileceği bir oda olarak ifade edilir.
Performans optimizasyonları: Kareleri bırakmayın
Tek bir kod tabanında çalışan ve her cihaz veya platform için optimum performans sunan çok platformlu bir VR deneyimi oluşturmak kolay bir iş değildir.
VR'de karşılaşabileceğiniz en rahatsız edici şeylerden biri, kare hızının hareketinize ayak uyduramaması nedeniyle ortaya çıkar. Başınızı çevirdiğinizde gözlerinizin gördüğü görseller, iç kulağınızın algıladığı hareketle eşleşmezse mideniz hemen bulanmaya başlar. Bu nedenle, büyük kare hızı gecikmeleri yaşamamak için dikkatli davranmamız gerekiyordu. Uyguladığımız bazı optimizasyonları aşağıda bulabilirsiniz.
1. Oluşturulan tampon geometrisi
Projemizin tamamında yalnızca birkaç 3D nesne kullanıldığı için Instanced Buffer Geometry'yi kullanarak performansı büyük ölçüde artırabildik. Temel olarak, nesnenizi GPU'ya bir kez yüklemenize ve tek bir çizim çağrısında bu nesnenin istediğiniz kadar "örnek"ini çizmenize olanak tanır. Dance Tonite'te yalnızca 3 farklı nesne (koni, silindir ve delik bulunan oda) var ancak bu nesnelerin yüzlerce kopyası olabilir. Örneklendirilmiş Arabellek Geometrisi, ThreeJS'nin bir parçasıdır ancak THREE.InstanceMesh
'i uygulayan Dusan Bosnjak'ın deneysel ve devam eden çatalını kullandık. Bu, Örneklendirilmiş Arabellek Geometrisi ile çalışmayı çok daha kolay hale getirir.
2. Çöp toplayıcıdan kaçınma
Diğer birçok komut dosyası dilinde olduğu gibi JavaScript de hangi ayrılmış nesnelerin artık kullanılmadığını tespit ederek belleği otomatik olarak boşaltır. Bu sürece atık toplama adı verilir.
Geliştiricilerin bu durumun ne zaman gerçekleşeceği üzerinde herhangi bir kontrolü yoktur. Çöp toplayıcı, istediği zaman kapımıza gelip çöpleri boşaltmaya başlayabilir. Bu da, işlerini yavaşça yaptıkları için karelerin atlanmasına neden olur.
Bunun çözümü, eşyalarımızı geri dönüştürerek mümkün olduğunca az çöp üretmektir. Her hesaplama için yeni bir vektör nesnesi oluşturmak yerine, Scratch nesnelerini yeniden kullanılmak üzere işaretledik. Bu kaynaklara referansımızı kapsamımızın dışına taşıyarak bu kaynakları sakladığımızdan, kaldırılmak üzere işaretlenmediler.
Örneğin, kullanıcının kafası ve ellerinin konum matrisini her karede depoladığımız konum/döndürme değerleri dizisine dönüştüren kodumuz aşağıda verilmiştir. SERIALIZE_POSITION
, SERIALIZE_ROTATION
ve SERIALIZE_SCALE
öğelerini yeniden kullanarak işlev her çağrıldığında yeni nesneler oluşturacak olsaydık gerçekleşecek bellek ayırma ve çöp toplama işlemlerinden kaçınıyoruz.
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'da kullanıcıların hareketlerini yakalamak için mikrofonlu kulaklıklarının ve kumandalarının konumunu ve dönüşünü serileştirmemiz ve bu verileri sunucularımıza yüklememiz gerekiyordu. Her kare için dönüşüm matrislerini eksiksiz bir şekilde yakalamaya başladık. Bu iyi bir performans gösterdi ancak her biri saniyede 90 kare hızında 16 sayının 3 konumla çarpılmasıyla ortaya çıkan çok büyük dosyalar, dolayısıyla da verilerin yüklenmesi ve indirilmesi sırasında uzun bekleme sürelerine yol açıyordu. Dönüşüm matrislerinden yalnızca konumsal ve rotasyonlu verileri çıkararak bu değerleri 16’dan 7’ye indirebildik.
Web'deki ziyaretçiler genellikle tam olarak neyle karşılaşacaklarını bilmeden bir bağlantıyı tıkladığından, görsel içeriği hızlı bir şekilde göstermemiz gerekir. Aksi takdirde ziyaretçiler birkaç saniye içinde siteyi terk eder.
Bu nedenle, projemizin mümkün olan en kısa sürede oynatılabileceğinden emin olmak istedik. Başlangıçta, hareket verilerimizi yüklemek için biçim olarak JSON kullanıyorduk. Sorun şu ki, dosyayı ayrıştırabilmemiz için önce JSON dosyasının tamamını yüklememiz gerekir. Pek ilerici değil.
Dans Tonite gibi bir projenin mümkün olan en yüksek kare hızında görüntülenmesini sağlamak için, JavaScript hesaplamaları için tarayıcının her karede yalnızca kısa bir süresi vardır. Çok uzun sürerse animasyonlar takılmaya başlar. İlk başta, bu büyük JSON dosyalarının tarayıcı tarafından kodu çözüldüğü için takılmalar yaşıyorduk.
NDJSON veya satır sonu ile ayrılmış JSON adlı uygun 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, dosyayı yüklenirken ayrıştırmanıza, böylece performansları tam olarak yüklenmeden önce görüntülememize olanak tanır.
Kayıtlarımızdan birinin bir bölümünü aşağıda görebilirsiniz:
{"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 kullanmak, performansların ayrı karelerinin veri temsilini dize olarak tutmamıza olanak tanır. Gerekli zamana ulaşana kadar bekleyip kodlarını konumsal verilere dönüştürerek gerekli işlemleri zamana yayabiliriz.
4. Hareketi ara değerle belirleme
Aynı anda 30 ila 60 performansı göstermeyi umduğumuz için veri hızımızı daha da düşürmemiz gerekiyordu. Veri Sanatları Ekibi, Virtual Art Sessions projesinde aynı sorunu ele aldı. Bu projede, eğerek eğimli boya ile resim yapan sanatçıların kayıtlarını yeniden oynattılar. 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 ara değer hesaplama yaparak çözdüler. 15 FPS'de çalışan bir ara kayıt ile orijinal 90 FPS kayıt arasında neredeyse fark göremedik.
Bunu kendiniz görmek isterseniz, ?dataRate=
sorgu dizesini kullanarak Dance Tonite'ı verileri çeşitli oranlarda oynatmaya zorlayabilirsiniz. Bu seçeneği, kaydedilen hareketi saniyede 90 kare, saniyede 45 kare veya saniyede 15 kare olarak karşılaştırmak için kullanabilirsiniz.
Konum için, animasyon kareleri arasındaki zamanda ne kadar yakın olduğumuza (oran) dayanarak önceki animasyon karesi ile sonraki arasında doğrusal bir interpolasyon yaparız:
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önlendirme, quaternion olarak depolanır.
const quaternion = getQuaternion(previous, performanceIndex, limbIndex);
quaternion.slerp(
getQuaternion(next, performanceIndex, limbIndex),
ratio
);
5. Hareketleri müzikle senkronize etme
Kaydedilen animasyonların hangi karesinin oynatılacağını bilmek için, müziğin mevcut zamanını milisaniyeye kadar indirmemiz gerekir. HTML ses öğesi, sesi kademeli olarak yüklemek ve oynatmak için mükemmel olsa da sağladığı zaman özelliği, tarayıcının çerçeve döngüsüyle senkronize olarak değişmiyor. Bu değer her zaman biraz sapma gösterir. Bazen milisaniyenin bir kısmından daha erken, bazen de bir kısmından daha geç olur.
Bu durum, güzel dans kayıtlarımızda takılmalara neden olur. Bu tür sorunlardan her ne pahasına olursa olsun kaçınmak isteriz. Bu sorunu gidermek için JavaScript'te kendi zamanlayıcımızı uyguladık. Bu şekilde, kareler arasında değişen sürenin tam olarak son kareden bu yana geçen süre olduğundan emin olabiliriz. Zamanlayıcımızın 10 ms.den fazla mesafesi müzikle senkronizasyonu bozulduğunda, zamanlayıcıyı tekrar senkronize ederiz.
6. Sis ve sis
Her hikayenin iyi bir sonu olması gerekir. Bu nedenle, deneyimimizin sonuna kadar gelen kullanıcılar için şaşırtıcı bir şey yapmak istedik. Son odadan çıkarken koni ve silindirlerden oluşan sessiz bir manzaraya girersiniz. "Bu son mu?" diye merak ediyorsunuz. Alana daha da yaklaştığınızda müziğin tonları, farklı koni ve silindir gruplarının dansçılara dönüşmesine neden olur. Kendinizi büyük bir partinin ortasında bulursunuz. Ardından müzik aniden durduğunda her şey yere düşer.
İzleyici olarak bu durum çok iyi hissettirse de çözülmesi gereken bazı performans sorunları ortaya çıktı. Oda ölçeğinde sanal gerçeklik cihazları ve bunların ileri teknoloji oyun ekipmanları, yeni kuruluşumuz için gereken 40 tuhaf ekstra performansla mükemmel bir performans gösterdi. Ancak belirli mobil cihazlardaki kare hızları yarıya düşürüldü.
Bununla mücadele etmek için sis özelliğini kullanıma sunduk. Belirli bir mesafeden sonra her şey yavaş yavaş siyah olur. Görünmeyen şeyleri hesaplamamız veya çizmemiz gerekmediğinden, görünmeyen odalardaki performansları toplarız. Bu da hem CPU hem de GPU için iş gücünden tasarruf etmemizi sağlar. Peki doğru mesafeye nasıl karar verilir?
Bazı cihazlar onlara yerleştirdiğiniz her şeyi işleyebilir, bazıları ise daha kısıtlamaya tabidir. Kaydırma ölçeği uygulamayı tercih ettik. Saniyedeki kare sayısını sürekli olarak ölçerek sisimizin mesafesini buna göre ayarlayabiliriz. Kare hızımız sorunsuz bir şekilde çalıştığı sürece, sis etkisini azaltarak daha fazla oluşturma işlemi gerçekleştirmeye çalışıyoruz. Kare hızı yeterince akıcı değilse karanlıkta oluşturma performanslarını atlamamıza olanak tanıyan sisi yaklaştırırız.
// 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 oluşturma
Çok platformlu, asimetrik deneyimler tasarlamak ve geliştirmek, her kullanıcının cihazına göre ihtiyaçlarını hesaba katmak anlamına gelir. Her tasarım kararının diğer kullanıcıları nasıl etkileyebileceğini de göz önünde bulundurmamız gerekiyordu. VR'de gördüklerinizin VR'siz gördüklerinizle aynı derecede heyecan verici olmasını nasıl sağlarsınız?
1. Sarı küre
Oda ölçekli VR kullanıcılarımız performansları yapacak. Peki mobil VR cihazlarının (Cardboard, Daydream View veya Samsung Gear gibi) kullanıcıları projeyi nasıl deneyimleyecek? Bunun için ortamımıza yeni bir öğe ekledik: sarı top.
Projeyi VR'de izlerken sarı kürenin bakış açısından izlersiniz. Odadan odaya geçerken dansçılar varlığınıza tepki verir. Size işaretler yapar, etrafınızda dans eder, arkanızda komik hareketler yapar ve size çarpmamak için hızlıca yolunuzdan çekilir. Sarı küre her zaman dikkatin merkezidir.
Bunun nedeni, performans kaydederken sarı kürenin müzikle senkronize olarak odanın ortasında hareket etmesi ve tekrar dönmesidir. Kürenin konumu, sanatçıya zaman içinde nerede oldukları ve döngülerinde ne kadar zamanları kaldığını gösterir. Bu, performans oluşturmak için doğal bir odak noktası sağlar.
2. Başka bir bakış açısı
Özellikle en büyük kitlemiz olacağı için, sanal gerçekliği olmayan kullanıcıları dışarıda bırakmak istemedik. Sahte bir VR deneyimi yerine, ekrana dayalı cihazlara özel bir deneyim sunmak istedik. Performansları yukarıdan, izometrik bir perspektiften gösterme fikrini ortaya attık. Bu bakış açısının bilgisayar oyunlarında zengin bir geçmişi vardır. İlk olarak 1982'de uzay nişancısı oyunu olan Zaxxon'da kullanıldı. VR kullanıcıları tam ortasındayken izometrik perspektif, aksiyona tanrısal bir bakış açısı sunar. Modelleri biraz büyüterek oyuncak evi estetiğine bir dokunuş katmayı tercih ettik.
3. Gölgeler: Başarılı olana kadar rol yapma
Bazı kullanıcılarımızın, izometrik bakış açımızda derinliği görmede zorlandığını tespit ettik. Zaxxon'un, tarihte uçan cisimlerinin altında dinamik gölge yansıtan ilk bilgisayar oyunlarından biri olmasının nedeninin bu olduğundan eminim.
3D gölgeler oluşturmak zor bir iş. Özellikle cep telefonları gibi kısıtlanmış cihazlarda. İlk başta, bunları denklemden çıkarmak gibi zor bir karar vermek zorunda kaldık. Ancak Three.js'in yazarı ve deneyimli demo korsanı Mr doob'dan tavsiye aldıktan sonra, bunları taklit etme fikrini ortaya attı.
Yüzen nesnelerimizin her birinin ışıklarımızı nasıl engellediğini ve dolayısıyla farklı şekillerde gölgeler oluşturduğunu hesaplamak yerine, her birinin altına aynı dairesel bulanık doku resmini çizeriz. Görsellerimiz gerçekliği taklit etmeye çalışmadığından, birkaç küçük ayar yaparak bu sorunu kolayca çözebileceğimizi fark ettik. Nesneler yere yaklaştıkça dokuların daha koyu ve daha küçük olmasını sağlarız. Yukarı doğru hareket ettiklerinde dokuları daha şeffaf ve daha büyük hale getiririz.
Bu efektleri oluşturmak için yumuşak bir beyazdan siyaha geçiş (alfa şeffaflığı olmadan) içeren bu doku kullanıldı. Malzemeyi şeffaf olarak ayarlıyoruz ve çıkarmalı karışım kullanıyoruz. Böylece bir araya gelip mükemmel bir şekilde bir araya gelebilirler:
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 olma
VR'si olmayan ziyaretçiler, bir sanatçının kafalarını tıklayarak içerikleri dansçının bakış açısından izleyebiliyor. Bu açıdan bakıldığında birçok küçük ayrıntı ortaya çıkar. Dansçılar, performanslarını uyumlu tutmaya çalışırken birbirlerine hızlıca göz atıyor. Küre odaya girerken gergin bir şekilde küreye doğru baktığını görürsünüz. İzleyici olarak bu hareketleri etkileyemezsiniz, ancak videoların içine çekme hissini şaşırtıcı derecede iyi biçimde iletiyorsunuz. Bu nedenle, kullanıcılarımıza fareyle kontrol edilen, gerçekçi olmayan bir VR sürümü sunmak yerine bunu yapmayı tercih ettik.
5. Kayıtları paylaşma
Birbirine tepki veren 20 katmanlı bir performansçının yer aldığı, karmaşık bir koreografiyle çekilmiş bir videoyu tamamladığınızda ne kadar gurur duyabileceğinizi biliyoruz. Kullanıcılarımızın bu videoları arkadaşlarına göstermek isteyeceğini biliyorduk. Ancak bu başarının hareketsiz bir resmi yeterli bilgi vermiyor. Bunun yerine, kullanıcılarımızın performanslarının videolarını paylaşmalarına izin vermek istedik. Aslında neden GIF olmasın? Animasyonlarımız düz gölgelidir ve biçimin sınırlı renk paletleri için mükemmeldir.
Animasyonlu GIF'leri tarayıcıdan kodlamanıza olanak tanıyan bir JavaScript kitaplığı olan GIF.js'ye yöneldik. Ç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.
Maalesef animasyonlar için ihtiyaç duyduğumuz kare sayısı nedeniyle kodlama işlemi hâlâ çok yavaştı. GIF, sınırlı bir renk paleti kullanarak küçük dosyalar oluşturabilir. Her piksel için en yakın rengi bulmak için çoğu zamanın harcandığını tespit ettik. Küçük bir kısa kesme yaparak bu işlemi on kat optimize etmeyi başardık: Pikselin rengi sonuncuyla aynıysa paletteki rengin aynısını kullanın.
Kodlama işlemleri artık hızlı olsa da sonuçta 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 elde etmek için her bir pikseli her karede güncellemek yerine yalnızca değişen pikselleri güncelleriz. Bu, kodlama sürecini tekrar yavaşlattı ancak dosya boyutlarımızı önemli ölçüde düşürdü.
6. Sağlam zemin: Google Cloud ve Firebase
"Kullanıcı tarafından oluşturulan içerik" barındıran bir sitenin arka ucu, genellikle karmaşık ve kırılgan olabiliyor. Ancak Google Cloud ve Firebase sayesinde basit ve sağlam bir sistem ortaya çıkardık. Bir sanatçı sisteme yeni bir dans yüklediğinde Firebase Authentication tarafından kimliği anonim olarak doğrulanır. Firebase için Cloud Storage'ı kullanarak kayıtlarını geçici bir alana yüklemelerine izin verilir. Yükleme tamamlandığında istemci makinesi, Firebase jetonunu kullanarak bir Cloud Functions for Firebase HTTP tetikleyicisini ç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şlemi tetikler.
Herkese açık içeriklerimizin tümü, bir Cloud Storage paketinde bir dizi düz dosyada depolanır. Bu, verilerimize dünyanın her yerinden hızla erişilebileceği ve veri kullanılabilirliğini herhangi bir şekilde etkileyen yüksek trafik yükleri konusunda endişelenmemize gerek olmadığı anlamına gelir.
Her yeni gönderimi VR'de izlememize ve herhangi bir cihazdan yeni oynatma listeleri yayınlamamıza olanak tanıyan basit bir moderasyon/seçme aracı oluşturmak için Firebase Realtime Database ve Cloud Functions uç noktalarını 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. Bizim durumumuzda hizmet çalışanları, geri gelen ziyaretçiler için içeriğimizi ışık hızında yükler ve hatta sitenin çevrimdışı çalışmasına olanak tanır. Ziyaretçilerimizin çoğu farklı kalitede mobil bağlantılar kullandığından bu özellikler önemlidir.
Ağır işlerin çoğunu sizin yerinize yapan kullanışlı bir webpack eklentisi sayesinde projeye servis çalışanları eklemek 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. Çalma listesi sürekli güncellendiğinden, mevcutsa ağdan en son oynatma listesi dosyasını alır. Hiçbir zaman değişmeyecekleri için tüm kayıt json dosyaları, varsa önbellekten alınmalıdır.
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 aşamalı olarak yüklenen medya öğelerini işlemiyor. Bu nedenle, tarayıcının dosyayı bir yıla kadar önbelleğe alabilmesi için bu dosyalardaki Cloud Storage Cache-Control
başlığını public, max-age=31536000
olarak ayarlayarak bu sorunu giderdik.
Sonuç
Performans gösterenlerin bu deneyime nasıl katkıda bulunacağını ve bunu hareketi kullanarak yaratıcı bir ifade olarak kullanabilecekleri bir araç olarak kullanmayı heyecanla bekliyoruz. Tüm kod açık kaynak kodunu yayınladık. Bu kodları https://github.com/puckey/dance-tonite adresinde bulabilirsiniz. Sanal gerçekliğin ve özellikle WebVR'nin ilk günlerinde, bu yeni aracın yeni ve beklenmedik yönlere nasıl gideceğini görmek için sabırsızlanıyoruz. Dans etmeye devam edin.