見出し画像

AfterEffectsのプロジェクトをJSONで書き出してopenFrameworksで三次元的な位置関係を維持したまま合成/書き出しした話

こんにちは、AQUARING かに です。

とある案件でfacebookの記念動画のようなコンテンツを制作する機会があったのでその解説記事になります。

facebookの記念動画とは、テンプレートとなる動画の中にユーザーが撮影した写真やいいね数のテキストが動的に合成されたものです。

まず、今回の案件では以下の3つの要件(制約)がありました。
・テンプレート動画内に配置されている画像とテキストを動的に合成したい
・単発イベントではなく、合成するPCごと常設納品する
・テンプレートとなる動画は外部の映像制作会社に依頼するため.aepをそのまま貰うのは避けたい

AfterEffectsで動的動画生成する方法を調べたところ、以下の2つの方法でできそうなことがわかりました。

1. AfterEffectsで自動レンダリング
2. AfterEffectsのコンポジションの情報をスクリプトで書き出してopenFrameworksでプリレンダ連番と合成

1. AfterEffectsで自動レンダリング

After Effects での自動レンダリングとネットワークレンダリング
AfterEffectsにはaerendererという実行ファイルが同梱されていて、それをコマンドラインから呼び出すことでレンダリングの自動化ができます。

AfterEffectsをサーバーサイドで使って動的に動画を生成する
aerendererを使って自動レンダリングしているBasculeさんの先行事例です。
この方法でできればAfterEffectsからそのまま書き出しができるのでよさそうなのですが、今回の要件的に.aepをそのまま貰えないのと、今回は単発イベントではなくPCごと常設納品で、AfterEffectsの月額課金が必要になるため見送りました。

2. AfterEffectsのコンポジションの情報をスクリプトで書き出して、プリレンダの連番画像と合成

nariakiiwatani/ofxAE: openFrameworks addon for porting Adobe AfterEffects composition to openFrameworks.
anno lab 岩谷さん(@nariakiiwatani)の、AfterEffectsのコンポジションをopenFrameworksでリアルタイム再現することを目的として作られたaddonです。

ofxAE/tool/compExport.jsxで.aepのレイヤー情報をjsonに書き出し、それをopenFrameworksで読み込んで再現しています。

↓ AfterEffectsのプロジェクト。

スクリーンショット 2020-07-31 19.21.11

↓ 書き出したjsonをopenFrameworksで読み込んでofxAEで再現したもの。

スクリーンショット 2020-07-31 19.22.51

リアルタイム再現なのでやりたいことにだいぶ近かったのですが、exampleが一部動かなかったり、未実装の部分(テキストレイヤーなど)もあり自前で機能追加するにはアドオンの設計を一通り把握する必要があったためそのまま使うのはやめました。(自前実装のほうがカスタマイズできるというのもあります)

ofxAEを自作する

jsxでJSONに書き出す仕組みは流用できそうだったので、compExport.jsxを参考にしてAfterEffects Script Referenceとにらめっこしながらほぼ全てのレイヤー情報をひとつのjsonファイルに書き出すスクリプトを書きました。

AfterEffects Composition JSON Exporter · GitHub

書き出したJSONファイルは以下の画像のように、キーフレームの打ってあるプロパティが1フレームごとの値の配列になります。

スクリーンショット 2020-08-17 14.58.55

JSONへの書き出しができたので、ここからはopenFrameworksでAfterEffectsと同等の機能を実装しました。

レイヤーのトランスフォームや親子関係はofNode、テキストレイヤーはofxTrueTypeFontUL2、レイヤーマスクはofxAlphaMaskを使って実装しました。

openFrameworksでコンポジションを再現する際にハマった箇所があったので、備忘のため以下に残しておきます。

AfterEffectsとopenFrameworks(OpenGL)の3D座標系の違い

After Effects での 3D レイヤーの使用

After Effects では、座標系の原点は左上隅です。X(幅)は左から右に、Y(高さ)は上から下に、Z(奥行き)は手前から奥にそれぞれ値が大きくなります。一部のビデオアプリケーションや 3D アプリケーションは、X 軸を中心に 180 度回転する座標系を使用しています。このような座標系では、Y 軸は下から上に、Z 軸は奥から手前に値が大きくなります。

↓ AfterEffects

原点 : 左上
X : 左 → 右
Y : 上 → 下 *
Z : 前 → 奥 *

↓ OpenGL

原点 : 中央
X : 左 → 右
Y : 下 → 上 *
Z : 奥 → 前 *​

YZ軸が反転しているため、openFrameworksで読み込む際に

ofVec3f pos( x, -y, -z );

として、YZ軸を反転させて代入すると同じ座標になります。
原点の位置も違うため、openFrameworks上で原点が左上にくるようにカメラ位置をオフセットする必要があります。

AfterEffectsのデフォルトカメラ画角

CameraLayer object にはfov(視野角)が取れるプロパティが存在しないので、zoomプロパティから算出する必要があります。

カメラレイヤーが置いてあるときはCameraLayerのzoomとコンポジションの高さからfovを算出できますが、カメラレイヤーが存在しない場合は自動的にAfterEffects側のデフォルトカメラが適用されるため、その画角の値も把握しておく必要がありました。

ググってもなかなか出てこなかった(*1)のですが、たまたま3DレイヤーをエクスプレッションのtoComp()でコンポジション座標に変換したら

[ x, y, 2665.66666 ]

となっていたので、2665.6666がカメラ距離だとわかりました。(FHDの場合)

距離がわかればコンポジションの高さは自明なので、三角関数を使って垂直画角を算出したら22.903555°だとわかりました。

カメラレイヤーがないフレームでは

ofCamera defaultCamera;
defaultCamera.setFov(22.903555);

として、デフォルト表示用のカメラの画角を設定してAfterEffectsと同じ見た目になるようにします。

*1)後々調べたらこちらの記事に同様の情報がまとまっていました。(この記事では水平画角を求めています)
After Effects の 3D レイヤーと OpenGL - Qiita

できたもの(デモ)

パターンの画像がAfterEffectsでレンダリングした連番jpg画像で、その上にopenFrameworksで空間ごと再現したコンポジションを重ねて描画しています。(openFrameworks側でパターン画像をケーキの画像に差し替えています)

このデモではイメージレイヤーとテキストレイヤーを全てopenFrameworks上で再現していますが、実際の案件では動画内の静的な要素だけをプリレンダリングした連番jpgと、openFrameworksでの合成部分とを組み合わせて動的に書き出しました。

openFrameworksでのコンポジションの再現ができれば合成したフレームのキャプチャができるので、連番で書き出して動画生成も可能です。

まずofxSequenceExportで連番jpgをdataフォルダに書き出し、openFrameworks内からofxThreadedCommandで別スレッドからFFmpegコマンドを呼び出して合成後の連番jpgからmp4を生成しました。

さいごに

このデモを作っていた段階ではどんな映像が上がってくるかもわからない状態で実装していたため当時はうまくいくか心配でなりませんでしたが、なんとか納品できたのでいまは安堵しています。。

この記事が気に入ったらサポートをしてみませんか?