虛擬藝術課程

Art Session 詳細資料

摘要

六位藝術家受邀在 VR 中繪畫、設計和雕刻。這是 像是記錄工作階段、轉換數據 透過網路瀏覽器即時執行

https://g.co/VirtualArtSessions

活出的美好時光!隨著消費者進入虛擬實境 並且探索各種可能性。魔幻畫筆、 適用於 HTC Vive 的 Google 產品 平面空間第一次嘗試「魔幻畫筆」時 搭配動態追蹤控制器繪製圖片,同時出現 「有超能力的房間」與您保持互動其實完全無法 像是在周遭空白處繪圖

虛擬藝術品

Google 的資料藝術團隊面臨一項挑戰,要展現這個構想 體驗沒有 VR 頭戴式裝置的使用者, 目前運作的內容為此,該團隊打造了雕塑家、插畫家 概念設計師、時裝藝術家、裝置藝術藝術家和街頭藝人 製作出風格獨具的藝術品

在虛擬實境中錄製繪圖

內建於 Unity 中的 Tilt Brush 軟體本身,就是電腦版應用程式 使用房間規模的 VR 追蹤頭部位置 (頭戴式顯示器或 HMD) 和每隻手的控制器使用魔幻畫筆製作的圖片 預設匯出為 .tilt 檔案為了在網路上提供這項服務 後來發現除了圖片資料外我們與 Tilt Brush 團隊修改魔幻筆刷,一併匯出復原/刪除動作 作為藝術家頭部和手部位置在每秒 90 倍的位置

繪圖時,魔術筆刷會擷取控制器位置與角度,然後換算成 轉換為「筆觸」。您可以在畫面中找到 請按這裡。 我們編寫的外掛程式擷取這些動作,並將其輸出為原始 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」。除了 我們希望能向藝人展示,改變方法 所以在思緒中,請務必儲存「DELETE」,這點十分重要用來做為 清除或復原整個筆劃操作。

系統會儲存每個筆劃的基本資訊,例如:筆刷類型、筆刷大小、顏色 RGB 全數收集完畢。

最後,系統會儲存筆劃的每個頂點,其中包含位置 角度、時間和控制器的觸發壓力強度 (註明 p 各時間點內的內容)

請注意,旋轉角度為 4 個元件四元數。日後 我們會算繪筆觸,避免重頭鎖定

使用 WebGL 播放背景素描

為了在網路瀏覽器中顯示草圖,我們使用 THREE.js 編寫了惡意的幾何圖形產生程式碼 「魔術筆」工具實際上具備哪些功能

魔幻畫筆會根據使用者的手即時產生三角形條紋 這張圖的全貌已經「完成」而是依據實際使用情境的時間 在網路上。這樣就能略過大部分的即時計算及烘焙模式 載入時達成的幾何圖形

WebGL 草圖

每組筆劃中的一對頂點都會產生一個方向向量 (藍線) 來連結每個點,如上所示,以下程式碼片段中的 moveVector)。 每個點也包含一個方向,也就是代表 控制器目前的角度為了產生三角形邊長,我們會逐一執行 產生與方向垂直的正常值 控制器方向

計算每個筆劃三角形線條的程序幾乎相同 與魔幻筆刷搭配使用的程式碼:

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 );
}
敬上
融合式四捨五入
融合式四捨五入。

每個四變形也含有做為下一步產生的 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 款紋理貼圖送上油漆用的紋理
適用於油畫的紋理圖集,有四個紋理
魔幻畫筆
魔術筆刷
在 WebGL 中
在 WebGL 中

由於每個素描都沒有限制筆劃,所以筆劃不需要 而在執行階段中修改時,我們會預先計算筆劃幾何圖形,然後加以合併 並納入單一網格雖然每種新的筆刷類型都必須有自己的 仍可將繪製呼叫減少為每次筆刷只能呼叫 1 次。

上方整個草圖都是在 WebGL 中透過單一繪製呼叫執行
上述整個草圖都是在 WebGL 中透過單一繪製呼叫執行

為了進行壓力測試,我們繪製出一個需要 20 分鐘的 空間,盡量增加頂點產生的草圖仍在 WebGL 為 60fps。

由於筆劃的每個原始頂點也包含時間,因此我們可以 還是能輕鬆播放資料重新計算每個影格的筆劃會真的 反之,因此我們在載入時預先計算整個草圖 所以不會打斷訓練

隱藏四點只是將頂點收合到 0,0,0 點。當 已經到局勢必得揭曉 重新調整頂點的位置

有待改進的地方 是完全在 GPU 上操控頂點 著色器。目前的實作方式會循環通過頂點,以放置這些元素 來自目前時間戳記的陣列,檢查需要揭露哪些頂點 然後更新幾何圖形這會增加 CPU 負載 風扇運轉及浪費電池壽命。

