เซสชันศิลปะเสมือนจริง

รายละเอียดเซสชันศิลปะ

สรุป

ศิลปิน 6 คนได้รับเชิญให้มาร่วมวาดภาพ ออกแบบ และแกะสลักใน VR ซึ่งเป็นกระบวนการที่เราบันทึกเซสชันของพวกเขา แปลงข้อมูล และนำเสนอในแบบเรียลไทม์ด้วยเว็บเบราว์เซอร์

https://g.co/VirtualArtSessions

ชีวิตสนุกจริงๆ! เมื่อมีการนำ Virtual Reality มาใช้เป็นผลิตภัณฑ์สำหรับผู้บริโภค ก็ทำให้เกิดการค้นพบความเป็นไปได้ใหม่ๆ ที่ยังไม่เคยสำรวจมาก่อน Tilt Brush ซึ่งเป็นผลิตภัณฑ์ Google บน HTC Vive ทำให้คุณสามารถวาดรูปในพื้นที่ สามมิติได้ เมื่อเราลองใช้ Tilt Brush เป็นครั้งแรก ความรู้สึกของการวาดรูปด้วยตัวควบคุมแบบติดตามการเคลื่อนไหวที่ผสานเข้ากับการได้ "อยู่ในห้อง ที่มีพลังพิเศษ" จะติดใจคุณ จริงๆ แล้ว ไม่เหมือนกับการได้วาดรูปในพื้นที่ว่างรอบๆ ตัวคุณเลย

งานศิลปะเสมือนจริง

ทีม Data Arts ที่ Google พบความท้าทายในการแสดงประสบการณ์นี้แก่ผู้ที่ไม่มีชุดหูฟัง VR บนเว็บที่ Tilt Brush ยังไม่ได้ให้บริการ ด้วยเหตุนี้ ทีมงานจึงได้เชิญประติมากร นักวาดภาพประกอบ นักออกแบบคอนเซ็ปต์ ศิลปินแฟชั่น ศิลปินนักแสดง และศิลปินสตรีทอาร์ตมาสร้างสรรค์งานศิลปะในสไตล์ของตนเองในสื่อรูปแบบใหม่นี้

การบันทึกภาพวาดในแบบ Virtual Reality

ซอฟต์แวร์ Tilt Brush สร้างขึ้นใน Unity และเป็นแอปพลิเคชันบนเดสก์ท็อปที่ใช้ VR ขนาดห้องเพื่อติดตามตำแหน่งศีรษะ (จอแสดงผลติดศีรษะหรือ HMD) และตัวควบคุมในมือแต่ละข้าง โดยค่าเริ่มต้น อาร์ตเวิร์กที่สร้างใน Tilt Brush จะส่งออกเป็นไฟล์ .tilt ในการนำประสบการณ์นี้มาสู่เว็บ เราทราบว่า เราต้องการมากกว่าแค่ข้อมูลอาร์ตเวิร์ก เราทำงานร่วมกับทีม Tilt Brush อย่างใกล้ชิดเพื่อแก้ไข Tilt Brush ให้ส่งออกการทำงานแบบเลิกทำ/ลบ ตลอดจนตำแหน่งหัวและมือของศิลปินในความเร็ว 90 ครั้งต่อวินาที

ขณะวาดภาพ Tilt Brush จะวางตำแหน่งและมุมตัวควบคุม แล้วแปลงหลายจุดในช่วงเวลาหนึ่งให้เป็น "เส้นโครงร่าง" ดูตัวอย่างได้ที่นี่ เราเขียนปลั๊กอินที่แยกเส้นโครงร่างเหล่านี้ออกมาและแสดงผลเป็น JSON แบบข้อมูลดิบ

    {
      "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
      ]
    }

ตัวอย่างด้านบนสรุปรูปแบบของรูปแบบ JSON สำหรับภาพร่าง

ที่นี่ ระบบจะบันทึกเส้นโครงร่างแต่ละรายการเป็นการดำเนินการ โดยเป็นประเภท "STROKE" นอกจากการดำเนินการด้านเส้นโครงร่างแล้ว เราต้องการแสดงให้เห็นศิลปินที่ทำผิดพลาดและเปลี่ยนใจภายหลังในร่างภาพ ดังนั้นการบันทึกการทำงานแบบ "ลบ" มีความสำคัญอย่างยิ่งยวด ไม่ว่าจะเป็นการลบหรือเลิกทำการดำเนินการสำหรับทั้งเส้นโครงร่าง

