Sesi Seni Virtual

Detail Sesi Seni

Ringkasan

Enam seniman diundang untuk melukis, mendesain, dan memahat di VR. Ini adalah proses untuk mencatat sesi, mengonversi data, dan menyajikannya secara real time dengan browser web.

https://g.co/VirtualArtSessions

Sungguh luar biasa untuk hidup! Dengan diperkenalkannya {i>virtual reality<i} sebagai produk konsumen, berbagai kemungkinan baru dan belum diselidiki mulai bermunculan. Tilt Brush, sebuah produk Google yang tersedia di HTC Vive, memungkinkan Anda menggambar dalam ruang tiga dimensi. Saat kami mencoba Tilt Brush untuk pertama kalinya, perasaan menggambar dengan pengontrol yang dilacak gerakan ditambah dengan keberadaan "di dalam ruangan dengan kekuatan super" tetap ada dalam diri Anda; sebenarnya tidak ada pengalaman seperti bisa menggambar di ruang kosong di sekitar Anda.

Karya seni virtual

Tim Data Arts di Google diberi tantangan untuk menampilkan pengalaman ini kepada mereka yang tidak menggunakan headset VR, di web yang belum dioperasikan oleh Tilt Brush. Untuk mencapai tujuan tersebut, tim ini melibatkan pematung, ilustrator, desainer konsep, seniman mode, seniman instalasi, dan seniman jalanan untuk membuat karya seni dengan gaya mereka sendiri dalam media baru ini.

Merekam Gambar dalam Virtual Reality

Dibangun di Unity, software Tilt Brush itu sendiri adalah aplikasi desktop yang menggunakan VR skala ruangan untuk melacak posisi kepala (tampilan yang dipasang di kepala, atau HMD) dan pengontrol di kedua tangan Anda. Poster yang dibuat di Tilt Brush secara default diekspor sebagai file .tilt. Untuk menghadirkan pengalaman ini ke web, kami menyadari bahwa kami membutuhkan lebih dari sekadar data karya seni. Kami bekerja sama dengan tim Tilt Brush untuk memodifikasi Tilt Brush sehingga dapat mengekspor tindakan urungkan/hapus serta posisi kepala dan tangan artis pada 90 kali per detik.

Saat menggambar, Kuas Virtual mengambil posisi dan sudut pengontrol Anda serta mengonversi beberapa titik seiring waktu menjadi "goresan". Anda dapat melihat contohnya di sini. Kami menulis plugin yang mengekstrak goresan tersebut dan menghasilkan output-nya sebagai JSON mentah.

    {
      "metadata": {
        "BrushIndex": [
          "d229d335-c334-495a-a801-660ac8a87360"
        ]
      },
      "actions": [
        {
          "type": "STROKE",
          "time": 12854,
          "data": {
            "id": 0,
            "brush": 0,
            "b_size": 0.081906750798225,
            "color": [
              0.69848710298538,
              0.39136275649071,
              0.211316883564
            ],
            "points": [
              [
                {
                  "t": 12854,
                  "p": 0.25791856646538,
                  "pos": [
                    [
                      1.9832634925842,
                      17.915264129639,
                      8.6014995574951
                    ],
                    [
                      -0.32014992833138,
                      0.82291424274445,
                      -0.41208130121231,
                      -0.22473378479481
                    ]
                  ]
                }, ...many more points
              ]
            ]
          }
        }, ... many more actions
      ]
    }

Cuplikan di atas menguraikan format format JSON sketsa.

Di sini, setiap goresan disimpan sebagai tindakan, dengan jenis: "STROKE". Selain tindakan goresan, kami ingin menunjukkan artis yang melakukan kesalahan dan mengubah tengah sketsa pikirannya, sehingga penting untuk menyimpan tindakan "DELETE" yang berfungsi sebagai tindakan menghapus atau mengurungkan tindakan untuk seluruh goresan.

Informasi dasar untuk setiap goresan disimpan, sehingga jenis kuas, ukuran kuas, warna RGB semua dikumpulkan.

Terakhir, setiap verteks goresan akan disimpan dan mencakup posisi, sudut, waktu, serta kekuatan tekanan pemicu pengontrol (dicatat sebagai p di dalam setiap titik).

Perhatikan bahwa rotasi adalah angka kuaternion 4 komponen. Hal ini penting untuk dilakukan nanti saat kita merender goresan untuk menghindari kunci gimbal.

Memutar Sketsa Kembali dengan WebGL

Untuk menampilkan sketsa di browser web, kami menggunakan THREE.js dan menulis kode pembuatan geometri yang meniru fungsi Tilt Brush di balik layar.

Meskipun Tilt Brush menghasilkan strip segitiga secara real-time berdasarkan gerakan tangan pengguna, keseluruhan sketsa sudah "selesai" pada saat kami menampilkannya di web. Hal ini memungkinkan kita mengabaikan sebagian besar penghitungan real-time dan menghitung geometri saat dimuat.