虛擬藝術品

錄製藝人

我們認為素描本身是不夠的。我們想展示 在素描中畫出每個筆刷。

為了捕捉藝術家的影像,我們使用 Microsoft Kinect 攝影機錄下深度 藝人專用太空中的身體這讓我們能顯示 就會顯示繪製在相同空間內的三維圖形

藝人的身體會遮住這裡,無法看到 並在房間正反面使用雙 Kinect 系統 並指向中心區域

除了深度資訊外,我們還擷取了 拍攝場景。我們使用了 用於校準及合併的 DepthKit 軟體 包括深度相機和彩色攝影機拍攝的影片片段Kinect 可以 但之所以選擇使用數位單眼相機 是因為我們能控制 曝光設定、使用精美的高階鏡頭,並以高畫質錄製。

為此,我們打造了特別的房間,讓這名藝術家 HTC Vive 使用 和相機之間所有表面都覆蓋了吸收紅外線的材質 可以賦予我們更簡潔的單點雲朵 (牆壁上的絨毛、絲絨橡膠) 地板的墊料)。以防材質出現在單點雲中的情況 我們選了黑色材料,所以不如 那是白色的。

歌手

這些錄製的影片能帶給我們足夠的資訊,讓我們能投影粒子 有些人會將 Cloud Storage 視為檔案系統 但實際上不是我們在 openFrameworks 進一步清理影片片段, 特別是地板、牆壁和天花板。

觀看錄影內容的全部四個頻道 (上方有兩個色彩頻道,上方有兩個色頻道)
深度如下)
在錄影工作階段的所有四個頻道中 (上方有兩個顏色頻道和兩個頻道) 詳細說明)

除了展示藝人外,我們也希望呈現 HMD 編碼器和 推出 3D 控制器這不只要呈現 最終的輸出結果清晰可辨 (HTC Vive 的反光鏡片脫落) Kinect 的 IR 讀數),讓我們可以聯繫我們用來對粒子偵錯的聯絡窗口 並以草圖排列影片畫面

頭戴式顯示器、控制器和粒子排列顯示
頭部安裝螢幕、控制器和粒子排成

做法是將自訂外掛程式寫入魔幻畫筆中 HMD 和控制器之間的位置由於魔術筆刷以 90 FPS 執行, 大量串流資料,草圖的輸入資料增加至 20 MB 未壓縮。此外,我們也使用這項技術擷取未記錄到的事件 一般的魔術筆刷儲存檔案 例如藝術家選擇某個項目 以及鏡像小工具的位置

我們在處理擷取到的 4 TB 資料時,面臨的最大挑戰之一就是 各項圖像/資料來源的對應關係透過數位單眼相機拍攝的每部影片 必須與對應的 Kinect 對齊,讓像素 大幅提高接著,這兩個鏡頭槽的片段 彼此協調,形成單一藝人接著,將 3D 圖像 從繪圖中擷取到數據和音樂大功告成!以瀏覽器為基礎 這些工具可協助您完成大部分的工作 您也可以親自試用 這裡

唱片藝人

資料校正後,我們使用一些以 NodeJS 編寫的指令碼進行處理 都會輸出一個影片檔案和一系列的 JSON 檔案 同步處理。我們做了三件事來縮減檔案大小首先,我們縮減了 更準確的浮點數,要求最多不超過 3 個浮點數 小數的精確度。其次,我們將分數數量減為三分之一 30fps,並在用戶端插入廣告位置。最後,我們將 因此,與其使用純 JSON 格式搭配鍵/值組合,值的順序是 專為 HMD 和控制器的位置與旋轉而建立。即可剪下檔案 大小適中,只有 3MB 這種大小可以通過電線。

唱片藝人

影片本身是以 HTML5 影片元素的形式放送, 要成為粒子的 WebGL 紋理,影片本身需要隱藏在 背景。著色器會將深度圖像的顏色轉換成 3D 空間。James George 分享了一個絕佳範例 說明如何直接使用 DepthKit 的影片片段

iOS 對內嵌影片播放設有限制,我們相信這是為了避免 使用者就不會受到自動播放的網路影片廣告幹擾我們使用了技巧 Google 提供的其他解決方案 網站,以便複製 將影片影格擷取到畫布上,接著每 1/30 次手動更新影片跳轉時間 1 秒

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 資源。為瞭解決這個問題,我們只針對 包括 iPhone 6 播放至少 30 FPS 的影片

結論

截至 2016 年,VR 軟體開發領域普遍達成了共識 簡單的幾何形狀和著色器,在 HMD 中能以 90 fps 以上的速度執行。這個 後來,這項工具就是 WebGL 示範的絕佳目標 與 WebGL 十分合作

雖然網路瀏覽器顯示複雜的 3D 網格,但對於 從這個概念驗證,便是將 VR 專案與 網路完全是可能的