ระบบจะบันทึกข้อมูลพื้นฐานสำหรับแต่ละเส้นโครงร่าง เพื่อให้รวบรวมประเภทแปรง ขนาดแปรง และสี rgb เรียบร้อยแล้ว

สุดท้ายระบบจะบันทึกจุดยอดแต่ละจุดของเส้นโครงร่างไว้ รวมถึงตำแหน่ง มุม เวลา ตลอดจนความแรงของแรงกดดันของตัวควบคุม (ระบุเป็น p ภายในแต่ละจุด)

โปรดทราบว่าการหมุนคือควอเทอร์เนียน 4 คอมโพเนนต์ เรื่องนี้สำคัญภายหลังเมื่อเราแสดงเส้นโครงร่าง เพื่อหลีกเลี่ยงการล็อกกิมบอล

การเล่นสเก็ตช์หลังด้วย WebGL

ในการแสดงภาพสเก็ตช์ในเว็บเบราว์เซอร์ เราใช้ THREE.js และเขียนโค้ดการสร้างเรขาคณิตที่เลียนแบบสิ่งที่ Tilt Brush เป็นเทคโนโลยีขั้นสูง

เนื่องจาก Tilt Brush สร้างแถบสามเหลี่ยมแบบเรียลไทม์ตามการเคลื่อนไหวมือของผู้ใช้ แต่ภาพร่างทั้งหมดก็ "สิ้นสุด" แล้วตามเวลาที่เราแสดงในเว็บ ซึ่งทำให้เราสามารถหลีกเลี่ยงการคำนวณแบบเรียลไทม์จำนวนมากได้และค่อยๆ เพิ่มเรขาคณิตขึ้นมาในขณะที่โหลด

ภาพสเก็ตช์ WebGL

จุดยอดแต่ละคู่ในเส้นโครงร่างจะสร้างเวกเตอร์ทิศทาง (เส้นสีน้ำเงินเชื่อมแต่ละจุดตามที่แสดงข้างต้น moveVector ในข้อมูลโค้ดด้านล่าง) แต่ละจุดยังมีการวางแนว ควอเทิร์นที่แสดงมุมปัจจุบันของตัวควบคุม ในการสร้างแถบสามเหลี่ยม เราจะทำซ้ำแต่ละจุดเพื่อสร้างเส้นปกติซึ่งตั้งฉากกับทิศทางและการวางแนวของตัวควบคุม

ขั้นตอนการคำนวณแถบสามเหลี่ยมสำหรับแต่ละเส้นโครงร่างจะเหมือนกับโค้ดที่ใช้ใน Tilt Brush ดังนี้

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

การรวมทิศทางของเส้นโครงร่างและการวางแนวด้วยตัวเองจะให้ผลลัพธ์ที่กำกวมทางคณิตศาสตร์ อาจมีการคำนวณปกติหลายข้อและมักทำให้เกิด "การบิด" ในเรขาคณิต

เมื่อทำซ้ำจุดของเส้นโครงร่าง เราจะคงเวกเตอร์ "ขวาที่ต้องการ" ไว้และส่งผ่านสิ่งนี้ไปยังฟังก์ชัน computeSurfaceFrame() ฟังก์ชันนี้ทำให้เราวาดรูปสี่เหลี่ยมในแนวแถบสี่เหลี่ยมได้ปกติ โดยอิงตามทิศทางของเส้นโครงร่าง (จากจุดสุดท้ายถึงจุดปัจจุบัน) และการวางแนวของตัวควบคุม (ควอเทอร์เนียน) ที่สำคัญกว่านั้น ยังแสดงผลเวกเตอร์ "ขวาที่ต้องการ" ใหม่สำหรับการคำนวณชุดถัดไปด้วย

เส้น

หลังจากสร้างสี่เหลี่ยมจัตุรัสตามจุดควบคุมของแต่ละสโตรกแล้ว เราจะรวมสี่เหลี่ยมจัตุรัสโดยการประมาณมุมจากจุดหนึ่งไปยังจุดถัดไป

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 );
}
สี่เหลี่ยมจัตุรัสรวม
Fused Quads

