CGアニメーションをWebで扱うには、どのような工程が必要になるのか。本稿では、まめたろう氏の協力の下、氏の代名詞である「ぽよんぽよん」アニメーションに対して、ドラッグやタップでインタラクションできるWebコンテンツmountが制作。その実装のながれ、制作の中で見えてきたポイントを紹介する。

記事の目次

    ※本記事は月刊「CGWORLD + digital video」vol. 334(2026年6月号)からの転載となります。

    関連記事

    ・全てに意図を通す、mountのものづくり。mountの「本質を捉える」仕事術
    ・【mount inc.✕日本デザインセンター】紙の重なりが生む変化と質感をWebで見せる。大丸松坂屋百貨店「百様図」特設サイト

    ぽよんぽよん、触れます。| まめたろう × mount inc.

    Webで公開中!
    ぜひ実際に触ってみてください。
    cgw334.mount.jp

    まめたろう 氏

    RED Inc.
    X:@mametarouboy

    岡部健二 氏

    mount inc. テクニカルディレクター
    X:@kenjiokabe

    寺田奈々 氏

    mount inc. デベロッパー
    X:@luckytempleboy

    須多 望 氏

    mount inc. デベロッパー
    X:@soundmuta

    Step 01:制作方針

    こうした柔らかい変形アニメーションをWebにもち込もうとすると、まず壁になるのがデータ量と処理の重さです。Alembic(.abc)は頂点単位でアニメーションを保持できる便利なフォーマットですが、

    ・データサイズが大きい
    ・再生にCPU負荷がかかる
    ・ ブラウザでのストリーミングに向かない

    といった事情から、そのままWebにもち込むのは現実的ではありません。そこで今回は、VAT(Vertex Animation Texture)を使うことにしました。

    VATとは

    VATは、頂点アニメーションをテクスチャに焼き込み、GPUで再生する技術です。イメージはパラパラ漫画に近く、1フレームごとに「どの頂点がどこにあるか」を画像として保存し、再生時にはGPUがそれをめくっていく、というものです。重い計算はあらかじめ済んでいるため、ブラウザ上でも軽く動かせます。スキニングやモーフターゲットと比べると、

    ・CPU負荷がほぼゼロ
    ・大量インスタンスに強い
    ・流体やソフトボディなど、自由な変形にも対応できる

    といった強みがあります。Unreal EngineUnityでも使われている手法のため、ゲーム系の方には馴染みがあるかもしれません。

    Three.jsについて

    本実装はThree.jsで構築しています。Three.jsはWebGLの複雑な処理を上手く隠してくれるライブラリで、生のWebGLを直接記述するよりも、はるかに少ないコードで3Dを描画することができます。セットアップの基本はシンプルで、Scene・Camera・Rendererを用意し、メッシュを1つ表示できれば、まずは動作する状態になります。

    Step 02:モデリングデータ

    まめたろうさんには、Cinema 4Dから書き出したAlembicデータを用意していただきました。この時点ではまだ、「頂点が時間ごとにどのように動くか」という情報がそのまま含まれている状態です。

    同じシミュレーション結果でハイポリを書き出すため、SDSに入れてAlembic出力してみたものの上手くいかず。何度も試行錯誤するうちに、書き出し時の[Subdivision Surface]のチェックを外すことで無事解決しました……

    3種類の球体アニメーション

    球体のアニメーションは3種類用意していただきました。それぞれ、通り抜ける際の粘り具合が異なります。

    Step 03:ジオメトリ

    ジオメトリの処理は、Blender(データ準備)とThree.js(再生)の2段階に分かれます。BlenderにAlembicをインポートし、アニメーションが正しく読み込まれているかを確認します。

    Blenderから頂点データの書き出し

    頂点アニメーションの取得には、BlenderのPython APIを使用して、全フレームの頂点座標を取得します。スクリプトで行なっている処理はシンプルで、

    ・各フレームの頂点座標(x, y, z)を取得
    ・それをRGB値として画像ピクセルにマッピング
    ・EXR形式で書き出す

    というながれです。スクリプトを実行すると、VATテクスチャとして使用するEXRファイルが生成されます。

    VATテクスチャの構造

    画像の並びは以下のような構造になっています。

    ・横方向 → 頂点インデックス
    ・縦方向 → 時間(フレーム)

    つまり、1ピクセルは「ある頂点の、あるフレームにおける位置」を表します。ライティング計算のために、Positionとは別にNorma(l 法線)も同様に取得しておきます。Positionのみでも形状は再現できますが、影や陰影が破綻するため必須となります。

    なぜBlenderを使うのか?

    AlembicをそのままWebにもち込めない以上、VAT用のデータに変換する作業が必要になります。
    ・Pythonによるスクリプト拡張が充実している
    ・ Webと親和性の高いglTF形式へのエクスポートに標準で対応している
    以上の理由から、Blenderを採用しています。

    なぜEXRなのか?

    JPEGやPNGは8bit整数のため、座標値のような細かい数値を正確に保存するには精度が不足します。一方、EXRは32bit floatをそのまま保持できるため、頂点データの保存に適しています。今回はPosition用とNormal用の計2枚のEXRを、VATテクスチャとして使用しています。ファイル容量が大きいと読み込みに時間がかかるため、容量と精度(見た目)のバランスを見て、最終的にHalf Float(16bit)+ZIP圧縮のEXRにしています。

    Step 04:マテリアル&ライティング

    onBeforeCompileによるシェーダの拡張

    本実装のマテリアルは、Three.jsのMeshPhysicalMaterialをベースにしています。Three.jsのPBRによる物理ベースシェーディングを活かしつつ、onBeforeCompileを用いてコンパイル前のシェーダコードに対して自作のGLSL処理を追加しています。

    完全にシェーダを自作する場合、ライティングや環境マップの処理もゼロから実装する必要がありますが、この手法であれば、PBRを土台にしたまま必要な箇所のみを差し替えることができます。

    ▲自作のGLSL処理を追加
    ▲頂点(VAT読み出し部分)
    ▲フラグメントシェーダ(マーブル配色の核心部分)

    3種類のマテリアル設計

    球体には、それぞれ異なるマテリアル設定とフラグメントシェーダを割り当てています。ひとつひとつの球体に対して、色や模様に少しずつ変化が出るよう、ランダム性を加えてバリエーションを生成しています。その上で、表現の軸となるマテリアルは大きく3種類を設計しました。

    マテリアル1:透過ゲルボール

    transmission(物理ベースの透過)とclearcoatにより、内部が透けるゲル状の質感を表現しています。フラグメントシェーダでは、法線ベースの座標系を用いてマーブル模様を生成しています。法線ベースであるため、変形しても模様が表面に張り付いたまま追従します。

    マテリアル2:sheen付きマット

    sheen(繊維のような表面散乱)を有効にしたMeshPhysical Materialを用い、PBRパラメータの組み合わせのみで質感を表現しています。

    マテリアル3:まだらスポット

    clearcoat付きのMeshPhysical Materialに、自作のフラグメントシェーダを差し込んでいます。指定した2色からfbmノイズを用いた有機的なまだら模様を生成しています。

    ライティングとソフトシャドウ

    ライティングは、環境マップとディレクショナルライトの組み合わせです。環境マップが柔らかいハイライトを担い、ディレクショナルライトが陰影のコントラストを表現します。影には、Three.js標準のシャドウマップではなく、レンダーベースのコンタクトシャドウを自作しています。処理としては以下の通りです。

    【1】真上の正射影カメラでシルエットをレンダーターゲットに焼き付ける
    【2】ブラーパスを複数回適用してソフト化する
    【3】床面のプレーンに半透明で投影する

    VATで動くオブジェクトにも毎フレーム追従するため、アニメーション中も自然な影が維持されます。ライト位置に応じた影の方向変化は、正射影カメラの投影行列にせん断(shear)を加えることで実現しています。

    • ▲【1】真上の正射影カメラでシルエットをレンダーターゲットに焼き付ける
    • ▲【2】ブラーパスを複数回適用してソフト化する
    • ▲【3】床面のプレーンに半透明で投影する

    Step 05:インタラクション

    カーソル追従による変形カ

    マウスやタッチの座標をレイキャストで床面に投影し、シェーダに渡しています。頂点シェーダ内では、各頂点とカーソルのXZ平面上の距離に対してガウシアンフォールオフを計算し、近い頂点ほど上方向にもち上げます。これにより、カーソル付近のメッシュがぷるっと盛り上がるような変形が得られます。

    カーソル座標はlerpで追従させているため、急な移動でもなめらかに反応します。タッチデバイスでは、指が触れている間のみアクティブ値がスムーズに遷移し、離すとゆっくりと元に戻ります。

    カメラアングルの連動

    マウスやタッチの位置に応じてカメラ位置を微妙にオフセットし、カーソル位置に応じてなめらかに移動するようにしています。スマートフォンではカメラの移動量を大きくし、球体の軌道全体が見えるよう調整しています。

    実装までの試行錯誤

    BlenderからのVAT出力問題

    まず、Blenderの無料アドオンであるopenVATを用いて出力を試みましたが、生成されたデータでは頂点が崩れ、形状も歪んでしまいました。今回のデータとの相性に加え、デバッグのしやすさ(可視性)や出力フォーマットのカスタマイズの難しさもあり、Pythonスクリプトを自作する方針に切り替え。自作スクリプトにより頂点の破綻は解消できたものの、依然として形状の歪みが残り、特定の軸方向に引っ張られたようなレモン型の変形が発生しました。

    対応1:実装側の検証

    まず、実装側に問題がないかを確認するため、他のVATサンプルデータで検証を行いました。その結果、正常に表示されたことから、VATの書き出し工程に問題があると判断。EXR出力に起因する不具合の可能性が高いと考え、EXRを直接表示して値を確認するなど、検証を進めました。

    次に、ワールド座標への変換を行わず、オブジェクト基準で出力する方法を試しました。この場合、アニメーション自体は成立しているものの、形状に歪みが残る状態でした。

    さらに、頂点座標を基準となるオブジェクトの頂点との差分を出力し、実装側で基準形状に加算する手法も検証しました。この方法ではアニメーションと形状の双方が改善されたものの、最終的には本来の形状とは一致しない結果となりました。

    対応2:BIN形式に切り替え

    出力形式を見直し、生のFloat32バイナリ(.bin)への切り替えを試みました。BIN形式はフォーマット変換やガンマ補正、ヘッダー情報をもたないため、数値をそのまま読み出せる点が特徴です。この方法により値の検証が容易になり、問題の切り分けが進みました。

    その後、EXRでの出力にも再度取り組み、正常に書き出せることを確認。最終的に、形状が軸方向に引っ張られていた原因は、ガンマ補正の設定にあることが判明しました。これを踏まえ、Blenderのスクリプトに以下の処理を追記しています。

    img.colorspace_settings.name = 'Non-Color’

    制作をふり返って

    mountさんとは一度お仕事させてもらったことがあり、今回またご一緒できて光栄でした。僕のエクスポートでもたつきましたが、途中段階のものを拝見して素直に感動しました! シェーディングも可愛く魅力的で、CGとこういう協業ができるんだな~と思ったのでまた一緒に何かつくりたいですね!

    あの「ぽよんぽよん」を触れる日がくるとは……。まめたろうさんには実装の都合をお伝えするたびに、データを快く調整いただき本当に助かりました。CGとWeb、双方の歩み寄りで表現の幅が広がると実感。またご一緒できる日を楽しみにしています!

    ▲制作中のMTGの様子

    Information

    6月1日(月)〜5日(金)に開催されたオンラインイベント「CGWORLD Web Design Week」にて、ぽよんぽよん実装の裏側について改めて語っていただきました。こちらもぜひご覧ください。

    CGWORLD 2026年6月号 vol.334

    WEB ✕ 3DCG
    判型:A4ワイド
    総ページ数:112
    発売日:2026年5月9日
    価格:1,540 円(税込)

    詳細・ご購入はこちら

    TEXT_寺田奈々(mount.inc)、須多 望(mount.inc)
    EDIT_小村仁美 / Hitomi Komura(CGWORLD)、山田桃子 / Momoko Yamada