ブログ移行しました -> MochiMochi 3D
初めに
2025/04/02にTHE LUV BUGSから発表された楽曲『WING IT!!!』のMVの制作に僭越ながら関わらせて頂きました。本記事では、私が担当したモデルやシミュレーションについて解説します。また、MV制作に携わるのは今回が初めてだったため、制作の進め方についても備忘録としてまとめます。
もう一人のMV制作者であるRenardさんの記事はこちら renard.hateblo.jp
目次
制作について
MVの制作はRenardさんと二人で制作しました。私はモデリング(遊園地とキャラクター以外)と物理シミュ、爆発シーンの映像を担当しました。レンダリング、コンポジット、その他のすべてはRenardさんが担当しています。
使用ツール
今回の制作で主に使ったツールは以下の通りです
- FigJam : アイディアボードとして打ち合わせに使用
- Houdini : 物理シミュや文字モデルの制作などに使用、またレンダラーとしても使っていた。
- Blender : キャラクターの微調整や一部建物の制作に使用
シーン
MVは大まかに分けて「遊園地」と「宇宙」、「コンクリート」の3つで構成されています。
遊園地
- 遊園地モデルはアセット
- キャラクターはO.G.I.さんが他のMVで制作したものを使わせて頂いた
- 文字モデルはHoudiniで制作(詳細は後述)、配置はRenardさんが担当

遊園地から宇宙シーンへのトランジション


宇宙シーン
- 月は遊園地アセットから一部抜き取って制作
- まじめな物理シミュではなく割と適当な感じのアニメーション

コンクリートシーン
- 建物のモデルは半分手作業、半分プロシージャル
- Le Vele di Scampiaという建物をモデルにした
- この辺は「やりたい放題やる」というテーマだったので好き勝手やってる

流れ
MV制作はお互い初めだったのですが、RenardさんはMV的な作品の制作経験があったので、Renardさんが舵を取って段取りを決めていきました。
最初にやったことは解釈のすりあわせでした。お互い曲と歌詞を確認し、どのような印象を持ったかについて話し合うことで方向性を決定しました。「WING IT!!!」の印象として私たちは「創作の面白さと苦痛が入り混じる」「皮肉的な要素が強い」「最後はやりたい放題やってる」ということを感じました。
そんな感じで話し合った結果、「安易な表現をする」→「破壊する」→「やりたい放題する」というストーリーラインを考えました。これを基準に演出を決めていきました。
次は曲からカットシーンの時間とタイミングを決めました。DJソフト使いながら、演出の区切りとなる部分を見つけていきました。そこから各カットシーンの演出を考えるというノリでやって行きました。
技術的詳細
文字アニメーション
MVではリリックモーションとして風船のような文字のアニメーションがあります。これは3Dモデルとして制作しており、実際にオブジェクトとしてシーンに配置されています。
特に文字アニメーションは自動化を重視して、Houdiniを使って歌詞データから各文字のFBXを出力するシステムを組んでいます。
歌詞データは元々はMusic XMLとして受け取っており、Renardさんが使いやすいようにjson形式にパースしてくれました。データはlyric(文字)、start(文字の開始時間)、during(出る時間)の3つの要素で構成されています。

これは発音のデータであったので、歌詞の文字に変換を行いました。ただ、MusicXMLは割と何でも入れられる形式のため、歌詞との対応関係の自動化は不可能でした。
- 漢字のように複数の発音を持っている
- 英語は一つの発音で複数の文字を持っている
- ブレスのような歌詞にない発音
- そもそも謎な空白文字
なので、手動でマッピングデータを作って変換をしました(かなり泥臭い作業をしていました)。


Houdini側はTOP netのpython processorを通して歌詞データを取り込んでいます。読み込んだ歌詞データから文字ごとwork itemを生成し、それぞれをタスクとしてFBXを出力するようなシステムにしています。pythonかけるので割と何でもできる気がします。

文字モデルは「フォントのメッシュ化」「風船シミュレーション」「データの埋め込み」の3つの手順で生成しています。
フォントのメッシュ化には、suzuki_ith 氏によるSUZUKITを使用しました。
SUZUKITは閉曲線に対して切り抜きや角の丸めなどの処理を行えるノードを追加するHoudiniアドオンです。こちらの良いところはFontを閉曲線として扱うので、Roundなどのベクターデータ的な操作を行えることです。簡単なところではフォントの太さを変更したり、輪郭を簡単に作れたりします(Houdini標準のFontではかなり厳しい)。

ラフの段階から文字モデルに何らかの加工を施すことは決まっていたため、今回SUZUKITを採用しました。風船シミュの初期形状の調整にすごい助かりました(繋げたいとかそういうのに)。
風船シミュについてはVellumを使いました。特殊なことはなく以下のTutorialを参考にしつつやりました。パラメーターの調整は頑張って微調整しています(PBDを使っているので仕方がないが、とても分かりづらくてつらい)。

