バスキュール技術ブログ

バスキュールが得意とするインタラクティブエンジニアリングを、あますことなくお届け!

マッチムーVJ

f:id:bascule-dev:20170426195330p:plain こんにちわ。エンジニアのビジュアル担当、渡邊(@_nabe)です。

今回はバスキュールとは全く関係ないんですが、趣味で北千住デザインという名義でthreejsを使ってブラウザVJをやっていまして、今回はそのVJネタのひとつを説明します。

やったこと

ARみたく、実写と動的なCGを組み合わせてVJをしたいと考えた(こういう合成をマッチムーブというらしい)。 ただARは現状では精度が低かったり、リアルタイムが前提の表現なので、映像作品とみたときイマイチな場合がある。そこで、実写映像をあらかじめ撮影して別のソフトで3Dトラッキングし、それにWebGLで描画された音に反応するアニメーションをオーバーレイさせるという方法をとってみた。静的な映像と動的な映像のハイブリットといった感じ。

altaltver6.gif

こんな感じで、背景はふつうのリニアな映像、手前の動いている物体は、音に合わせてリアルタイムに変形している。

どなたかが録画してくれていた動画↓

ラッキングのやり方

実写のトラッキングにはCinema4d Studioを使った(会社にあったから)。やり方はこの辺を見ればわかる 。トラッキングができたら、Cinema4DはPythonを使える機能があるので、それを使い、毎フレーム、カメラの座標・回転(クォータニオン)・FOVをjsonに書き出す。ただcinema4dとthreejsは座標系が違う(左手・右手)ので書き出す際注意が必要。

Cinema4dのPythonのコードはこんな感じ https://gist.github.com/kitasenjudesign/d739c6123e0b55bc77445d2db6f608d1

書き出したJSONはこんな感じ

    "frames": [
        {
            "fov": 32.70611613573759, 
            "frame": 0, 
            "q": [
                0.01175325347189373, 
                0.9667209890999054, 
                0.04514531549377907, 
                -0.25154381478281923
            ], 
            "x": -141.4472256273544, 
            "y": 68.24724022421263, 
            "z": -198.63611330979802
        },...

これをthreejsに持っていき、映像の再生時間と合わせて、毎フレーム、PerspectiveCameraのパラメータを更新すれば良い。

※AfterEffectsでも同様のことができるようです。他の3Dソフトでもできると思う。 https://medium.com/@Jam3/mtchmv-a54624f6232#.jwdrxnan1

Video再生

WebGLのキャンバスの背景を透明にして下にVideoタグを敷くという方法もあるが、今回はポストプロセスもかけたかったのでVideoをCanvasにキャプチャしてthreejsの中の板ポリに貼り付けた。(やり方はググれば出てくる) その際、板ポリはカメラに関係なくずっと正面を向いていてほしい。毎フレーム、板ポリをLookAtするという手段もあるが、めんどいので、以下のようにシェーダーを書いた。

geo = new THREE.PlaneBufferGeometry(2, 2, 1, 1);
mat = new THREE.ShaderMaterial({
            vertexShader: _vertexShader,
            fragmentShader: _fragmentShader,
            uniforms: {
                texture: { type: 't', value: _texture } 
            }
});
mesh = new THREE.Mesh(geo,mat);
varying vec2 vUv;
void main()
{
  vUv = uv;
  vec4 hoge = vec4(position, 1.0);//マトリックス計算しない
  hoge.z = 1.0;//最背面のz=1に。
  gl_Position = hoge;
}   
uniform sampler2D texture;
varying vec2 vUv;                                             
void main()
{
  //テクスチャを書き出してるだけ
  gl_FragColor = texture2D(texture, vUv);
}   

影もつけたい。ShadowMaterialっていうのを使うと透明なPlaneに影だけ落としてくれる。 http://stackoverflow.com/questions/35710130/shadow-catcher-in-three-js-shadow-on-transparent-material

クリッピング

地面から飛び出してくるような演出もしたい。3Dオブジェクトをクリッピングせねばならない。シェーダーを自分で書いても良い(たとえばy<0ならdiscardするとか)。けれど、めんどうなので、これもthreejsのクリッピング機能を使う。 https://threejs.org/examples/?q=clipp#webgl_clipping

おわりに

世にある大概のマッチムーブは実写とCGの合成が違和感ないように、なじむ方向に作るのだけれど、今回のように実写としょぼいCGを組み合わせてみたら、それはそれで違和感が生まれて面白い。3Dトラッキングの精度はそれなりに必要だと思うけど。

今後もよいネタあれば、発信していきます。

あと今エンジニアを募集してますーー。 www.bascule.co.jp