สี่เหลี่ยมแต่ละรูปยังมียูวีที่สร้างขึ้นในขั้นตอนถัดไป แปรงบางตัวมีรูปแบบเส้นโครงร่างที่หลากหลายเพื่อให้ความรู้สึกว่าแต่ละเส้นให้ความรู้สึกเหมือนเส้นที่แตกต่างกันของพู่กัน ซึ่งทำได้โดยใช้ _texture atlasing _ที่แต่ละพื้นผิวของแปรงจะมีรูปแบบที่เป็นไปได้ทั้งหมด เลือกพื้นผิวที่ถูกต้องโดยการปรับค่ายูวีของเส้นโครงร่าง

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

    });

}
พื้นผิว 4 ลายในสมุดแผนที่พื้นผิวสำหรับแปรงน้ำมัน
4 พื้นผิวในหนังสือภาพพื้นผิวสำหรับแปรงพ่นน้ำมัน
ใน Tilt Brush
ใน Tilt Brush
ใน WebGL
ใน WebGL

เนื่องจากภาพร่างแต่ละภาพมีจำนวนเส้นโครงร่างไม่จำกัด และไม่จำเป็นต้องแก้ไขเส้นโครงร่าง เราจึงคำนวณเรขาคณิตของเส้นโครงร่างไว้ล่วงหน้าและผสานเป็นเส้นโครงร่างไว้ในตาข่ายเดียว แม้ว่าแปรงใหม่แต่ละประเภทจะต้องเป็นวัสดุของตัวมันเอง แต่ก็ยังลดการเรียกให้เหลือ 1 ครั้งต่อแปรงได้

ภาพร่างทั้งหมดข้างต้นดำเนินการในการเรียกครั้งเดียวใน WebGL
การร่างภาพทั้งหมดข้างต้นทำในการเรียกครั้งเดียวใน WebGL

ในการทดสอบระบบอย่างเครียด เราสร้างภาพร่างที่ใช้เวลา 20 นาทีในการเติมจุดยอดมุมให้มากที่สุดเท่าที่จะทำได้ ภาพสเก็ตช์ที่ได้จะยังคงเล่นที่ 60 FPS ใน WebGL

เนื่องจากจุดยอดเดิมแต่ละจุดของเส้นโครงร่างก็มีเวลาด้วย เราจึงแสดงข้อมูลได้อย่างง่ายดาย การคำนวณเส้นโครงร่างต่อเฟรมใหม่นั้นช้ามาก เราจึงคำนวณภาพร่างทั้งหมดไว้ล่วงหน้าเมื่อโหลดเสร็จ และเพียงแค่แสดงสี่เหลี่ยมจัตุรัสแต่ละชิ้นเมื่อถึงเวลา

การซ่อนรูปสี่เหลี่ยมหมายถึงการยุบจุดยอดมุมเป็นจุด 0,0,0 เมื่อถึงเวลาแสดงจุดที่รูปสี่เหลี่ยมจะแสดง เราจะย้ายตำแหน่งจุดยอดมุมกลับเข้าที่

ส่วนที่ต้องปรับปรุงคือการควบคุมจุดยอดทั้งหมดบน GPU ด้วยเฉดสี การใช้งานปัจจุบันจะวางจุดยอดเหล่านั้นโดยวนซ้ำอาร์เรย์จุดยอดมุมจากการประทับเวลาปัจจุบัน ตรวจสอบว่าจุดยอดใดบ้างที่ต้องแสดงแล้วอัปเดตเรขาคณิต ซึ่งจะใช้ CPU มาก และทำให้พัดลมหมุน ตลอดจนสิ้นเปลืองแบตเตอรี่

งานศิลปะเสมือนจริง

การบันทึกเสียงศิลปิน

เราคิดว่าภาพสเก็ตช์ยังไม่พอ เราอยากให้ศิลปินเห็นภาพ ในสเก็ตช์ภาพโดยการวาดภาพแต่ละพู่กัน

ในการจับภาพศิลปิน เราใช้กล้อง Microsoft Kinect เพื่อบันทึกความลึกของร่างกายศิลปินในอวกาศ วิธีนี้จะช่วยให้เราแสดงรูป 3 มิติ ในพื้นที่เดียวกับที่ภาพวาดปรากฏขึ้นได้

เนื่องจากร่างกายของศิลปินจะบังตัวทำให้เราไม่เห็นสิ่งที่อยู่เบื้องหลัง เราจึงใช้ระบบ Kinect ทั้ง 2 ด้านในฝั่งตรงข้ามของห้องโดยชี้ไปที่กึ่งกลาง