Sketsa WebGL

Setiap pasangan verteks dalam goresan menghasilkan vektor arah (garis biru yang menghubungkan setiap titik seperti yang ditunjukkan di atas, moveVector dalam cuplikan kode di bawah). Setiap titik juga berisi orientasi, yaitu kuaternion yang mewakili sudut pengontrol saat ini. Untuk menghasilkan strip segitiga, kami melakukan iterasi pada setiap titik ini menghasilkan nilai normal yang tegak lurus dengan arah dan orientasi pengontrol.

Proses komputasi strip segitiga untuk setiap goresan hampir identik dengan kode yang digunakan di Kuas Virtual:

const V_UP = new THREE.Vector3( 0, 1, 0 );
const V_FORWARD = new THREE.Vector3( 0, 0, 1 );

function computeSurfaceFrame( previousRight, moveVector, orientation ){
    const pointerF = V_FORWARD.clone().applyQuaternion( orientation );

    const pointerU = V_UP.clone().applyQuaternion( orientation );

    const crossF = pointerF.clone().cross( moveVector );
    const crossU = pointerU.clone().cross( moveVector );

    const right1 = inDirectionOf( previousRight, crossF );
    const right2 = inDirectionOf( previousRight, crossU );

    right2.multiplyScalar( Math.abs( pointerF.dot( moveVector ) ) );

    const newRight = ( right1.clone().add( right2 ) ).normalize();
    const normal = moveVector.clone().cross( newRight );
    return { newRight, normal };
}

function inDirectionOf( desired, v ){
    return v.dot( desired ) >= 0 ? v.clone() : v.clone().multiplyScalar(-1);
}

Menggabungkan arah goresan dan orientasi masing-masing akan menampilkan hasil yang ambigu secara matematis; mungkin ada beberapa normal yang diturunkan dan sering kali akan menghasilkan "putaran" dalam geometri.

Saat melakukan iterasi pada titik goresan, kita mempertahankan vektor "kanan pilihan" dan meneruskannya ke fungsi computeSurfaceFrame(). Fungsi ini memberi kita nilai normal dari mana kita dapat memperoleh quad dalam quad strip, berdasarkan arah goresan (dari titik terakhir ke titik saat ini), dan orientasi pengontrol (kuaternion). Yang lebih penting, kode ini juga menampilkan vektor "kanan pilihan" baru untuk kumpulan komputasi berikutnya.

Garis luar

Setelah membuat segiempat berdasarkan titik kontrol setiap goresan, kita menggabungkan segitiga dengan menginterpolasi sudutnya, dari satu segi empat ke bidang berikutnya.

function fuseQuads( lastVerts, nextVerts) {
    const vTopPos = lastVerts[1].clone().add( nextVerts[0] ).multiplyScalar( 0.5
);
    const vBottomPos = lastVerts[5].clone().add( nextVerts[2] ).multiplyScalar(
0.5 );

    lastVerts[1].copy( vTopPos );
    lastVerts[4].copy( vTopPos );
    lastVerts[5].copy( vBottomPos );
    nextVerts[0].copy( vTopPos );
    nextVerts[2].copy( vBottomPos );
    nextVerts[3].copy( vBottomPos );
}
Paha depan menyatu
Perempat empat bagian.

Setiap segi empat juga berisi UV yang dihasilkan sebagai langkah berikutnya. Beberapa kuas berisi berbagai pola goresan untuk memberikan kesan bahwa setiap goresan terasa seperti goresan kuas yang berbeda. Hal ini dilakukan menggunakan atlasing _tekstur, _dengan setiap tekstur kuas berisi semua kemungkinan variasi. Tekstur yang benar dipilih dengan mengubah nilai UV goresan.

function updateUVsForSegment( quadVerts, quadUVs, quadLengths, useAtlas,
atlasIndex ) {
    let fYStart = 0.0;
    let fYEnd = 1.0;

    if( useAtlas ){
    const fYWidth = 1.0 / TEXTURES_IN_ATLAS;
    fYStart = fYWidth * atlasIndex;
    fYEnd = fYWidth * (atlasIndex + 1.0);
    }

    //get length of current segment
    const totalLength = quadLengths.reduce( function( total, length ){
    return total + length;
    }, 0 );

    //then, run back through the last segment and update our UVs
    let currentLength = 0.0;
    quadUVs.forEach( function( uvs, index ){
    const segmentLength = quadLengths[ index ];
    const fXStart = currentLength / totalLength;
    const fXEnd = ( currentLength + segmentLength ) / totalLength;
    currentLength += segmentLength;

    uvs[ 0 ].set( fXStart, fYStart );
    uvs[ 1 ].set( fXEnd, fYStart );
    uvs[ 2 ].set( fXStart, fYEnd );
    uvs[ 3 ].set( fXStart, fYEnd );
    uvs[ 4 ].set( fXEnd, fYStart );
    uvs[ 5 ].set( fXEnd, fYEnd );

    });

}
Empat tekstur dalam atlas tekstur untuk kuas minyak
Empat tekstur di atlas tekstur untuk kuas minyak
Di Kuas Virtual
Di Kuas Virtual
Di WebGL
Di WebGL

