GIFからフリップブックテクスチャへ — 任意のGIFをUnity & VRChat用のフレームストリップにパック

自分でgifからフリップブックを作成する
GIFをUnity、Godot、VRChat向けの単一列フリップブックテクスチャにパックします。グリッド自動配置、すぐに使えるrows/columnsメタデータ、透過背景に対応。
GIFはタイムラインです。フリップブックテクスチャは、その同じタイムラインを1枚の画像にパックしたもので、プレイヤーがフレームをシークする代わりに、シェーダーがインデックスでそれを走査できるようにします。GIFをツールにドロップすると、フレーム数、寸法、遅延を検出し、マテリアルに貼り付けるrowsとcolumnsのメタデータ付きで、単一列またはグリッドのストリップを書き出します。
このページでは、gifからフリップブックへの変換がUnity、Godot、VRChat向けに実際に何を生成するのかを扱います。フリップブックシェーダーが必要とする4つの数値、Poiyomiマテリアルで設定すべき項目、そしてフレームストリップがグリッドより優れるのはどのような場合か。出力は透過背景のPNGで、その横にrow/column数がプレーンテキストで記載されます。
GIFをドロップ
ツール本体が最初の画面です。ドロップゾーンが上部にあり、その下はすべて出力です。GIFをドラッグすると、ツールはフレーム数、フレームごとの遅延、キャンバスサイズ、処理方法を読み取ります。実際のGIFはこの4項目すべてについて見解が一致しないため、何かを書き出す前に、検出した内容を報告します。
通常、判断が必要になる点が2つあります。1つ目は不均一なフレーム遅延です。ほとんどのフリップブックシェーダーは一定のFPSで進むため、遅延が混在するGIFは固定レートにリサンプリングするか、最も遅い共通のフレーム時間でエクスポートする必要があります。2つ目は処理方法です。フレーム間で変更された領域だけを再描画するGIFは、フレームを単純に重ねるとゴーストが表示されます。ツールはパック前に各フレームをフルキャンバスに合成するため、部分的な再描画はフルフレームになります。
合成が完了すると、パッカーは1枚の画像を書き出します。24フレームの128x128 GIFは3072x128のストリップになります。同じフレームを6x4グリッドにすると768x512になります。どちらも同じピクセルで、違いはシェーダーがUVをどう扱うかだけです。
01
GIFをドロップゾーンにドロップします。報告されたフレーム数、遅延、キャンバスサイズを確認します。
02
パックレイアウトを選択します。UVスクロールシェーダーには単一列、アトラスやエンジンインポートにはグリッドを選びます。グリッドのcolumnsは画像が正方形に近くなるよう自動選択されます。
03
GIFのフレーム遅延が不均一な場合はリサンプルレートを選択します。デフォルトは遅延の中央値です。シェーダーが一定レートで進む場合は固定FPSを選んでください。
04
エクスポートします。透過背景のPNGが1枚、それに加えてrows、columns、フレーム数、FPSがテキストで出力され、マテリアルやスクリプトに貼り付けられます。
フリップブックテクスチャとは
フリップブックシェーダーは4つの数値を読み取ります。rows、columns、現在のindex、FPSです。0から1の範囲のUV座標を取得し、それをrow/columnのセルに分割し、そのセルを現在のindexでシフトします。テクスチャ自体は静的です。indexが動くまで何もアニメーションしません。
indexは通常、時間から導出されます。列ストリップの場合、indexはfloor(time × FPS)となり、U座標はindex ÷ columnsでオフセットされます。グリッドの場合、indexはrowも与えます。row = floor(index ÷ columns)、column = index mod columnsです。これが列ストリップがより簡単なケースである理由です。走査する次元が1つしかありません。
rowsとcolumnsは画像と正確に一致する必要があります。3072x128のストリップで24 columns、1 rowを宣言すると正しくサンプリングされます。23 columnsを宣言すると、すべてのフレームがセルの端数分ずれ、斜めのスミアとして見えます。1 columnを宣言すると静止画になります。この2つのミスが、壊れたフリップブックのほとんどを占めています。
FPSはフレーム数とは別です。24フレームのストリップを12 FPSで再生すると1秒に2回ループします。24フレームのストリップを24 FPSで再生すると1秒に1回ループします。テクスチャデータは同一で、変わるのはクロックだけです。FPSはrowsとcolumnsの数値と同じ場所に保管し、互いにずれないようにしてください。
4つの数値
rows、columns、index、FPS。rowsとcolumnsはテクスチャを記述します。indexとFPSは時間を記述します。rowsとcolumnsはエクスポート時に固定されます。indexは動的で、シェーダーまたはスクリプトに属します。FPSはほとんどのシェーダーで固定ですが、速度を制御したい場合はパラメータで駆動できます。
シェーダーにspeedまたはplayback rateパラメータがある場合、それはFPS定数ではなく時間の項に掛け算されます。エクスポートしたFPSを基準レートとして維持することで、speedが1のときにメタデータが意味を持ち続けます。
Unity用フリップブックテクスチャ
Unityでは、フリップブックは通常クアッドまたはパーティクル上のマテリアルです。PNGはsRGBを有効にしてインポートし、フレームが小さい場合はミップマップを無効にし、alpha is transparencyを有効にします。Wrap modeはRepeatではなくClampにしてください。繰り返し設定のフリップブックはUVの端で最後のフレームが最初のフレームに回り込み、1ピクセルの継ぎ目が見えます。
indexを駆動する方法は2つあります。組み込みのフリップブックノードを持つUnlitまたはParticlesシェーダーでは、tilingをrowsとcolumnsに設定し、0から1のblend値を渡します。カスタムシェーダーでは、UVの計算を自分で書き、rows、columns、FPSをマテリアルプロパティとして公開し、再コンパイルなしで編集できるようにします。
貼り付けるメタデータは、rows、columns、フレーム数、エクスポートしたFPSです。シェーダーが整数のindexではなく正規化されたblendを使用する場合、blend範囲は0からフレーム数 ÷ グリッドセル総数です。24フレームの単一列では0から1、24セル中24フレームの6x4グリッドでも0から1です。グリッドが部分的に埋まっている場合にこれが問題になります。20フレームの6x4グリッドは20 ÷ 24、つまり約0.833で終わります。それを超えて走査すると空のセルをサンプリングします。
- 透過背景エクスポートされたPNGはalphaを保持するため、クアッド上のフリップブックに乗算ブレンドやクロマキーは不要です。マットカラーを持つソースGIFは、代わりにそのマットカラーがalphaに書き込まれます。
- 小さいサイズではミップマップを無効に1辺256ピクセル未満のフレームは、ミップマップを無効にした方が良好です。ミップチェーンの生成はストリップ内の隣接フレームをブレンドするため、距離が離れるとフリップブックは全フレームの平均になります。
- ClampラップRepeatラップのストリップは継ぎ目をまたいでサンプリングします。wrap UとVをClampに設定し、最後のフレームが最初のフレームににじまないようにしてください。
VRChat用Poiyomiフリップブック
Poiyomiはフリップブックノードを搭載しており、アバターの口パク、スクロールするスクリーン、2フレームのトグルなどで通常使われる経路です。ノードはテクスチャ、rowsとcolumnsのペア、blend値を受け取ります。VRChatはスクリプトから実行時にカスタムシェーダーコードを実行できないため、indexはアニメーションするマテリアルプロパティまたはアニメーター駆動のパラメータから取得する必要があります。
メッシュはマテリアルと同じくらい重要です。平面クアッド上のフリップブックは正しく見えますが、同じテクスチャを曲面に貼るとUVが不均一に分布し、セルが引き伸ばされて見えます。フリップブックのマテリアルは平面またはほぼ平面のメッシュに留めてください。
Poiyomiでは、アニメーションがループの場合はストリップレイアウトで作業します。UVの計算が乗算1回と加算1回で済むためです。アニメーションが、ジャンプして切り替えたい離散的な状態の集合である場合はグリッドレイアウトを使用します。4つの形を持つ口は、スクロールとして捉えるより、整数のindexを持つ4x1グリッドとして考える方が扱いやすくなります。
01
離散的な状態が必要でない限り、ストリップレイアウトでエクスポートします。rowsが1、columnsがフレーム数と等しいことを確認してください。
02
PNGをUnityにインポートします。Wrap modeをClamp、sRGBを有効、alpha is transparencyを有効、小さいテクスチャはstreamingを無効に設定します。
03
PoiyomiでFlipbookノードを作成します。テクスチャを割り当てます。rowsとcolumnsをエクスポートした値に設定します。
04
blend入力を駆動します。ループの場合、アニメーションするfloatパラメータから時間ベースの値を渡します。離散的な状態の場合、整数のindexをblendに変換して渡します。
05
alphaとrender queueを設定します。フェードが必要なフリップブックは、マテリアルの他の部分と同じ透過設定を使用します。別途cutoutを有効にしないでください。
06
Playモードでテストし、その後アバターアップロードでテストします。ループポイントを確認します。最後のフレームの後に間を置かず最初のフレームが続く必要があります。
フレームストリップ vs グリッド:どちらをエクスポートするか
ピクセルデータは同一です。選択はそれを消費する側によって決まります。シェーダーはストリップを求めます。エンジンとスプライトシステムはグリッドを求めます。ファイルサイズではなく、消費する側に基づいて選んでください。ストリップは横長、グリッドは正方形寄りで、同じ総ピクセル数であればどちらも同程度に圧縮されます。
ストリップは1行なので、V座標は未使用でシェーダーはUだけをシフトします。これは命令数が少なく、計算を間違える余地も少なくなります。グリッドは両軸を使い、これはアトラスベースのシステムが期待する形です。迷った場合はストリップをエクスポートし、エンジンのインポーターが求めたときにだけグリッドで再エクスポートしてください。
もう1つ、個別のフレームを期待するスプライトアニメーターのケースがあります。一部のエンジンはアトラスではなくPNGのフォルダを求めます。ツールはフレームを個別に書き出せますが、その場合ディスク上の画像は1ファイルではなく全フレームの合計となり、インポート設定はフレームごとになります。
| 消費する側 | レイアウト | 読み取るもの | 備考 |
|---|---|---|---|
| シェーダーフリップブック | 単一列 | rows 1、columns N、Uオフセット | UV命令が最小、ループが容易 |
| スプライトアトラス | グリッド | rows M、columns N、セルサイズ | セルサイズはキャンバスサイズと等しい |
| スプライトアニメーター | グリッドまたは個別PNG | フレーム順序とFPS | 個別PNGは単一ファイルパックを失う |
| エンジンインポート | グリッド | rows、columns、フレーム数 | テクスチャ制限を守るため画像を正方形に近づける |
3Dで再生する
静的平面に貼ったフリップブックテクスチャは何も証明しません。確認すべき主張は、動かして初めて現れるもの、つまり継ぎ目が回り込むか、alphaが距離を置いても保たれるか、カメラが動いたときにFPSが適切に感じられるかです。The Cyclops' Islandは3Dゲームビルダーで作られたプレイ可能なシーンで、サーフェスがリアルタイムでアニメーションするため、インスペクターではなくジオメトリの隣でフリップブックのループを眺められます。
開いて、サーフェスを歩き、ループポイントを観察してください。フリップブックが1フレーム足りない、あるいは1 column分広いなら、アセットをアップロードする前にそこで分かります。目に見える引っかかりや斜めのスミアとして現れます。これがプレイ可能なシーンの主張のすべてです。失敗は視覚的なものであり、視覚的な失敗にはビューポートが必要です。
同じシーンは、フレームの切り替えが様々な距離やカメラアングルでどう見えるかのリファレンスにもなります。近くで128ピクセルなら問題ないフレームも、ミップ制御なしでは距離を置くとエイリアシングします。遠くで問題ないフレームも、近距離では柔らかすぎることがあります。どちらも動かしながらの方が判断しやすくなります。
それが属する世界へ足を踏み入れる
スプライトとは、立つ場所を持たないキャラクターです。最後のステップは他にはないものです。今作ったシートを、誰かが歩き回れる世界、つまり小さな島、惑星、雨の街角に置いてください。このサイトのすべてのワールドは、1つの書かれた説明から作られ、プレイできるページとして公開されています。
FAQ
Poiyomiフリップブックとは何ですか? +
PoiyomiはUnityとVRChat用のシェーダーパッケージで、そのFlipbookノードはパックされたフレームストリップをサンプリングし、マテリアルがアニメーターなしでフレームを循環できるようにします。テクスチャ、rowsとcolumns、blend値を渡します。blend値がindexを動かすもので、通常はアニメーションするfloatパラメータで駆動されます。
フリップブックに斜めのスミアが表示されるのはなぜですか? +
宣言したcolumn数が画像と一致していません。24フレームのストリップを23 columnsとしてサンプリングすると、すべてのフレームがセルの端数分ずれ、それが積み重なってストリップ全体に斜めのスミアとして現れます。エクスポートしたcolumnsの値と実際のフレーム数を再確認してください。
ストリップとグリッドのどちらをエクスポートすべきですか? +
シェーダーフリップブックには単一列をエクスポートしてください。UVの計算が1次元で、ループが自明になるためです。スプライトアトラスやrowsとcolumnsを期待するエンジンインポーターにはグリッドをエクスポートします。ピクセルは同じで、異なるのは消費する側だけです。
透過背景を保つにはどうすればよいですか? +
エクスポートは色にフラット化するのではなく、alphaをPNGに書き込みます。インポート時はalpha is transparencyを設定し、sRGBを有効のままにしてください。ソースGIFが実際の透過ではなくマットカラーを使用していた場合、ツールはフルフレームを透過キャンバスに合成するため、マットカラーは残りません。
GIFのフレーム遅延が不均一です。どのFPSを使用すればよいですか? +
固定レートを選んでください。デフォルトは遅延の中央値で、通常はブラウザでGIFがどのように見えるかに近くなります。フリップブックシェーダーは一定のクロックで進むため、混在した遅延は1つのフレーム時間にリサンプリングしない限り表現できません。
フリップブックがループポイントで引っかかるのはなぜですか? +
フレーム数に重複した最後のフレームが含まれているか、FPSがソースからわずかにずれているかのどちらかです。エクスポートしたフレーム数とFPSの値を合わせて確認してください。一時停止するループは、ほぼ常にシェーダーの問題ではなく、余分な1フレームが原因です。
3Dゲームビルダーに戻る
完成した31個の3Dワールド、ゲーム、シーンはすべて1つのページにあり、そのすべてがプレイ可能です。
フリップブック対応ストリップを見る
このライブラリのすべてのアセットは、記録されたプロンプト付きの透過されたゲーム対応PNGです — スプライトシートリソースと無料スプライトシートで、アクション、スタイル、被写体でタグ付けされています。閲覧とダウンロードは無料です。