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

รายละเอียดเซสชันอาร์ตเวิร์ก

สรุป

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

https://g.co/VirtualArtSessions

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

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

ทีมศิลปะจากข้อมูลของ 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 องค์ประกอบ ซึ่งสำคัญในภายหลังเมื่อเราแสดงผลเส้นเพื่อหลีกเลี่ยงการล็อกของ Gimbal

เล่นภาพสเก็ตช์ด้วย 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() ฟังก์ชันนี้จะให้ค่าปกติซึ่งเรานำมาใช้สร้างรูปสี่เหลี่ยมจัตุรัสในแถบรูปสี่เหลี่ยมจัตุรัสได้ โดยอิงตามทิศทางของเส้น (จากจุดสุดท้ายไปยังจุดปัจจุบัน) และการวางแนวของตัวควบคุม (Quaternion) และที่สำคัญกว่านั้น ฟังก์ชันนี้จะแสดงผลเวกเตอร์ "ขวาที่แนะนำ" ใหม่สําหรับชุดการคํานวณถัดไปด้วย

เส้น

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

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 );
}
รูปสี่เหลี่ยมผืนผ้าที่ผสาน
Quad ที่ผสาน

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

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 รายการใน Atlas พื้นผิวสำหรับแปรงน้ำมัน
พื้นผิว 4 รายการใน Atlas พื้นผิวสำหรับแปรงน้ำมัน
ใน Tilt Brush
ใน Tilt Brush
ใน WebGL
ใน WebGL

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

ภาพสเก็ตช์ทั้งหมดด้านบนจะดำเนินการในการเรียกใช้การวาดครั้งเดียวใน WebGL
ภาพสเก็ตช์ทั้งหมดด้านบนดำเนินการในการเรียกใช้การวาดครั้งเดียวใน WebGL

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

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

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

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

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

การบันทึกศิลปิน

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

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

เนื่องจากร่างกายของศิลปินจะบดบังกันและทำให้เราไม่เห็นสิ่งที่อยู่ด้านหลัง เราจึงใช้ระบบ 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 ทำงานที่ 90 fps ระบบจึงสตรีมข้อมูลจำนวนมากออกและข้อมูลอินพุตของภาพสเก็ตช์มีขนาดใหญ่กว่า 20 MB โดยไม่ผ่านการบีบอัด นอกจากนี้ เรายังใช้เทคนิคนี้เพื่อบันทึกเหตุการณ์ที่ไม่ได้บันทึกไว้ในไฟล์บันทึกของ Tilt Brush ทั่วไป เช่น เมื่อศิลปินเลือกตัวเลือกในแผงเครื่องมือและตำแหน่งวิดเจ็ตกระจก

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

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

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

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

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

iOS มีข้อจํากัดในการเล่นวิดีโอในหน้าเว็บ ซึ่งเราคิดว่ามีไว้เพื่อป้องกันไม่ให้ผู้ใช้ถูกรบกวนจากโฆษณาวิดีโอบนเว็บที่เล่นอัตโนมัติ เราใช้เทคนิคที่คล้ายกับวิธีแก้ปัญหาอื่นๆ บนเว็บ ซึ่งก็คือการคัดลอกเฟรมวิดีโอลงใน Canvas และอัปเดตเวลากรอวิดีโอด้วยตนเองทุกๆ 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 จะลดลงอย่างมากเนื่องจากการคัดลอกบัฟเฟอร์พิกเซลจากวิดีโอไปยังแคนวาสต้องใช้ CPU เป็นอย่างมาก วิธีแก้ปัญหานี้ก็คือ เราแสดงวิดีโอเดียวกันในเวอร์ชันขนาดเล็กซึ่งเล่นได้อย่างน้อย 30 fps ใน iPhone 6

บทสรุป

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

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