Karena setiap sketsa memiliki jumlah goresan yang tidak terbatas, dan goresan tidak perlu diubah selama runtime, kita akan menghitung geometri goresan terlebih dahulu dan menggabungkannya menjadi satu mesh tunggal. Meskipun setiap jenis kuas baru harus berupa materialnya sendiri, hal tersebut tetap mengurangi panggilan gambar ke satu per kuas.

Seluruh sketsa di atas dilakukan dalam satu panggilan gambar di WebGL
Seluruh sketsa di atas dilakukan dalam satu panggilan gambar di WebGL

Untuk menguji daya tahan sistem, kami membuat sketsa yang memerlukan waktu 20 menit untuk mengisi ruang dengan sebanyak mungkin titik sudut. Sketsa yang dihasilkan masih diputar pada 60 fps di WebGL.

Karena setiap verteks asli dari goresan juga berisi waktu, kita dapat memutar kembali datanya dengan mudah. Menghitung ulang goresan per frame akan sangat lambat. Jadi, kami telah menghitung sebelumnya seluruh sketsa saat dimuat dan hanya menampilkan setiap segi empat ketika tiba waktunya untuk melakukannya.

Menyembunyikan segi empat berarti menciutkan verteksnya ke titik 0,0,0. Setelah waktu mencapai titik untuk menampilkan quad, kita dapat menempatkan verteks kembali ke tempatnya.

Area yang perlu ditingkatkan adalah memanipulasi verteks sepenuhnya di GPU dengan shader. Implementasi saat ini menempatkannya dengan melakukan loop pada array verteks dari stempel waktu saat ini, memeriksa verteks mana yang perlu ditampilkan, lalu memperbarui geometri. Hal ini akan membebani CPU sehingga menyebabkan kipas berputar serta membuang masa pakai baterai.

Karya seni virtual

Merekam Artis

Kami merasa bahwa sketsa itu sendiri tidak akan cukup. Kami ingin menunjukkan kepada para seniman di dalam sketsa mereka, melukis setiap sapuan kuas.

Untuk mengabadikan artis, kami menggunakan kamera Microsoft Kinect untuk merekam data kedalaman tubuh artis di luar angkasa. Ini memberi kita kemampuan untuk menampilkan bentuk tiga dimensi di ruang yang sama tempat gambar muncul.

Karena tubuh sang seniman akan menutupi dirinya sendiri sehingga kami tidak dapat melihat apa yang ada di belakangnya, kami menggunakan sistem Kinect ganda, yang keduanya berada di sisi berlawanan dari ruangan yang menunjuk ke tengah.

Selain informasi kedalaman, kami juga mengambil informasi warna tampilan dengan kamera DSLR standar. Kami menggunakan software DepthKit yang sangat baik untuk mengkalibrasi dan menggabungkan rekaman dari kamera kedalaman dan kamera warna. Kinect mampu merekam warna, tetapi kami memilih untuk menggunakan DSLR karena kami dapat mengontrol setelan eksposur, menggunakan lensa kelas atas yang indah, dan merekam dalam definisi tinggi.

Untuk merekam rekaman, kami membangun ruangan khusus untuk menampung HTC Vive, sang artis, dan kamera. Semua permukaan ditutupi dengan bahan yang menyerap cahaya inframerah untuk memberi kami titik yang lebih bersih (duvetyne di dinding, matting karet bergaris di lantai). Jika materi tersebut muncul di rekaman cloud titik, kami memilih materi hitam sehingga tidak akan mengganggu sesuatu yang berwarna putih.

Artis rekaman

Rekaman video yang dihasilkan memberi kami informasi yang cukup untuk memproyeksikan sistem partikel. Kami menulis beberapa alat tambahan di openFrameworks untuk membersihkan rekaman lebih jauh, khususnya penghilang lantai, dinding, dan plafon.

Keempat saluran sesi video yang direkam (dua saluran warna di atas dan dua
kedalaman di bawah)
Keempat saluran dari sesi video yang direkam (dua saluran warna di atas dan dua saluran di bawah)

Selain menampilkan seniman, kami juga ingin merender HMD dan pengontrol dalam 3D. Hal ini tidak hanya penting untuk menampilkan HMD di output akhir dengan jelas (lensa reflektif HTC Vive mengurangi pembacaan IR Kinect), tetapi juga memberi kami kontak (POC) untuk men-debug output partikel dan menyelaraskan video dengan sketsa.