นอกจากข้อมูลความลึกแล้ว เรายังบันทึกข้อมูลสีของฉากด้วยกล้อง DSLR แบบมาตรฐาน เราใช้ซอฟต์แวร์ DepthKit ที่ยอดเยี่ยมในการปรับเทียบและผสานฟุตเทจจากกล้องที่มีความลึกและกล้องสี Kinect สามารถบันทึกสีได้ แต่เราเลือกใช้กล้อง DSLR เพราะสามารถควบคุมการตั้งค่าการเปิดรับแสง ใช้เลนส์ระดับไฮเอนด์สวยๆ และบันทึกด้วยความละเอียดสูงได้

ในการบันทึกฟุตเทจ เราได้สร้างห้องพิเศษเพื่อจัดเก็บ HTC Vive ศิลปินและกล้องดังกล่าว ทุกพื้นผิวถูกปกคลุมด้วยวัสดุที่ดูดซับแสงอินฟราเรด เพื่อให้เราได้พอยต์คลาวด์ที่สะอาดตาขึ้น (มีนวมบนผนัง ยางบนพื้นเป็นริ้ว) ในกรณีที่วัสดุปรากฏในฟุตเทจ พอยต์คลาวด์ เราเลือกวัสดุสีดำไว้เพื่อให้ไม่รบกวนสายตาเหมือนกับสีขาว

ศิลปินที่บันทึก

การบันทึกวิดีโอที่ได้นั้นให้ข้อมูลที่เพียงพอสำหรับเราในการฉายภาพระบบอนุภาค เราเขียนเครื่องมือเพิ่มเติมบางอย่างใน openFrameworks เพื่อทำความสะอาดฟุตเทจให้ดียิ่งขึ้น โดยเฉพาะอย่างยิ่งการนำพื้น ผนัง และเพดานออก

ทั้ง 4 ช่องของเซสชันวิดีโอที่บันทึกไว้ (ช่องสี 2 ช่องด้านบนและความลึก 2 ช่องด้านล่าง)
ช่องทั้ง 4 ช่องของเซสชันวิดีโอที่บันทึกไว้ (ช่องสี 2 ช่องด้านบนและความลึก 2 ช่องด้านล่าง)

นอกจากแสดงภาพศิลปินแล้ว เรายังอยากแสดงภาพ HMD และ คอนโทรลเลอร์ในแบบ 3 มิติด้วย วิธีนี้ไม่เพียงสำคัญต่อการแสดง HMD ในผลลัพธ์สุดท้ายอย่างชัดเจน (เลนส์สะท้อนแสงของ HTC Vive ขจัดค่า IR ของ Kinect) เท่านั้น แต่ยังช่วยให้เรามีจุดสัมผัสในการแก้ไขข้อบกพร่องของผลการอนุภาคและจัดแถววิดีโอด้วยภาพสเก็ตช์

อุปกรณ์แสดงผล ตัวควบคุม และอนุภาคที่ติดศีรษะ
อุปกรณ์แสดงผล ตัวควบคุม และอนุภาคที่ติดศีรษะติดศีรษะ

ซึ่งทำได้โดยการเขียนปลั๊กอินที่กำหนดเองลงใน Tilt Brush แยกตำแหน่งของ HMD และตัวควบคุมแต่ละเฟรม เนื่องจาก Tilt Brush ทำงานที่ 90fps ข้อมูลจำนวนมากจึงถูกสตรีมออกและข้อมูลอินพุตของสเก็ตช์จึงสูงเกิน 20MB โดยไม่มีการบีบอัด นอกจากนี้ เรายังใช้เทคนิคนี้เพื่อบันทึกเหตุการณ์ที่ไม่ได้บันทึกไว้ในไฟล์บันทึกของ Tilt Brush เช่น เมื่อศิลปินเลือกตัวเลือกบนแผงเครื่องมือและตำแหน่งของวิดเจ็ตมิเรอร์

ในการประมวลผลข้อมูลขนาด 4 TB ที่เราบันทึกได้ อุปสรรคใหญ่ที่สุดอย่างหนึ่งคือการปรับแหล่งข้อมูลภาพ/ข้อมูลที่แตกต่างกันทั้งหมด วิดีโอแต่ละรายการจากกล้อง DSLR จะต้องอยู่ในแนวเดียวกับ Kinect เพื่อให้พิกเซลอยู่ในแนวนอนและเวลา จากนั้นฟุตเทจจากแท่นวางกล้อง 2 ตัวนี้จะต้องวางคู่กัน เพื่อสร้างศิลปินเดียวกัน จากนั้นเราก็ต้องจัดแนวศิลปิน 3 มิติ กับข้อมูลที่บันทึกจากภาพวาด ในที่สุด เราเขียนเครื่องมือบนเบราว์เซอร์เพื่อช่วยในการทำงานส่วนใหญ่เหล่านี้ และคุณลองใช้งานได้ที่นี่

