跳到正文
Qiita · Unity 开发社区· 来源· yasuharusmooth·· 2 小时前精选AI 评分85

非程序员用AI视频生成加Python脚本制作2D游戏Sprite的实践

プログラマーじゃない私が2Dアクションのアニメで3回挫折して、「AI動画→Pythonでスプライト化」に落ち着くまで

推荐理由

作者实测三种AI动画方案后,给出基于视频生成服务加Python脚本处理Sprite的完整工作流与代码细节。

正文 · 原文

私はゲームのプログラムが書けません。AIに日本語で指示して、Unity 6でゲームを作っています。

新しく2Dアクションゲームを作り始めました。3Dゲーム用に用意したエルフのアーチャーが気に入っていたので、このキャラを2Dでも活かす方針で考えました。

問題は2Dのアニメーションをどう作るかです。3つのやり方を試して、3つとも挫折しました。この記事では、なぜダメだったのかと、いま落ち着いているやり方を紹介します。

試したやり方

  1. 3DモデルをPixelOverでピクセルアート化して使う
  2. イラストからSee-through(OSS / ComfyUI)などのAIでレイヤー分解し、アクションにする
  3. イラストを複数用意し、Wan 2.x(ComfyUI)でアニメーションとしてつなぐ

→ いずれの案もダメでした(挫折しました)。

①3DモデルをPixelOverでピクセルアート化する

考えていた2Dアクションゲームは爽快感重視なので、アクション自体はある程度デフォルメされている必要がありました。

PixelOverは、3Dモデルのアニメーションクリップからボーンを当てて動作させます。つまり、まず3Dモデル側である程度モーションクリップが揃っていないと成り立ちません。2Dのデフォルメを前提にすると、そもそもアニメーションクリップから作り直す必要があります。(もちろん別のやり方もあると思いますが、そこまでは調べませんでした)

3DモデルからPixelOverは、3Dのリアル寄りな動きをそのままピクセル化する前提なら適していると思います。ただ、自分が考えていたゲームの方向性には合いませんでした。

image.png

※PixelOverは、このエルフのアーチャーではなく別のキャラで試しました。3Dモデルの歩きのクリップにボーンを当てて、ピクセル化しています。

②See-throughなどのAIでレイヤー分解する

AIによるレイヤー分解は、精度的に70〜80点くらいの出来でした。そのままではゲーム利用に耐えられず、ある程度自分の手で直す必要があります。

私は元々グラフィック系のツールに疎く、使い方や塗り方から始めることになったので、タイパが悪すぎました。

ある程度グラフィック系ツールを触ったことがある人なら、選択肢になりえると思います。

image.png

※See-throughで分解したレイヤー(前髪、顔、耳、上着、首、手、下衣、脚、後ろ髪など)を、ブラウザの画像編集ツールで開いた状態です。手で直した後のものです。

③Wan 2.x(ComfyUI)でイラストをつなぐ

自分のPC(RTX 3060 Ti 8GB)のGPUスペックでは、Wan 2.xの良いモデルは動作しませんでした。軽いモデルでは精度が全然悪かったです。

スペック的に耐えられるグラフィックボードは10万円を超えるので、別の方法を試すことにしました。

比較

やり方 向いている人・場面 私がダメだった理由
① PixelOver(3D→ピクセルアート) 3Dのリアル寄りな動きをそのままピクセル化したい人。3D側にモーションクリップが揃っている人 デフォルメした動きにしたいので、クリップから作り直しになる
② See-through などのレイヤー分解 グラフィック系ツールを触ったことがある人 精度70〜80点で手直しが必要。ツールの使い方から始まりタイパが悪い
③ Wan 2.x(ComfyUI、ローカル) VRAMに余裕のあるGPUを持っている人 8GBでは良いモデルが動かず、軽いモデルは精度が悪い
③´ 動画生成サービス+Python GPUがなくても、絵が描けなくても始めたい人 いまの採用案

落ち着いたやり方:③´ 動画生成サービス+Pythonでスプライト化

イラストを複数用意し、kling.aiなどの動画生成サービスで短い動画を作ります。それをPythonでスプライト化し、細かいフレームは間引いて、ゲーム用のスプライトにします。

前提:コマ打ちは最小限、派手さはコードとエフェクトで

企画書には、最初からこう書いています。

個人開発において「2Dアニメーション制作の泥沼」を回避するため、「キャラクター本体のコマ打ちアニメは最小限にし、プログラム制御(Tween・VFX・外付け兵器)でリッチに見せる」方針を徹底する。

キャラのアニメは「動いて見えれば十分」にして、矢や斬撃の光、ヒットストップなどの手応えはUnity側で足しています。

全体の流れ

  1. ChatGPT / Gemini でキャラの静止画を作る(単色背景・全身・足元まで写す)
  2. 動画生成サービスで短い動画にする(待機、走り、弓を撃つ、倒れる、キックなど)
  3. Pythonで透過して、スプライトシートとJSONを書き出す
  4. Pythonで、クリップごとにずれる色と大きさをそろえる
  5. UnityでJSONを読んで、自動で切り分ける

PythonスクリプトもUnity側の取り込みも、AIに作ってもらいました。手順書(AI向けのスキルファイル)もフォルダに置いて、毎回AIに読ませています。

動画生成の指示文のコツ

  • 英語で書く。日本語だと主語が抜けやすいです(日本人ならではの問題だと思います)
  • 概要 → アクションの説明 → ルール(絶対に守ってほしいこと) の順で書く
  • 特に、手足や武器が画面外にはみ出す(フレームアウトする)と、ゲームのスプライトとしては使えません。ここはルールとして明確に書きます
  • それでもフレームアウトすることはあるので、何度も作り直すことになります