Layar yang dipasang di kepala, pengontrol, dan partikel berbaris
Layar yang dipasang di kepala, pengontrol, dan partikel berbaris

Hal ini dilakukan dengan menulis plugin kustom ke Tilt Brush yang mengekstrak posisi HMD dan pengontrol setiap frame. Karena Tilt Brush berjalan pada 90 fps, banyak data yang dialirkan dan data input sketsa lebih besar dari 20 MB tidak terkompresi. Kami juga menggunakan teknik ini untuk menangkap peristiwa yang tidak direkam dalam file penyimpanan Tilt Brush standar, seperti saat artis memilih opsi di panel alat dan posisi widget mirror.

Dalam memproses 4 TB data yang kami ambil, salah satu tantangan terbesar adalah menyelaraskan semua sumber visual/data yang berbeda. Setiap video dari kamera DSLR harus disejajarkan dengan Kinect yang sesuai, sehingga piksel sejajar dalam ruang serta waktu. Kemudian, rekaman dari kedua rig kamera ini perlu diselaraskan satu sama lain untuk membentuk artis tunggal. Kemudian kita perlu menyelaraskan seniman 3D dengan data yang diambil dari gambar mereka. Fiuh! Kami membuat alat berbasis browser untuk membantu sebagian besar tugas tersebut, dan Anda dapat mencobanya sendiri di sini

Artis Perekam Suara

Setelah data diselaraskan, kami menggunakan beberapa skrip yang ditulis dalam NodeJS untuk memproses semuanya dan menghasilkan file video serta serangkaian file JSON, yang semuanya dipangkas dan disinkronkan. Untuk mengurangi ukuran file, kami melakukan tiga hal. Pertama, kami mengurangi akurasi setiap bilangan floating point sehingga nilai presisi maksimumnya adalah 3 desimal. Kedua, kita memotong jumlah titik hingga sepertiganya menjadi 30 fps, dan menginterpolasi posisi sisi klien. Terakhir, kita melakukan serialisasi data, sehingga daripada menggunakan JSON biasa dengan key-value pair, urutan nilai dibuat untuk posisi dan rotasi HMD dan pengontrol. Cara ini memangkas ukuran file menjadi hanya kurang dari 3 MB yang dapat diterima untuk dikirimkan melalui kabel.

Artis rekaman

Karena video itu sendiri disajikan sebagai elemen video HTML5 yang dibaca oleh tekstur WebGL untuk menjadi partikel, video itu sendiri perlu diputar secara tersembunyi di latar belakang. Shader mengonversi warna dalam gambar kedalaman menjadi posisi dalam ruang 3D. James George telah membagikan contoh bagus cara yang dapat Anda lakukan dengan rekaman langsung dari DepthKit.

iOS memiliki batasan pemutaran video inline, yang kami asumsikan untuk mencegah pengguna diganggu oleh iklan video web yang diputar otomatis. Kami menggunakan teknik yang mirip dengan solusi lain di web, yaitu menyalin frame video ke kanvas dan memperbarui waktu pencarian video secara manual, setiap 1/30 detik.

videoElement.addEventListener( 'timeupdate', function(){
    videoCanvas.paintFrame( videoElement );
});

function loopCanvas(){

    if( videoElement.readyState === videoElement.HAVE\_ENOUGH\_DATA ){

    const time = Date.now();
    const elapsed = ( time - lastTime ) / 1000;

    if( videoState.playing && elapsed &gt;= ( 1 / 30 ) ){
        videoElement.currentTime = videoElement.currentTime + elapsed;
        lastTime = time;
    }

    }

}

frameLoop.add( loopCanvas );

Pendekatan kami memiliki efek samping yang tidak menguntungkan, yaitu penurunan kecepatan frame iOS secara signifikan karena penyalinan buffer piksel dari video ke kanvas sangat membebankan CPU. Untuk menyiasati hal ini, kami hanya menayangkan versi video yang sama berukuran lebih kecil yang memungkinkan setidaknya 30 fps pada iPhone 6.

Kesimpulan

Konsensus umum untuk pengembangan software VR mulai tahun 2016 adalah untuk menjaga geometri dan shader tetap sederhana sehingga Anda dapat berjalan pada 90+ fps dalam HMD. Teknik ini ternyata menjadi target yang sangat bagus untuk demo WebGL karena teknik yang digunakan di Kuas Virtual memetakan dengan sangat baik ke WebGL.

Meskipun browser web yang menampilkan mesh 3D yang kompleks tidaklah menarik, hal ini adalah bukti konsep bahwa penyerbukan silang pekerjaan VR dan web sepenuhnya mungkin dilakukan.