ศิลปินผู้บันทึกเสียง

เมื่อจัดเรียงข้อมูลแล้ว เราใช้สคริปต์บางรายการที่เขียนใน NodeJS เพื่อประมวลผลข้อมูลทั้งหมด และเอาต์พุตไฟล์วิดีโอและชุดไฟล์ JSON ซึ่งทั้งหมดถูกตัดและซิงค์ เราทำ 3 สิ่งต่อไปนี้เพื่อลดขนาดไฟล์ ก่อนอื่น เราลดความแม่นยำของจำนวนจุดลอยตัวแต่ละจุดให้เหลือทศนิยมไม่เกิน 3 ตำแหน่ง ประการที่ 2 เราตัดจำนวนจุดลง 1 ใน 3 เป็น 30 FPS และ ประมาณตำแหน่งฝั่งไคลเอ็นต์ สุดท้าย เราเรียงอันดับข้อมูลเพื่อให้แทนที่จะใช้ JSON ธรรมดากับคู่คีย์/ค่า ระบบจะสร้างลำดับของค่าสำหรับตำแหน่งและการหมุนเวียนของ HMD และตัวควบคุม นี่จะลดขนาดไฟล์ให้เหลือเพียง 3MB ซึ่งสามารถนำส่งข้ามสายได้

ศิลปินบันทึกเสียง

เนื่องจากตัววิดีโอเองทำหน้าที่เป็นองค์ประกอบวิดีโอ HTML5 ที่มีการอ่านผ่านพื้นผิว WebGL จนกลายเป็นอนุภาค ตัววิดีโอเองจึงต้องเล่นโดยซ่อนอยู่ในเบื้องหลัง ตัวปรับเฉดสีจะแปลงสีในภาพความลึกเป็นตำแหน่งในพื้นที่ 3 มิติ James George ได้แชร์ตัวอย่างที่ยอดเยี่ยม เกี่ยวกับวิธีการใช้ฟุตเทจจาก DepthKit โดยตรง

iOS มีข้อจำกัดในการเล่นวิดีโอแบบในหน้า ซึ่งเราถือว่ามีไว้เพื่อป้องกันไม่ให้ผู้ใช้ถูกรบกวนโดยโฆษณาวิดีโอบนเว็บที่เล่นอัตโนมัติ เราใช้เทคนิคที่คล้ายกับวิธีแก้ปัญหาเบื้องต้นอื่นๆ บนเว็บ ซึ่งก็คือการคัดลอกเฟรมวิดีโอลงในผืนผ้าใบและอัปเดตเวลากรอวิดีโอด้วยตนเองทุกๆ 1/30 วินาที

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 >= ( 1 / 30 ) ){
        videoElement.currentTime = videoElement.currentTime + elapsed;
        lastTime = time;
    }

    }

}

frameLoop.add( loopCanvas );

แนวทางของเราส่งผลข้างเคียงอย่างน่าเสียดายตรงที่จะลดเฟรมของ iOS ลงอย่างมาก เนื่องจากการคัดลอกบัฟเฟอร์พิกเซลจากวิดีโอไปยัง Canvas นั้นใช้ CPU มาก ในการแก้ปัญหานี้ เราเพียงแสดงวิดีโอเดียวกันในเวอร์ชันขนาดเล็กลงซึ่งอนุญาตให้ใช้ 30 fps เป็นอย่างน้อยใน iPhone 6

บทสรุป

ฉันทามติทั่วไปสำหรับการพัฒนาซอฟต์แวร์ VR ในปี 2016 คือการทำให้ภูมิศาสตร์และเฉดสีเรียบง่ายเพื่อให้ทำงานใน 90 FPS ขึ้นไปใน HMD และกลายเป็นเป้าหมายที่ยอดเยี่ยมสำหรับการสาธิต WebGL เนื่องจากเทคนิคที่ใช้ใน Tilt Brush ทำแผนที่กับ WebGL ได้อย่างสวยงาม

แม้ว่าเว็บเบราว์เซอร์ที่แสดงโครงข่าย 3 มิติที่ซับซ้อนจะไม่ใช่สิ่งที่น่าตื่นเต้นในตัววิดีโอเอง แต่สิ่งนี้ก็เป็นข้อพิสูจน์ถึงแนวคิดที่ว่าการหลอมรวมของงาน VR และเว็บเป็นไปได้ทั้งหมด