Frame Blending with Motion Vectors ( GDC2017 VFX BootCamp ) via @simonschreibt

  • 8x8 コマのフリップブックで, 30 秒のスローモーション動画.
  • 1 秒あたり 2.13 コマ. ( 8 * 8 / 30.0 = 2.13 )

Related Links

要旨

  • まずは 下の動画を再生して下さい.
  • 左側は通常のフリップブック, 右側は今回のモーションベクトルも使ったフリップブックです.
  • 左側だとスローモーションの際に特にかくついてしまいますが, 右側は滑らかにアニメーションしているように見えます.


  • 今回の手法では ベースのテクスチャのフリップブックだけでなく, そのモーションベクトルのフリップブックも出力しておきます.
  • そして, モーションベクトルのフリップブックを使ってベーステクスチャを参照するときの UV を歪ませることで, 実際のベーステクスチャには存在しないフレーム間の絵を擬似的に再現します.
  • 例えば, フレーム0 とフレーム 1 の間にある フレーム 0.25 の画像を作りたいとします.
  • フレーム0 について
    • まず, フレーム0 の UV については 「フレーム0のモーションベクトルの画像」を参照した際の 「UV の速度」で 0.25 フレーム分, 歪ませます.
    • そして, その UV で フレーム0 のベーステクスチャを参照します.
  • フレーム 1 について
    • フレーム1 の UV については「フレーム 1 のモーションベクトルの画像」を参照した際の「UV の速度」 で ( 1 - 0.25 ) = 0.75 フレーム分に逆方向に歪ませます.
    • そして, その UV1 でフレーム 1 のベーステクスチャを参照します.
  • 合成
    • そして, これらの両者を 0.25 でリニアブレンドしてフレーム間の画像を作ります.
  • 今回の方法だと 後述するように, FumeFX を使ってシミュレーション結果を元にモーションベクトルを出力しています.
  • 一方で, ベーステクスチャだけから上の Slate Editor を使ってオプティカルフローを求めて 擬似的に 2D のモーションベクトルを作って使うこともできると思います.


  • Adobe Premirere Pro でもフレーム補間にオプティカルフローを使うことができていました.

背景

最初は Guerilla Games の Killzone 2 のカットシーンで使用された技術
  • まず, 最初に Guerilla Games が Killzone 2 のカットシーンでモーションベクトルでフレームブレンディングする技術を使い, その後 Killzone Shadow Fall で使われています.
  • これについての情報は上の資料の p81-86 に載っています. 下図に図を貼っておきます.

  • ただし, この場合だと「モーションベクトルの画像は 2 枚」使っていました.
今回の記事 "Frame Blending with Motion Vectors" by Klemen Lozar について
  • 今回の記事は上の Killzone 2 のものを改良して, 「モーションベクトルの画像を 1 枚」で済ませるようにしています.
  • あと, この記事の作者の Klemen Lozar さんは Guerilla Games に勤めていたわけではないです.

どういうテクスチャデータが必要なのか ?

  • 必要なものは下の 2 枚のテクスチャです.
    • 1 つ目は左側のベーステクスチャ (RGB: カラー, A: アルファ)のフリップブックです.
    • 2 つ目は右側の 2D のモーションベクトル (RG 成分のみ)のフリップブックです.

  • あと, 2D のモーションベクトルについては非圧縮テクスチャを使用します.

どうやってテクスチャデータを作っているか ?

(0) FumeFX for 3dsMax
  • ベーステクスチャとアルファを出します.


  • シミュレート時に速度チャンネルも出します.
    • その後, Blue 成分は 0 にします. この段階で, RG 成分がカメラ座標系でのモーションベクトルになっています.
  • ベーステクスチャのアルファで抜いて, 少しぼかすと右図のようになります.


(1) After Effects と Revision FX というプラグイン( Twixtor の Pro 版に付属 )
  • モーションベクトルの画像を 1 枚で済ませるために, このツールでベーステクスチャを元にスクリーンスペースのモーションベクトルの画像も作ります.
  • これをするのはアルファの範囲外のモーションベクトルを作って合成するためです.
  • 下図の左側は今回作ったスクリーンスペースのモーションベクトルです. ( アルファの範囲外用 )
  • 右側がこれを (0)で作ったものと合成した結果です. FumeFX の方でアルファでステンシル抜きして少しぼかしておけば下のようにうまく合成されるとのことです.


(3) UE4 のシェーダでの再生


// フレーム 0 の UV
float2 current_uv;

// フレーム 1 の UV
float2 next_uv;

// フレーム 0 と フレーム 1 のブレンド割合 (0.0-1.0)
float frac;


// フレーム 0 の UV を順方向に歪ませる
float2 current_motion_uv = tex2D( _MotionVecTexture, current_uv ).rg;
float2 forward_delta_uv  = frac * current_motion_uv * distortion_strength;
float2 forward_uv        = current_uv - forward_delta_uv;

// フレーム0 のベーステクスチャを参照
float4 forward_color     = tex2D( _BaseTexture, forward_uv );


// フレーム 1 の UV を逆方向に歪ませる
float2 next_motion_uv    = tex2D( _MotionVecTexture, next_uv ).rg;
float2 backward_delta_uv = ( 1 - frac ) * next_motion_uv * distortion_strength;
float2 backward_uv       = next_uv + backward_delta_uv;

// フレーム 1 のベーステクスチャを参照
float4 backward_color    = tex2D( _BaseTexture, backward_uv );


// フレーム間の画像を求める
float3 final_emission    = lerp( forward_color.rgb, backward_color.rgb, frac );
float  final_opacity     = lerp( forward_color.a  , backward_color.a  , frac );