poipoiです。

技術的ななにかと、そうじゃないなにか。

THETA S x vvvv でリアルタイム360°ビューワーつくった話

こちらは vvvv Advent Calendar 2015 の 16日目の記事です。

今日は vvvv と THETA S ネタ。

この界隈(?)ならみんなが持っているであろう 360°全天球カメラ「RICOH THETA」シリーズ。

この THETAシリーズに、この秋新たに「THETA S」が加わりました!

https://theta360.com/ja/about/theta/s.html

旧モデルから画質が改善されたり、いろいろと変更点はあるのですが、

注目したいのは、「ライブストリーミング」モードが追加されたことです!

THETA S のライブストリーミングモード

THETA S の本体下部には micro USB 端子があり、USBケーブルで PC と接続することによって、Webカメラと同じように THETA S のリアルタイムな映像を取得することができるのです!

今までは撮影専用でしたが、このモードが追加されたことで用途がぐっと広がるのでは!と期待しています。

問題点

ですが、問題点が1つ。。。

実はライブストリーミングモードで取得できる画像は以下のようになっているのです。

f:id:poipoides:20151209175002j:plain

THETA 両サイドにあるレンズからの映像が「そのまま」表示されているだけなのです。本当は↓のような 360°ぐるっと好きな位置で見れるようにしたいのに。。。


360° cockpit view | Fighter Jet | Patrouille Suisse ...

こうするためには THETA S から取得できる画像をリアルタイムで 360° 用に変換してあげる必要があるのです!

本題

と、いうことで vvvv で THETA S リアルタイム 360°ビューワーを作ってみました!

ただし、後述しますが制作上の制約がありまして、今回は vvvv x64 + DirectX 11 環境のみの対応になります。

使用方法

細かい技術的な解説は一旦後回しにして、まずは使用方法です。

まずは今回作成した ThetaSTexture をこちらからダウンロードしてください

https://github.com/poipoi/ThetaSTexture/releases

以下、使うためのステップです。

  1. vvvv x64 に Direct X11 パックを入れた環境を用意
  2. コントリビューション用フォルダを用意してパスを通す
  3. コントリビューション用フォルダに「texture11」というフォルダを作成
    • 公式では「effects」「plugins」「modules」の3つを用意しろと書いてますが、それと同じレイヤーに「texture11」を作ってください。
  4. 上述のURLより ThetaSTexture をzipでダウンロード
  5. zip を解凍しフォルダごと「texture11」フォルダ内に入れる

これで使用できます!

実例

今回作成した ThetaSTexture にはヘルプ用パッチもつけてありますので、そちらを見てみましょう!

こんな感じで THETA S からの映像を

  • THETA S から読み込んできた変換前の状態
  • パノラマ状テクスチャへ変換した状態
  • それを元に Cube Map した状態

の3つがそれぞれ見て取れると思います。

解説

ここからは、技術解説です。

ものすごい簡単にいうと、

  1. ピクセルシェーダーで THETA S からの画像をパノラマ画像に変換する。
  2. パノラマ画像をつかって Cube Map する。

ということをやっています。

2 については普通に vvvv に元からあるパッチで実現できるので説明は割愛します。なので、今回の制作のメインは 1 の部分になります。

ちなみに、今回シェーダー素人+算数苦手な私が挑戦したので、いろいろ間違えや周りくどい部分がありそうな気がしてます。もし変なとこあったらご指摘大歓迎です。

変換の手順

THETA S の画像からパノラマ画像に変換するだけというと簡単に聞こえますが、ピクセルシェーダー内だけでも結構複雑な手数を踏んで変換を行っています。

簡単に説明すると以下の様な感じです。

f:id:poipoides:20151209165114g:plain

  1. パノラマ画像の各ピクセルを全天球の緯度経度に変換
  2. 緯度経度を THETA S レンズ上のXY座標(正射影)に変換
  3. 正射影のXY座標から立体射影のXY座標に変換
  4. 立体射影の座標を THETA S 上の座標に変換。

THETA S の画像をパノラマに変換するんだから順序が逆じゃない?と思い方もいるかと思いますが、ピクセルシェーダーはアウトプット画像上の座標がインプット画像上の座標のどこに当たるかを考えて計算します。

なので、アウトプット座標(パノラマ画像上の座標)→インプット座標(THETA S 画像上の座標)方向の変換を考えていくことになります。

1. パノラマ画像の各ピクセルを全天球の緯度経度に変換

f:id:poipoides:20151209165244g:plain

パノラマ画像上の各ピクセルが、全天球上の表面のどこに当たるかを計算し、その緯度経度を算出します。

パノラマ画像は正距円筒図法であると仮定。 (くわしくはここ参照)

なので単純に以下のような対応になります。

経度:λ = x
緯度:φ = y

2. 緯度経度を THETA S レンズ上のXY座標(正射影)に変換

f:id:poipoides:20151209165305g:plain

全天球上の緯度経度の値を、THETA S のレンズで正射影したときの座標に変換します。

変換式は以下。

X座標(正射影):xt = cos(λ) * sin(φ)
Y座標(正射影):yt = sin(φ)

3. 正射影のXY座標から立体射影のXY座標に変換

f:id:poipoides:20151209165318g:plain

THETA S のレンズは立体射影らしいので(ソースはここ)、正射影の座標を立体射影の座標に変換しなければいけません。

正射影を立体射影に変換するには、

XY座標(正射影)→ 極座標(正射影)→ 方位角・仰角 → 極座標(立体射影) → XY座標(立体射影)

というように計算してあげるといいような気がします。

(参考にしたのはこちら

ちなみに極座標上の偏角と方位角は同じになりますので仰角のみを計算する形になります。

偏角 = 方位角:θ = arctan(yt / xt)
距離(正射影):r = √(xt^2 + yt^2)

仰角:φ = r

距離(立体射影):r' = tan(φt / 2)

X座標(立体射影):x' = r' * cos(θ)
Y座標(立体射影):y' = r' * sin(θ)

4. 立体射影の座標を THETA S 上の座標に変換。

f:id:poipoides:20151209165342g:plain

最後に、THETA S の画像に合うようにサイズや位置、向きなどを調整します。

ココらへんは単純な位置とスケールと角度の調整なので説明ははしょります。

締め

ということで、こんな感じでちょっと複雑になってしまいましたが、シェーダを使って THETA S 画像をパノラマ画像に変換できました!

ちなみに、vvvv x86 の方だと DirectX 9 なのでピクセルシェーダーの演算スロット数が少なく、今回の実装を実現できませんでした。

変換式自体にちょっとまわりくどい部分がありそうなので、いつかブラッシュアップして vvvv x86 の方にも対応できればいいなーと思っています。

それでは、今回はこの辺で。