Dance Tonite di WebVR

Saya bersemangat ketika tim Google Data Arts mendekati Moniker dan saya sendiri tentang bekerja sama untuk mengeksplorasi kemungkinan yang diperkenalkan oleh WebVR. Saya telah melihat pekerjaan yang dilakukan tim mereka selama bertahun-tahun dan proyek mereka selalu cocok dengan saya. Kolaborasi kami menghasilkan Dance Tonite, pengalaman dance VR yang terus berubah dengan LCD Soundsystem dan penggemarnya. Inilah cara kami melakukannya.

Konsep

Kami mulai dengan mengembangkan serangkaian prototipe menggunakan WebVR, sebuah standar terbuka yang memungkinkan masuknya VR dengan mengunjungi situs menggunakan browser Anda. Tujuannya adalah memudahkan semua orang menikmati pengalaman VR, apa pun perangkat yang Anda miliki.

Kami telah mempertimbangkannya. Apa pun yang kami hasilkan seharusnya berfungsi pada semua jenis VR, mulai dari headset VR yang berfungsi dengan ponsel seperti Daydream View Google, Cardboard, dan Gear VR dari Samsung, hingga sistem berskala ruangan seperti HTC VIVE dan Oculus Rift yang mencerminkan gerakan fisik Anda di lingkungan virtual. Mungkin yang paling penting, kami merasa diberdayakan oleh web untuk membuat sesuatu yang juga berfungsi bagi semua orang yang tidak memiliki perangkat VR.

1. Rekam gerakan DIY

Karena kami ingin melibatkan pengguna secara kreatif, kami mulai mencari kemungkinan untuk berpartisipasi dan berekspresi diri menggunakan VR. Kami terkesan dengan kelancaran Anda bisa bergerak dan melihat-lihat dalam VR, dan seberapa banyak ketepatan di sana. Hal ini memberi kami ide. Alih-alih meminta pengguna melihat atau menciptakan sesuatu, bagaimana cara merekam gerakan mereka?

Seseorang yang merekam dirinya sendiri di Dance Tonite. Layar di belakang perangkat menunjukkan
  apa yang mereka lihat di headset

Kami membuat prototipe untuk merekam posisi kacamata dan pengontrol VR saat menari. Kami mengganti posisi yang tercatat dengan bentuk abstrak dan kagum dengan hasilnya. Hasilnya sangat manusiawi dan mengandung kepribadian yang sangat banyak! Kami segera menyadari bahwa kami dapat menggunakan WebVR untuk melakukan pengambilan gambar gerak murah di rumah.

Dengan WebVR, developer memiliki akses ke posisi dan orientasi kepala pengguna melalui objek VRPose. Nilai ini diupdate setiap frame oleh hardware VR, sehingga kode Anda dapat merender frame baru dari sudut pandang yang benar. Melalui GamePad API dengan WebVR, kita juga dapat mengakses posisi/orientasi pengontrol pengguna melalui objek GamepadPose. Kita hanya menyimpan semua nilai posisi dan orientasi ini setiap frame, sehingga menciptakan "rekaman" gerakan pengguna.

2. Minimalis & kostum

Dengan peralatan VR skala kamar saat ini, kita dapat melacak tiga titik tubuh pengguna: kepala dan dua tangan. Di Dance Tonite, kami ingin tetap fokus pada kemanusiaan dalam gerakan 3 titik di ruang angkasa ini. Untuk mencapai hal ini, kami mendorong estetika seminimal mungkin untuk fokus pada gerakan. Kami menyukai ide untuk mengasah otak.

Video yang mendemonstrasikan karya Psikolog Swedia, Gunnar Johansson, adalah salah satu contoh yang kami rujuk saat mempertimbangkan untuk menghapus sebanyak mungkin. Cara ini menunjukkan bagaimana titik-titik putih mengambang langsung dikenal sebagai tubuh saat terlihat bergerak.

Secara visual, kami terinspirasi oleh ruangan berwarna dan kostum geometris dalam rekaman pementasan ulang Triadic Balet Oskar Schlemmer pada tahun 1970 oleh Margarete Hastings.

Alasan Schlemmer memilih kostum geometris abstrak adalah untuk membatasi gerakan penarinya hanya pada boneka & boneka, sedangkan tujuan yang berlawanan adalah untuk Dance Tonite.