今回の文字モデルは2つの要望がありました
- 膨らむアニメーションがしたい
- StartとDurationの情報をシェーダー側で受け取りたい
膨らむアニメーションについてはVATが高コスト過ぎるため、シンプルに前後のoffsetだけ持ってUnityのshader側でイージングする形にしました。FBXは幸いにもtangentやuvに自由に書き込むことができるため、必要な情報をそこに埋め込んでshader側で読んで使うという手段を取っています。
以下のようにwrangleで指定の名前のattributeを設定するとFBXの出力時に値を書き込んでくれます。
- tangent : 膨らんだ後の法線
- uv1 : 膨らんだ後の頂点のoffset(xy)
- uv2 : 膨らんだ後の頂点のoffset(z), start
- uv3 : duration
vector p1 = @P;
vector p2 = point(1,"P",@ptnum);
float start = chf("start");
float duration = chf("duration");
vector offset = p2 - p1;
@uv1 = offset;
@uv2 = set(offset.z,start,start);
@uv3 = set(duration,duration,duration);
vector n = vertex(1,"N",@vtxnum);
v@tangentu = n;

物理シミュレーション
RDBでやるちゃんとした物理シミュとなんちゃって物理シミュがあります。前者は遊園地の爆発シーンと破片が集まるシーン、後者は月の爆破シーンでやっています。
爆破シーンはポップな爆発(だけど爆発自体はリアル, クソコラみたいなの)を目指して作っており、各々の爆心地に単一のPOP attractを単に置いているだけです。処理負荷的な問題が大きく、イテレーションを早く回せるようにPoly Reduceで20%ほどに落としたり、box形状でシミュレーションしました。

破片が集合するシーンはガイドとなるパスを用意し、POP Curve Forceでそれに沿うように力場を用意してあげています。ただ、速すぎてガイドから外れてしまうことが多かったため、Geometry Wrangleでパスの最近傍へと向かう強めのforceをかけて拘束するようにしています。
forceによる拘束は記述が楽なのですが、不自然な挙動をしがちなので何とかしたい(うまい方法あるんでしょうか・・・)

なんちゃって物理シミュは衝突とか考えずに簡易的な解析解でポジションを移動させているものです。各インスタンスに各々固有の重心[tex : c_i]、質量を与えて、一様な初期速度
で計算した結果の処理を書いています。回転では慣性モーメントに
をそのまま使ったらいい感じだったので、それを元に角運動方程式の簡単な式をやっています(行列にしてインスタンスのmatrixに設定しています)
割と適当な実装ではあったのですが、意外とそれっぽくなり調節がしやすかったので月の爆破シーンに使用しました。
float time = chf("time");
vector exPoint = chv("explosion_point");
float exPower = chf("explosion_power");
float exTorque = chf("explosion_torque");
float exAttenuation = chf("explosion_distance_attenuation");
vector center = @P;
float massEffect = chf("mass_effect");
float massScale = chf("mass_scale");
// Rigid Body Paseudo Dynamics
float mass = @mass;
float aveMass = detail(0,"sumMass",0) / detail(0,"numObject",0);
mass = lerp(mass, aveMass, massEffect) * massScale;
vector exVelocity = normalize(center - exPoint) / mass;
exVelocity *= exPower;
vector gravity = chv("gravity_direction") * mass;
vector constForce = chv("const_force");
vector force = gravity + constForce;
@P = force * time * time / mass + exVelocity * time + center;
// Rotation
vector lv = normalize(center - exPoint);
vector lm;
if(abs(lv.y) < 0.99) lm = normalize(cross(lv,set(0,1,0)));
else lm = normalize(cross(lv,set(0,0,-1)));
int id = @id;
float deltaV = 2.0 * rand(id) - 1.0;
vector axis = lm;
matrix3 m = ident();
float angle = deltaV * exTorque / mass;
rotate(m, angle * time, axis);
setprimintrinsic(0, ‘transform’, @ptnum, m, ‘set’);

爆破シーンのレンダリング設定
爆発のvolumeはHoudini標準のpyro solver fire_ballを使用しました。その結果をPyro Bake Volumeで値を決めマテリアルのプリセットを生成してもらいました(Volumeのマテリアル設定はバージョンによってまちまちで20.5だとPyro Shaderというノードで設定するのが正しいっぽい?)

レンダリングではcolorとdepthを出力しており、COPでcolorのluminanceに対してdepthのウェイトをかけた値に対してInfelnoカラーマップを適用して、サーモグラフィーっぽい表現にしています。

感想
- MV制作は初めてで大変だったがなんだかんだ楽しかった
- インプットが大事だと感じた(演出の提案が大変だった、Renardさんには多いに助けられた)
- 共同作業の経験の良い経験だった
- とにかくイテレーション回すことを重要視した方がよい、後々に修正が入ることを前提にシステムを組むべきだと感じた
