• 32
    いいね
  • 0
    コメント

はじめに

北千住デザインという名前で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);

VertexShader
varying vec2 vUv;
void main()
{
  vUv = uv;
  vec4 hoge = vec4(position, 1.0);//マトリックス計算しない
  hoge.z = 1.0;//最背面のz=1に。
  gl_Position = hoge;
}   
FragmentShader
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

おわりに

Threejsはめんどいこともやってくれて素晴らしい。WebGLは手軽だし、VJみたいなことも十分できる。今回のように他のツールと組み合わせて、なんかやるのもいいのかもしれない。

この投稿は Three.js Advent Calendar 201625日目の記事です。