Kami akhirnya mendasarkan pilihan bentuk kami pada seberapa banyak informasi yang disampaikan melalui rotasi. Bola terlihat sama bagaimana pun caranya diputar, tetapi kerucut benar-benar mengarah ke arah yang dilihatnya dan terlihat berbeda dari depan dari belakang.

3. Putar pedal untuk bergerak

Kami ingin menunjukkan sejumlah besar rekaman orang yang menari dan bergerak satu sama lain. Melakukannya secara langsung tidak mungkin dilakukan, karena perangkat VR tidak tersedia dalam jumlah yang cukup besar. Tapi kami tetap ingin ada sekelompok orang yang berreaksi satu sama lain melalui gerakan. Pikiran kita tertuju pada pertunjukan rekursif Norman McClaren dalam video berjudul "Canon" yang dibuat pada tahun 1964.

Performa McClaren menampilkan serangkaian gerakan yang sangat koreografinya yang mulai berinteraksi satu sama lain setelah setiap loop. Mirip dengan gerakan loop dalam musik, saat musisi bernyanyi dengan merangkai berbagai potongan musik live, kami tertarik untuk melihat apakah kami dapat menciptakan lingkungan yang memungkinkan pengguna berimprovisasi versi pertunjukan yang lebih longgar dengan bebas.

4. Kamar yang saling terhubung

Kamar yang saling terhubung

Seperti kebanyakan musik, trek Soundsystem LCD dibuat menggunakan ukuran waktu yang tepat. Trek mereka, Tonite, yang ditampilkan dalam project kami, menampilkan ukuran yang berdurasi tepat 8 detik. Kita ingin pengguna membuat performa untuk setiap loop 8 detik di jalur. Meskipun ritme ini tidak berubah, konten musiknya berubah. Seiring berjalannya lagu, ada momen dengan berbagai instrumen dan vokal yang dapat bereaksi dengan para artis dengan cara berbeda. Setiap ukuran ini dinyatakan sebagai ruangan, tempat orang dapat membuat performa yang sesuai dengannya.

Pengoptimalan untuk performa: jangan lepaskan frame

Menciptakan pengalaman VR multi-platform yang berjalan pada satu codebase dengan performa optimal untuk setiap perangkat atau platform bukanlah pekerjaan yang mudah.

Saat berada dalam VR, salah satu hal paling memuakkan yang dapat Anda alami disebabkan oleh kecepatan frame yang tidak mengikuti gerakan Anda. Jika Anda menolehkan kepala, tetapi visualisasi yang dilihat mata Anda tidak sesuai dengan gerakan yang dirasakan telinga bagian dalam, hal ini menyebabkan murah perut. Karena alasan ini, kami perlu menghindari penundaan kecepatan frame yang besar. Berikut beberapa pengoptimalan yang telah kami terapkan.

1. Geometri buffer instance

Karena seluruh project kami hanya menggunakan beberapa objek 3d, kami bisa mendapatkan peningkatan performa yang besar dengan menggunakan Instanced Buffer Geometry. Pada dasarnya, hal ini memungkinkan Anda mengupload objek ke GPU satu kali dan menggambar "instance" objek tersebut sebanyak yang Anda inginkan dalam satu panggilan gambar. Dalam Dance Tonite, kita hanya memiliki 3 objek yang berbeda (kerucut, silinder, dan ruangan berlubang), tetapi berpotensi ratusan salinan objek tersebut. Geometri Buffer Instance adalah bagian dari ThreeJS, tetapi kami menggunakan fork eksperimental dan yang sedang berlangsung Dusan Bosnjak yang mengimplementasikan THREE.InstanceMesh, yang membuat penggunaan Geometri Buffering Instanced jauh lebih mudah.

2. Menghindari pembersih sampah memori

Seperti banyak bahasa skrip lainnya, JavaScript secara otomatis membebaskan memori dengan mencari tahu objek mana yang telah dialokasikan yang tidak digunakan lagi. Proses ini disebut pembersihan sampah memori.

Developer tidak memiliki kontrol atas waktu terjadinya hal ini. Pembersih sampah memori dapat muncul di pintu kami kapan saja dan mulai mengosongkan sampah, sehingga frame mengalami penurunan saat menghabiskan waktu.

Solusi untuk hal ini adalah menghasilkan sesedikit mungkin sampah dengan mendaur ulang objek kita. Kami menandai objek awal untuk digunakan kembali, bukan membuat objek vektor baru untuk setiap penghitungan. Karena kami mempertahankannya dengan memindahkan referensi ke luar cakupan kami, referensi tersebut tidak ditandai untuk dihapus.