例(骨組みだけです):

Overview: A side view of <character> on a plain white background.
Action: <character> <does the action>, then returns to the starting pose.
Rules:
- Keep the whole body, hands, feet and weapon inside the frame at all times.
- Fixed camera. No zoom, no camera movement.
- Side view only.

フォルダ構成

<キャラ>/
  mp4s/Idle.mp4, Run.mp4, ArrowShot1.mp4 ...   ← 生成した動画を手で置く
  sprite/<Action>/
    <Action>.png          スプライトシート(Unityに取り込むのはこれ)
    <Action>.json         コマサイズ・列数・pivot・推奨fps・使用フレーム
    <Action>_preview.gif  市松背景の確認用アニメ
Python/
  2stripe.py   動画 → 透過スプライトシート
  unify.py     クリップ間の色・大きさをそろえる

透過とフレームの間引き(2stripe.py)

背景は、アニメ向けの背景除去モデル(rembg の isnet-anime)と、背景色のキー抜きを組み合わせて消しています。全コマ共通の矩形でトリミングするので、コマごとに足元がブレません。

フレームは動画のまま全部使わず、--fps で間引きます。

種類 例 設定
待機ループ Idle --loop --fps 8
移動ループ Run, Walk --loop --fps 12 --loop-min 0.4 --loop-max 1.5
単発アクション 弓を撃つ、ジャンプ --start <秒> --end <秒> --fps 12
python -X utf8 Python/2stripe.py "<キャラ>/mp4s/Idle.mp4" -o "<キャラ>/sprite" --loop --fps 8 --save-frames
  • --loop は、きれいにつながる開始点と終了点を自動で探します
  • ブレて崩れたコマは --drop で外します
  • 間引くと「矢を放つ瞬間」のような決めの絵が抜けることがあるので、そのときは --use で使うコマを直接指定します
  • 弓を引いたまま数秒止まっている動画は、1本にせず「引く」と「放つ」に分けました。Unity側で引いた最後のコマを保持すれば、溜め撃ちにも使えます

image.png

※左が動画生成サービスで作った元動画の1コマ、右がPythonで背景を透過した1コマです。
※右は、間引いたコマを並べて書き出した走りのスプライトシート(12コマ)です。

AI動画のクセと対処

AIの動画は、頼んでいないことをよくやります。出てきた症状と対処はこうです。

症状 対処
途中でカメラが勝手に寄って、キャラが大きくなる --zoom-fix(コマの範囲で倍率をなめらかに戻す)。弓や胴など長さが変わらない物を寄る前後で測って倍率を決める。倒れる動画では18→34コマで0.74倍
寄り方が一定でない --zoom-keys(コマごとの倍率を折れ線で指定)。倍率は画像の特徴点照合(SIFT)で測る
頼んでいないのに口パクする 口を閉じた絵を貼り付けるスクリプト(mouthfix.py)
床に影を描く 影を消す。静止画から作ったクリップには影がないので、全クリップで消して、Unity側で共通の影を付ける
動画サービスの透かしロゴ --wm-rect で指定した矩形内の白っぽい画素だけ消す(重なった靴などは残る)
飛んでいく矢がコマに写り込む 矢のないコマから埋める(erase_patch.py)。矢はUnity側で弾として飛ばす
倒れたとき体が床から浮く --ground で体の下端を最初のコマの足元にそろえる
弦と脚の間の背景が残る --key-inside
途中で背景色が変わる/色ムラのあるグリーンバック --bg-per-frame --green-screen
髪先の白フチ・欠け、白い服が抜ける --erode / --key-low の調整、--mode rembg

色と大きさをそろえる(unify.py)

動画はクリップごとに生成するので、同じキャラでも髪の色やキャラの大きさが微妙にずれます。並べると別人に見えるので、Pythonでそろえています。

  • 色:基準クリップ(待機)の色を Lab 色空間で k-means して「色マスタ」を作り、他のクリップの色をそれに寄せます。陰影やグラデーションは残します。最初は12色にしましたが、髪のハイライトと肌が混ざったので16色にしました
  • 大きさ:身長はポーズで変わるので使えません。顔と胴の特徴点(SIFT)を基準クリップと照合して倍率を出します。照合は inlier 10点→6点の2段階で、5点まで下げると誤推定することを確認しています
python -X utf8 Python/unify.py palette "<キャラ>" -k 16

Unityでの取り込み

Pythonが書き出したJSON(コマサイズ、列数、pivot、推奨fps、ループの有無)を読んで、Unityのエディタ拡張がセルサイズで自動スライスし、pivotを足元に設定します。大きさはPython側でそろえているので、Unity側ではスケールを調整しません。

{ "frame_size": [W, H], "columns": N, "pivot": [x, y], "recommended_fps": 8, "loop": true }

(項目の例。値は伏せています)

再生は自作のコマ送りコンポーネントで行っています。

【動画・GIF:ゲーム内で動いているところ】

まとめ

  • 3D→ピクセルアート(PixelOver)は、リアル寄りの動きをそのまま使うなら向いている。デフォルメしたい私には合わなかった
  • AIのレイヤー分解は70〜80点。グラフィック系ツールに慣れた人なら選択肢になる
  • ローカルのWan 2.xは、8GBのGPUでは良いモデルが動かなかった
  • 動画生成サービスで短い動画を作り、Pythonで透過・間引き・色と大きさの統一までして、Unityに自動で取り込む形に落ち着いた
  • キャラのコマ打ちは最小限にして、派手さはコードとエフェクトで出す

リンク

来源:Qiita · Unity 开发社区 · qiita.com