Tutti Lab

元シリコンバレー在住のおっさん技術者、モバイルVRアプリ開発に挑戦中

プリレンダリングの360度立体視CGとカメラ入力映像を重畳し、エンコードする

前回は、Maker Faire Tokyoに出展したVR撮影システムについて、360度立体視CGのプリレンダリングのやり方について書きました。
今回は、その360度立体視CGと、カメラ(魚眼レンズを付けたiPhone2台)入力画像を重畳し、mp4動画ファイルとしてエンコードする方法について書きたいと思います。

【第1回】VR撮影システムのハードウェア構成
【第2回】360度立体視CG映像を作る
【第3回】カメラ入力映像と重畳しエンコードする(今回)

左右眼用のカメラ入力映像をFisheye形式からEquirectangular形式に変換

基本的なやり方は、Theta二台から立体視用Equirectangular映像をつくるにて書いた内容と同じです。しかし、Theta Shader Packをそのまま利用することはできません。iPhoneからのカメラ入力映像は確かにFisheye形式なのですが、Thetaからの入力映像と異なり、左右が欠けてしまっています。
以下の図はMaker Faire Bay Area時のカメラ入力映像の取り込み・変換の仕組みです。左右眼用のThetaからの入力映像のうち、前方のFisheye映像をTheta Shader Packを利用してEquirectanguler形式に変換する、という方法をとっていました。
f:id:tuti107:20160810144242p:plain
今回のMaker Faire Tokyoでのカメラ入力映像の取り込み・変換の仕組みは以下のとおりです。
f:id:tuti107:20160810174152p:plain
iPhoneには魚眼レンズが取り付けられているため、カメラ入力映像はFisheyeのように歪んだ状態となっています。ただiPhone縦持ちで撮影する際、縦方向と比較して横方向の画角は狭くなってしまいます。iPhoneSE + Gizcamの場合、図の緑の破線(画角180度を示す)がカメラ入力映像からはみ出してしまいます。つまり、iPhoneからのカメラ入力映像の中にはThetaのように完全なFisheye形式の画像は含まれません。iPhoneからの入力画像を、上記Theta Shader Packの要領でEquirectanguler形式に変換すると図のように、ひょうたん(?)のような形になります。このため、大半はTheta Shader Packの処理のままで良いのですが、

  • はみ出ている部分は透明にする
  • Fisheye部の径を適切な値とする

2点の修正が必要となります。

フルHDサイズのオフスクリーンテクスチャを60fpsでエンコードする

前回のMaker Faire Bay Areaでは、ffmpegでリアルタイムエンコードするスクリプトを生成し、それを使用しました。しかし、その方法では12-15fpsが限界であり、せっかく搭載されている GeForce970の力を生かしたハイパフォーマンスなエンコードをできるようにしたいと思っていました。
そこで見つけたのが、GPU Video Encoderです。$100とかなり高価なアセットですが、複数のFull HDサイズのRenderテクスチャを同時に60fpsでエンコードできるスグレモノです。
本アセットの利用手順は次の通りです。
※本アセットは、Windows x86_64 DX11環境かつ、NVIDIAのHWエンコーダ(nvenc)が利用できる環境でのみ動作します。それ以外の環境では使用できませんのでご注意を(高価ですし)

  • Spicy Pixel Concurrency Kitをダウンロード・インポートする(本アセットと依存関係にあります)
  • 1920x1080のRender Textureを左右眼用作成する(それぞれの名前を"LeftTex", "RightTex"とする。Render Textureは、Projectにて右クリック→Create→Render Textureで作成、インスペクタのSizeにて1920x1080を設定できる)
  • それぞれのRender Textureに描画するCameraについて、Clear FlagsをSolid Color、Backgroundを緑(R=0, G=255, B=0)とする。のちほどffmpegでクロマキー処理をする際に「抜く色」として緑を使用するため
  • GameObjectを二つ生成する(ぞれぞれの名前を"Left", "Right"とする)。それぞれにMovie Record Cameraスクリプトを追加し、それぞれインスペクタより、Textureにはぞれぞれ上記で作成したRender Texture(LeftTex, RightTex)、Output File Path/Output File Titleにはそれぞれ生成するファイルのパスと名称を設定する

f:id:tuti107:20160810182039p:plain
あとは、エンコードを開始したいタイミングで、MovieRecordCamera#StartMovieRecord()を、終了したいタイミングでMovieRecordCamera#EndMovieRecord()を呼ぶだけです。スクリプトとしては以下のような感じで、上記生成したGameObject left, rightのMovieRecordCameraコンポーネントをインスペクタで下記leftCam, rightCamに設定しておき、開始・終了のタイミング(以下の例ではRキー押下)でそれぞれのメソッドを呼び出します。

using UnityEngine;
using System.Collections;
using GPUVideoEncoder;

public class CameraController : MonoBehaviour {

	public MovieRecordCamera leftCam;
	public MovieRecordCamera rightCam;

	private bool isRecording;

	// Use this for initialization
	void Start () {
		isRecording = false;
	}
	
	// Update is called once per frame
	void Update () {
	
		if (Input.GetKeyUp (KeyCode.R)) {
			isRecording = !isRecording;
			if (isRecording) {
				leftCam.StartMovieRecord ();
				rightCam.StartMovieRecord ();
			} else {
				leftCam.EndMovieRecord ();
				rightCam.EndMovieRecord ();
			}
		}
	}
}

すると、左右それぞれ用の.h264ファイルが、それぞれ指定したパス・ファイル名にて生成されます。このファイルをffmpegにてmp4に変換すれば、完成です。

ffmpeg.exe -i movieLeft.h264 -vcodec copy movieLeft.mp4

左目用・右目用の撮影映像を縦に並べる

次に上記生成した、左目用・右目用のmp4ファイルを縦に並べたmp4ファイルを生成します。以下のコマンド一発で変換可能です。

ffmpeg.exe -i movieLeft.mp4 -i movieRight.mp4 -vcodec nvenc -filter_complex vstack -b:v 8M movie.mp4

プリレンダリングの360度立体視CGとカメラ入力映像を重畳し、エンコードする

最後に、上記縦に並べた左右眼用の撮影映像と、前回生成したプリレンダリングの360度立体視CGを重畳します。これもffmpegのコマンド一発でオッケーです。

ffmpeg.exe -i movie.mp4 -f lavfi -t 10 -i \"movie = filename = a.mp4:loop = 0, setpts = N / (FRAME_RATE * TB)\" -filter_complex [0:0]colorkey=0x00ff00:0.5:.2[a1];[1:0][a1]overlay out.mp4
  • "t"オプションには作成する映像の時間(秒)を設定します
  • "movie=..."部分は重畳する360度立体視CG映像についての設定です。"loop = 0, setpts = N / (FRAME_RATE * TB)"とすることで、360度立体視CG映像の再生時間が-tで指定した時間より短い場合、これをループ再生します
  • "filter_complex"オプションには、クロマキーと映像重畳を設定します。colorkeyに緑色(0x00ff00)を指定することで緑色が透過します。なお":"で句切られた他の2つの数値は、クロマキーする範囲について指定しています。この2つの数字は試行錯誤で設定したものであり、数値とクロマキーの度合いの関係はいまいちわかっておりません。

これで、プリレンダリングの360度立体視CGとカメラ入力映像を重畳した動画ファイルが完成です!

終わりに

3回に渡り、Maker Faire Tokyoに出展した「スマホ2台を利用したVR映像作成システム」について書きました。記載量が莫大になってしまうため、実装詳細については触れませんでしたが、ご興味おありの方はその旨いろいろご質問いただけると嬉しいです。