Misalnya, berikut adalah kode kami untuk mengonversi matriks lokasi kepala dan tangan pengguna menjadi array nilai posisi/rotasi yang kita simpan setiap frame. Dengan menggunakan kembali SERIALIZE_POSITION, SERIALIZE_ROTATION, dan SERIALIZE_SCALE, kita menghindari alokasi memori dan pembersihan sampah memori yang akan terjadi jika kita membuat objek baru setiap kali fungsi dipanggil.

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. Menserialisasi gerakan & pemutaran progresif

Untuk menangkap pergerakan pengguna di VR, kami perlu melakukan serialisasi posisi dan rotasi headset dan pengontrol mereka serta mengupload data ini ke server kami. Kami mulai mengambil matriks transformasi penuh untuk setiap frame. Proses ini berperforma baik, tetapi dengan 16 angka yang dikalikan dengan 3 posisi masing-masing pada kecepatan 90 frame per detik, hasil ini menghasilkan file yang sangat besar sehingga menunggu lama saat mengupload dan mendownload data. Dengan hanya mengekstrak data posisi dan rotasi dari matriks transformasi, kita dapat menurunkan nilai-nilai ini dari 16 menjadi 7.

Karena pengunjung di web sering mengklik link tanpa mengetahui persis apa yang diharapkan, kami perlu menampilkan konten visual dengan cepat atau mereka akan meninggalkan situs dalam hitungan detik.

Karena alasan ini, kami ingin memastikan project kami dapat mulai dijalankan sesegera mungkin. Awalnya, kami menggunakan JSON sebagai format untuk memuat data gerakan kami. Masalahnya adalah kita harus memuat file JSON lengkap sebelum dapat mengurainya. Tidak terlalu progresif.

Agar project seperti Dance Tonite tetap ditampilkan pada kecepatan frame setinggi mungkin, browser hanya memiliki sedikit waktu setiap frame untuk penghitungan JavaScript. Jika terlalu lama, animasi akan mulai tersendat. Awalnya, kami mengalami ketersendatan karena file JSON yang berukuran besar ini didekode oleh browser.

Kami menemukan format data streaming yang praktis dan berbasis yang disebut NDJSON atau JSON yang dibatasi baris baru. Triknya di sini adalah dengan membuat file dengan serangkaian string JSON yang valid, masing-masing di barisnya sendiri. Hal ini memungkinkan Anda untuk mengurai file saat sedang dimuat, sehingga kami dapat menampilkan performa sebelum file dimuat sepenuhnya.

Berikut adalah tampilan bagian dari salah satu rekaman kami:

{"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, ... ]
...

Dengan NDJSON, kita dapat menyimpan representasi data setiap frame performa sebagai string. Kita dapat menunggu sampai mencapai waktu yang diperlukan, sebelum mendekodenya ke data posisi, sehingga menyebarkan pemrosesan yang diperlukan dari waktu ke waktu.

4. Gerakan interpolasi

Karena kami berharap dapat menampilkan antara 30 hingga 60 performa yang berjalan sekaligus, kami perlu menurunkan kecepatan data lebih jauh dari yang sudah kami lakukan. Tim Data Arts juga mengatasi masalah yang sama dalam project Virtual Art Sessions yang mengharuskan mereka memutar rekaman artis yang melukis di VR menggunakan Kuas Virtual. Mereka menyelesaikannya dengan membuat versi menengah dari data pengguna dengan kecepatan frame yang lebih rendah dan melakukan interpolasi antar-frame sambil memutarnya kembali. Kami terkejut mendapati bahwa kami kesulitan menemukan perbedaan antara perekaman interpolasi yang berjalan pada 15 FPS dibandingkan dengan rekaman 90 FPS asli.

Untuk melihatnya sendiri, Anda dapat memaksa Dance Tonite untuk memutar data dengan berbagai frekuensi menggunakan string kueri ?dataRate=. Anda dapat menggunakan ini untuk membandingkan gerakan yang direkam pada 90 frame per detik, 45 frame per detik, atau 15 frame per detik.

Untuk posisi, kita melakukan interpolasi linier antara keyframe sebelumnya dan yang berikutnya, berdasarkan seberapa dekat posisi kita dalam waktu antara keyframe (rasio):

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

Untuk orientasi, kita melakukan interpolasi linier sferikal (slerp) antar-keyframe. Orientasi disimpan sebagai Kuaternion.

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

5. Menyinkronkan gerakan dengan musik

Untuk mengetahui frame animasi rekaman mana yang akan diputar, kita perlu mengetahui waktu musik saat ini hingga milidetik. Ternyata meskipun elemen Audio HTML cocok untuk memuat dan memutar suara secara bertahap, properti waktu yang disediakannya tidak berubah sinkron dengan frame loop browser. Fungsi ini selalu sedikit salah. Terkadang beberapa md terlalu awal, terkadang sepersekiannya terlambat.

Hal ini menyebabkan rekaman tarian kita yang indah tersendat, yang ingin kita hindari dengan segala cara. Untuk mengatasi hal ini, kami menerapkan timer sendiri di JavaScript. Dengan cara ini, kita dapat memastikan bahwa jumlah waktu yang berubah antar-frame adalah jumlah waktu yang telah berlalu sejak frame terakhir. Setiap kali timer tidak sinkron dengan musik lebih dari 10 md, kami akan menyinkronkannya kembali.

6. Membebaskan dan berkabut

Setiap cerita perlu akhir yang bagus dan kami ingin memberikan sesuatu yang mengejutkan bagi pengguna yang berhasil sampai ke akhir pengalaman. Saat meninggalkan ruangan terakhir, Anda memasuki sebuah lanskap kerucut dan silinder yang tenang. “Apakah ini sudah akhir?”, Anda bertanya-tanya. Saat Anda semakin maju ke lapangan, tiba-tiba nada musik menyebabkan berbagai kelompok kerucut dan silinder berubah menjadi penari. Anda berada di tengah-tengah pesta besar! Kemudian saat musik berhenti tiba-tiba, semuanya jatuh ke tanah.

Meskipun terasa menyenangkan bagi penonton, acara ini memperkenalkan beberapa rintangan performa yang harus dipecahkan. Perangkat VR berskala besar dan perangkat game kelas atas berperforma sempurna dengan 40 pertunjukan tambahan aneh yang diperlukan untuk versi baru kami. Tetapi kecepatan {i>frame<i} di perangkat seluler tertentu berkurang setengahnya.

Untuk melawannya, kami memperkenalkan kabut. Setelah jarak tertentu semuanya menjadi gelap. Karena kita tidak perlu menghitung atau menggambar hal yang tidak terlihat, kita mengecualikan performa di ruangan yang tidak terlihat dan ini memungkinkan kita untuk menghemat pekerjaan untuk CPU & GPU. Tetapi bagaimana cara menentukan jarak yang tepat?

Beberapa perangkat dapat menangani apa pun yang Anda lemparkan dan yang lainnya lebih terbatas. Kami memilih untuk menerapkan skala geser. Dengan terus mengukur jumlah frame per detik, kita dapat menyesuaikan jarak kabut. Selama kecepatan frame berjalan lancar, kita mencoba melakukan lebih banyak pekerjaan render dengan mendorong keluarnya. Jika kecepatan frame tidak berjalan cukup lancar, kami mendekatkan kabut sehingga dapat melewati performa rendering dalam kegelapan.

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

Sesuatu untuk semua orang: membangun VR untuk web

Merancang dan mengembangkan pengalaman asimetris multi-platform berarti memperhitungkan kebutuhan setiap pengguna, bergantung pada perangkat mereka. Dan dengan setiap keputusan desain, kita perlu melihat bagaimana itu dapat berdampak pada pengguna lain. Bagaimana Anda memastikan bahwa apa yang Anda lihat di VR sama menariknya dengan tanpa VR, dan sebaliknya?

1. Bola kuning

Jadi, pengguna VR berskala kamar kami akan membuat pertunjukan, tetapi bagaimana pengguna perangkat VR seluler (seperti Cardboard, Daydream View, atau Samsung Gear) akan mengalami proyek ini? Untuk ini, kita memperkenalkan elemen baru ke lingkungan kita: bola kuning.

Bola kuning
Bola kuning

Saat menonton project di VR, Anda melakukannya dari sudut pandang bola kuning. Saat Anda melayang dari ruangan ke ruangan, para penari bereaksi terhadap kehadiran Anda. Mereka memberi isyarat kepada Anda, menari di sekitar Anda, membuat gerakan lucu di belakang Anda, dan bergerak dengan cepat sehingga tidak menabrak Anda. Bola kuning selalu menjadi pusat perhatian.

Alasannya adalah saat merekam pertunjukan, bola kuning bergerak di tengah ruangan secara sinkron dengan musik dan berputar-putar kembali. Posisi bola ini memberi pemain gambaran mengenai posisi mereka dalam waktu yang tepat dan berapa banyak waktu yang tersisa dalam loop. Hal ini memberikan fokus alami bagi mereka untuk membangun performa.

2. Sudut pandang lain

Kami tidak ingin mengabaikan pengguna tanpa VR, terutama karena mereka kemungkinan akan menjadi audiens terbesar kami. Daripada membuat pengalaman VR tiruan, kami ingin memberikan pengalaman yang berbeda bagi perangkat berbasis layar. Kami memiliki ide untuk menunjukkan pertunjukan dari atas dari perspektif isometrik. Perspektif ini memiliki sejarah yang kaya dalam {i>game<i} komputer. Pertama kali digunakan di Zaxxon, game menembak ruang angkasa dari tahun 1982. Sementara pengguna VR berada di dalamnya, perspektif isometrik memberikan tampilan seperti dewa tentang tindakan tersebut. Kami memilih untuk sedikit meningkatkan skala model, dengan memberikan sentuhan estetika rumah boneka.

3. Bayangan: palsukan sampai Anda membuatnya

Kami menemukan bahwa beberapa pengguna kesulitan melihat kedalaman sudut pandang isometrik. Karena alasan inilah Zaxxon juga merupakan salah satu game komputer pertama dalam sejarah yang memproyeksikan bayangan dinamis di bawah objek terbangnya.

Bayangan

Ternyata membuat bayangan dalam 3D itu sulit. Terutama untuk perangkat yang terbatas seperti ponsel. Awalnya kami harus membuat keputusan sulit untuk mengatasinya, tetapi setelah meminta saran dari penulis Three.js dan peretas demo berpengalaman Mr doob, dia memiliki ide baru tentang... memalsukan mereka.

Daripada harus menghitung bagaimana setiap objek mengambang mengaburkan cahaya, sehingga kita menggambar bentuk tekstur buram melingkar yang sama di bawah masing-masing objek. Karena visual kami tidak mencoba meniru realitas, kami sadar bahwa kami dapat mengabaikannya cukup mudah hanya dengan beberapa penyesuaian. Ketika objek mendekati tanah, tekstur kita akan menjadi lebih gelap dan lebih kecil. Ketika mereka bergerak ke atas, kita membuat teksturnya lebih transparan dan lebih besar.

Untuk membuatnya, kami menggunakan tekstur ini dengan gradien putih lembut ke hitam (tanpa transparansi alfa). Kami menetapkan bahan sebagai transparan dan menggunakan pencampuran subtraktif. Hal ini membantu elemen-elemen tersebut berbaur dengan baik saat tumpang tindih:

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. Berada di sana

Dengan mengklik kepala pemain, pengunjung tanpa VR dapat menonton berbagai hal dari sudut pandang penari. Dari sudut ini, banyak detail kecil akan terlihat jelas. Supaya penampilan mereka tetap selaras, para penari dengan cepat melihat satu sama lain. Saat bola itu memasuki ruangan, Anda melihat mereka melihat dengan gugup ke arahnya. Meskipun sebagai penonton, Anda tidak dapat memengaruhi gerakan ini, tetapi gerakan tersebut menyampaikan ketenangan dengan sangat baik. Sekali lagi, kami lebih memilih melakukannya daripada menyajikan versi VR palsu yang dikontrol mouse kepada pengguna.

5. Membagikan rekaman

Kami tahu betapa bangganya Anda saat menyanyikan rekaman dengan koreografi rumit dari 20 lapisan artis yang saling bereaksi satu sama lain. Kami tahu pengguna kami mungkin ingin menunjukkannya kepada teman-teman mereka. Tapi gambar diam dari prestasi ini tidak cukup untuk dikomunikasikan. Sebaliknya, kami ingin mengizinkan pengguna untuk membagikan video pertunjukan mereka. Sebenarnya, mengapa bukan GIF? Animasi kita diarsir datar, cocok untuk palet warna format yang terbatas.

Membagikan rekaman

Kami beralih ke GIF.js, library JavaScript yang memungkinkan Anda mengenkode animasi GIF dari dalam browser. Solusi ini mengalihkan encoding frame ke pekerja web yang dapat berjalan di latar belakang sebagai proses terpisah, sehingga dapat memanfaatkan beberapa prosesor yang bekerja berdampingan.

Sayangnya, dengan jumlah frame yang kami butuhkan untuk animasi, proses encoding masih terlalu lambat. GIF dapat membuat file kecil dengan menggunakan palet warna terbatas. Kita menemukan bahwa sebagian besar waktu dihabiskan untuk mencari warna terdekat untuk setiap {i>pixel<i}. Kita dapat mengoptimalkan proses ini sepuluh kali lipat dengan meretas: jika warna piksel sama dengan yang terakhir, gunakan warna yang sama dari palet seperti sebelumnya.

Sekarang kita memiliki encoding cepat, tetapi file GIF yang dihasilkan berukuran terlalu besar. Dengan format GIF, Anda dapat menunjukkan cara setiap frame ditampilkan di atas yang terakhir dengan menentukan metode pembuangannya. Untuk mendapatkan file yang lebih kecil, kami hanya mengupdate piksel yang berubah, bukan memperbarui setiap piksel di setiap frame. Meskipun melambatkan lagi proses encoding, ukuran file kami turun dengan baik.

6. Solusi yang kokoh: Google Cloud & Firebase

Backend situs "konten buatan pengguna" sering kali rumit dan rapuh, tetapi kami memiliki sistem yang sederhana dan andal berkat Google Cloud dan Firebase. Saat pemain mengupload tarian baru ke sistem, tarian tersebut akan diautentikasi secara anonim oleh Firebase Authentication. Mereka akan diberi izin untuk mengupload rekaman ke ruang sementara menggunakan Cloud Storage for Firebase. Setelah upload selesai, mesin klien memanggil pemicu HTTP Cloud Functions for Firebase menggunakan token Firebase. Tindakan ini akan memicu proses server yang memvalidasi pengiriman, membuat catatan database, dan memindahkan rekaman ke direktori publik di Google Cloud Storage.

Tanah padat

Semua konten publik kami disimpan dalam serangkaian file datar dalam Bucket Cloud Storage. Ini berarti data kami dapat diakses dengan cepat di seluruh dunia dan kami tidak perlu khawatir dengan beban traffic yang tinggi yang memengaruhi ketersediaan data.

Kami menggunakan endpoint Firebase Realtime Database dan Cloud Function untuk membuat alat moderasi/kurasi sederhana yang memungkinkan kami melihat setiap pengiriman baru di VR dan memublikasikan playlist baru dari perangkat apa pun.

7. Service Worker

Pekerja layanan adalah inovasi terbaru yang membantu mengelola caching aset situs. Dalam kasus ini, pekerja layanan memuat konten secepat kilat untuk pengunjung yang kembali dan bahkan memungkinkan situs bekerja secara offline. Fitur tersebut penting karena banyak pengunjung akan menggunakan sambungan seluler dengan kualitas yang beragam.

Menambahkan pekerja layanan ke project dapat dilakukan dengan mudah berkat plugin webpack praktis yang menangani sebagian besar tugas berat untuk Anda. Pada konfigurasi di bawah ini, kita membuat pekerja layanan yang akan otomatis meng-cache semua file statis. Tindakan ini akan menarik file playlist terbaru dari jaringan, jika tersedia, karena playlist akan diperbarui sepanjang waktu. Semua file json rekaman harus diambil dari cache jika tersedia, karena hal ini tidak akan pernah berubah.

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',
        },
        },
    }],
    })
);

Saat ini, plugin tidak menangani aset media yang dimuat secara progresif seperti file musik kami. Jadi, kami mengatasinya dengan menyetel header Cache-Control Cloud Storage pada file ini ke public, max-age=31536000, sehingga browser akan menyimpan file tersebut dalam cache hingga satu tahun.

Kesimpulan

Kami ingin segera melihat bagaimana kreator akan menambahkan pengalaman ini dan menggunakannya sebagai alat untuk berekspresi kreatif menggunakan gerakan. Kami telah merilis semua kode menjadi open source, yang dapat Anda temukan di https://github.com/puckey/dance-tonite. Di masa-masa awal VR dan terutama WebVR, kami tidak sabar untuk melihat materi iklan baru dan arah yang tidak terduga dari media baru ini. Ayo menari.