RICOH THETA SのDualfisheye動画(変換前の動画)をThree.jsで表示してみた。
計算とか教えてもらいながら自分なりに考えて実装したのでおかしいところがあるかもしれないが忘れないようにメモしておく(計算難しい)。
ソースコード:https://gist.github.com/mechamogera/5635338a1075baadba0b
動作サンプル:http://bl.ocks.org/mechamogera/5635338a1075baadba0b
(2016/01/25追記 コミットミスってソースコード & 動作サンプルぶっ壊してました、修復しました)
上のコードだとmp4動画を視聴しているが、WebRTCで取得したTHETAのライブストリーミング画像でもちゃんと表示できた。
2016/01/26追記
THETA S のUSBライブストリーミングをブラウザで球面マップする - 自習室でいろいろ改善していただいてました!
コミットミスってて申し訳ないですm(_ _)m
THETA S で全天球映像を配信するまで(3) 映像を貼り付けて表示してみましたなどの記事も出てきてありがたいですね。
コード解説
概要
基本は初心者でも絶対わかる、WebGLプログラミング<three.js最初の一歩> | HTML5Experts.jpを参照してThree.jsで実装。
構成は以下のようにしている。
- three.min.js:Three.jsのメイン処理を行う取得してきたファイル
- OrbitControls.js:Three.jsでマウスをグリグリするための取得してきたファイル
- index.html:Dualfisheye動画を見るために作成したHTML
- theta-view.js:Dualfisheye動画を見るために作成したJS
- m20.mp4:表示するためのDualfisheyeサンプル動画
球を作成してカメラを内部に配置してvideoタグをソースにした動画テクスチャをごにょごにょして貼り付けて表示している。
テクスチャを貼る
theta-view.jsで以下の部分がUVを設定している部分。
if (i < faceVertexUvs.length / 2) {
var correction = (x == 0 && z == 0) ? 1 : (Math.acos(y) / Math.sqrt(x * x + z * z)) * (2 / Math.PI);
uvs[ j ].x = x * (404 / 1920) * correction + (447 / 1920);
uvs[ j ].y = z * (404 / 1080) * correction + (582 / 1080);
} else {
var correction = ( x == 0 && z == 0) ? 1 : (Math.acos(-y) / Math.sqrt(x * x + z * z)) * (2 / Math.PI);
uvs[ j ].x = -1 * x * (404 / 1920) * correction + (1460 / 1920);
uvs[ j ].y = z * (404 / 1080) * correction + (582 / 1080);
}
404や447のマジックナンバーは以下のサイズに対応する。
ただし、正確に測ったりしていないのでざっくりとした値。
ベースとなるコードは以下の質問の回答にあるこちらのコードを参考にしている。
javascript - Mapping image onto a sphere in Three.js - Stack Overflow
faceVertexUvs[ face ][ j ].x = face.vertexNormals[ j ].x * 0.5 + 0.5;
faceVertexUvs[ face ][ j ].y = face.vertexNormals[ j ].y * 0.5 + 0.5;
ただし、上のコードのままだと画像が歪む。
そのため以下のように計算して補正している。