概要
6 人のアーティストに VR でのペイント、デザイン、彫刻が紹介されました。これが セッションを記録し、データを変換して、プレゼンテーションの ウェブブラウザでリアルタイムに作成できます。
https://g.co/VirtualArtSessions
こんなに生きているなんて!消費者としてバーチャル リアリティが登場したことで、 新たな可能性が次々と見つかっています。Tilt Brush、 HTC Vive で利用可能な Google プロダクトでは、 あります。Tilt Brush を初めて試したときは モーション トラッキング コントローラを組み込んだスケッチと、 「超能力を持つ会議室」をユーザーとともにいる。ユーザーエクスペリエンスが 周りの何もない空間に描き出すことです。
Google のデータアート チームは、 ウェブ版の VR ヘッドセットなしでも、Tilt Brush では利用できない あります。そのために、彫刻家、イラストレーター、 コンセプト デザイナー、ファッション アーティスト、インスタレーション アーティスト、ストリート アーティスト この新しいメディアで 独自のスタイルでアートワークを作成できます
バーチャル リアリティで描画を録画する
Unity で構築された Tilt Brush ソフトウェア自体は、
ルームスケールの VR で頭の位置を追跡します(ヘッドマウント ディスプレイ、HMD)
コントローラを手に持っています。Tilt Brush のアートワークの作成者:
デフォルトは .tilt
ファイルとしてエクスポートされます。このエクスペリエンスをウェブでも利用できるようにするために、
アートワークのデータ以外のものも
必要だと考えました私たちは
Tilt Brush チームが Tilt Brush を変更して、元に戻す/削除のアクションもエクスポートできるようにしました
頭と手の位置を 1 秒に 90 回繰り返すことになります
Tilt Brush は描画時にコントローラの位置と角度を取得し、 複数のポイントを「ストローク」に変換します。Google Cloud コンソールの こちらをご覧ください。 これらのストロークを抽出し、未加工の 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」になっています。これらに加えて、 ストロークアクションを 修正して 考えていたら [削除]を保存することが重要でしたアクション モデルです。 ストローク全体の操作を元に戻すことができます。
各ストロークの基本情報が保存されるため、ブラシの種類、ブラシのサイズ、色 すべて収集されます
最後にストロークの各頂点が保存されます。これには位置、頂点、
角度、時間、コントローラのトリガー圧力(p
と表記)
あります)。
回転は 4 成分の四元数であることに注意してください。これは後で ジンバルロックを避けるために ストロークがレンダリングされます
WebGL でスケッチを再生する
ウェブブラウザでスケッチを表示するために、 THREE.js を作成し、それを模倣したジオメトリ生成コードを作成しました。 Tilt Brush の仕組みを説明します。
Tilt Brush はユーザーの手の形に基づいてリアルタイムで三角形のストリップを作成します。 スケッチ全体がすでに「完成」していますいつまでも続きます できます。これにより リアルタイムの計算処理の多くをバイパスして 読み込み時にジオメトリを表示します。
ストロークを構成する各頂点のペアから方向ベクトル(青い線)が
各ポイントを上のように接続します(以下のコード スニペットでは 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 );
}
各クワッドには、次のステップとして生成される UV も含まれます。一部のブラシ さまざまなストロークパターンが含まれており、ストロークごとに 絵筆の絵の具材が違ったような感じです。これには 各ブラシのテクスチャに可能な あります。オブジェクトの 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 );
});
}
各スケッチのストローク数は無制限であり、 ストローク ジオメトリを事前に計算して統合し、 1 つのメッシュにできます新しいブラシタイプは、それぞれ独自の ブラシごとに 1 回描画呼び出しを減らすことができます。
<ph type="x-smartling-placeholder">システムのストレステストを実施するために、 できる限り多くの頂点を持つスペースを 作成する必要があります。完成したスケッチは、 WebGL で 60 fps。
ストロークの元の各頂点にも時間が含まれていたため、 簡単にデータを再生できるようになります。フレームごとのストロークを再計算するのは 読み込み時にスケッチ全体を事前計算して、 アラートを生成しました。
クワッドを非表示にするということは、単にその頂点を 0,0,0 ポイントに折りたたむことを意味していました。Google クワッドが表示されるはずの時点に到達し、 頂点の位置を元の位置に戻します
改善の余地があるのは、GPU を使用して、頂点をすべて GPU で操作することです。 使用できます。現在の実装では、頂点をループして配置します。 表示する必要がある頂点を確認するための、現在のタイムスタンプから配列 ジオメトリを更新しますCPU に多くの負荷がかかるため ファンの回転とバッテリーの消耗が早まります。
アーティストをレコーディングする
スケッチだけでは不十分だと考えました。今回は アーティストたちがスケッチの中にし、ブラシストロークを 1 つずつ描いている。
アーティストを捉えるために Microsoft の Kinect カメラを使用して奥行きの アーティストのデータです。これにより 同じ空間に 3 次元の図形が現れることです。
芸術家の身体が閉まってしまうため その背後では 2 つの Kinect システムを使用して、部屋の反対側に設置しました。 指しています。
奥行き情報に加えて、画像のカラー情報もキャプチャしました。 標準的なデジタル一眼レフカメラで撮影できます。優良な特徴量を使用した 調整と統合のための DepthKit ソフトウェア 深度カメラとカラーカメラで生成された映像を確認できますKinect は 記録の色はさまざまですが デジタル一眼レフを 使用することにしました 露出設定、美しいハイエンド レンズの使用、高解像度での撮影が可能です。
映像を記録するために、アーティストの HTC Vive を収容する特別な部屋を用意しました です。すべての表面が赤外線を吸収する素材で覆われている 光が当たり前の点をきれいにできる マットを敷くなど)。資料がポイントクラウドに表示された場合は 動画では 動画の邪魔にならないように 白でした。
撮影した動画から、素粒子を投影するのに十分な情報が得られました ありません追加のツールについては、 openFrameworks を使用して、映像をさらにクリーンアップし、 特に床、壁、天井の撤去などです
<ph type="x-smartling-placeholder">アーティストを表示するだけでなく、HMD と 3D のコントローラも作成しました。これは、HMD を表示するうえで重要であるだけでなく、 (HTC Vive の反射レンズはレンズが乱れていました) Kinect の IR 測定値など)を使用して、粒子をデバッグするための連絡窓口となりました。 動画の並べ方です
<ph type="x-smartling-placeholder">これは、カスタム プラグインを Tilt Brush に書き込み、 各フレームで HMD とコントローラの位置を推定します。Tilt Brush は 90fps で動作し 大量のデータがストリーミングされ スケッチの入力データが 非圧縮ですまた、この手法を使用して、記録されていないイベントをキャプチャしました。 アーティストがオプションを選択したときなど、典型的な Tilt Brush 保存ファイル内 ミラー ウィジェットの位置を変更できます。
収集した 4TB のデータの処理において 最大の課題の一つは 調整する必要がありますデジタル一眼レフカメラの映像ごとに 対応する Kinect に合わせ、ピクセルが 1 つずつ スペースと時間で決まります。2 台のカメラで撮影する映像は 1 つのアーティストになります。次に、3D の画像を データを取り込むことができますぜひブラウザベースの ツールが用意されているため、自分でも試してみることもできます。 こちら
データを揃えたら、NodeJS で記述されたいくつかのスクリプトを使用してデータを処理しました。 動画ファイルと一連の JSON ファイルを出力します。 同期できます。ファイルサイズを小さくするために、3 つのことを行いました。まず 最大 3 になるように、各浮動小数点数の精度 10 進数で表します次に、ポイント数を 1/3 削減して、 して、クライアントサイドで位置を補間しました。最後に、UDM で定義された そのため、Key-Value ペアを含む書式なし JSON を使用する代わりに、 HMD とコントローラの位置と回転のために作成されています。これにより、ファイルがカットされます。 わずか 3 MB のサイズに縮小され、ワイヤレスでの送信は許容範囲内でした。
動画自体は、HTML5 動画要素として配信され、 WebGL テクスチャを粒子にして、動画自体を 説明します。シェーダーは、奥行きのある画像の色を 3D 空間James George による好例 動画を使って方法を説明しました。
iOS ではインライン動画再生に制限があります。これは、 ウェブ動画広告が自動再生されるためユーザーが 煩わされるのを防げます手法を使用して、 方法はアップグレードの web は、 動画フレームをキャンバスに読み込み、動画のシーク時間を手動で更新し、 見てみましょう。
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 );
Google の手法では、iOS アプリの大幅なコスト削減という残念な副作用が 動画からキャンバスへのピクセル バッファのコピーは処理に時間がかかるため、 CPU 使用率が高い。この問題を回避するために、サイズの小さいバージョンを iPhone 6 で最低 30 fps を可能にするのと同じ動画です。
まとめ
2016 年時点での VR ソフトウェア開発の全般的なコンセンサスは、 ジオメトリとシェーダーをシンプルにし、HMD で 90 fps で実行できます。この WebGL を使用したデモでは WebGL に適切に対応しています
複雑な 3D メッシュを表示するウェブブラウザは、 これは VR 作品と世界中の人々を相互に作用させる ウェブでできることはたくさんあります。