KitsuバージョニングアドオンでBlenderファイルのリビジョン管理を行う(2026)

KitsuバージョニングアドオンでBlenderファイルのリビジョン管理を行う(2026)
🧱
混乱したファイル命名を、Blenderリビジョンの単一の真実の情報源で置き換えましょう。

すべてのプロジェクトは、良い意図から始まります。きれいなmodel.blend、整理されたフォルダ、そして「今回はちゃんと整頓しておこう」という約束からスタートします。

しかし締切が近づくにつれ、制作に静かに忍び寄るエントロピーが現実になります。やがてプロジェクトのディレクトリは、パニック気味の直前編集が積み重なった、考古学的な発掘現場のように見え始めます:

model.blend
model_v2.blend
model_v2b.blend
model_final.blend
model_final_really_final.blend
model_FINAL_v3.blend

お分かりの通りです。誰かが急な変更を必要とし、別のアーティストが「念のため」でバージョンを枝分かれさせます。そうして、いったいどのファイルが「本物」なのか、誰も確信を持てなくなっていきます。チャットのコメントはファイル名と矛盾し、古いバージョンからショットがレンダーされ、そしてスーパーバイザーは深くため息をつきます。

アニメーションスタジオでは、このような小さなカオスが積み重なります。そこで必要になるのが、きちんとした真実の情報源です。

多くのチームでは、その情報源がKitsuです。そしてBlenderアーティストにとって不足しているのは、ファイルのバージョンが管理され、追跡でき、プロジェクトの制作データと確実に揃う状態を保つ自動化されたブリッジです。

そこで方針を決めます。BlenderがKitsuと連携し、パイプラインがついに「味方してくれている」感覚になるようなバージョニングシステムを作るのです。

このチュートリアルでは、Blender上から直接ファイルのリビジョンを管理するアドオンを作成します。BlenderをKitsuプロジェクトに接続し、3Dモデルのリビジョンを作成・アップロードし、既存のすべてのリビジョンを閲覧し、さらに過去のリビジョンをBlenderへ呼び戻せるようになります。


ワークフローの概要

一般的なKitsu主導のワークフローでは、アーティストがBlenderでシーンを開き作業を行い、マイルストーンに到達したらリビジョンをアップロードします。アーティストはレビューし、改良し、修正し、そして再度アップロードします。Kitsuは各ステップをきれいに管理してくれます。

ただ、クリックひとつでリビジョンをアップロードしたり、引き戻したりできれば便利ですよね?

  1. Blenderから始める - 作業用シーンを開きます。モデリング、シェーディング、リギングなど、いま必要な作業に応じて対応します。
  2. 作業をチェックポイント化する - マイルストーン(「ブロッキング完了」「レビュー準備完了」など)に到達したら、Kitsu上で新しいリビジョンを作成します。
  3. 履歴を確認する - Kitsuはすべてのリビジョンを保存するため、スーパーバイザーには明確なタイムラインが提示され、ファイルを掘り起こさずにバージョン比較が可能になります。
  4. 新しい変更を取り込む - 別のバージョンが必要になったら、現在のワークスペースにアセットを取り込むだけです。

これは非常に基本的なワークフローなので、競合解決の扱い(同じショットに対して2人のアーティストが作業し、それぞれが新しいリビジョンを作成したら? どう処理する?)といった問題に直面するのは避けられませんが、まずはアニメーションパイプラインのニーズに合わせて後で改善できる、機能するアドオンを作るには十分です。

💡
動作例を探していますか?

このガイドで紹介する例の統合について、完全なソースコードはGitHubで確認できます:

🔗 https://github.com/cgwire/blender-kitsu-versioning-addon

1. Kitsuダッシュボードを準備する

KitsuのWebインターフェースは、プロデューサー、コーディネーター、リードがプロジェクトの構造を素早く設定できるように設計されています。Blenderアーティストがリビジョンを公開する前に、制作中のアセットで制作データを埋めておく必要があります。 ローカル開発用のKitsu Dockerインスタンスでは:

  1. Kitsuダッシュボードにログインします。
  2. メインのナビゲーションバーでProductionsに移動します。
  3. 「Create production」をクリックします(通常は右上)。
  4. 制作情報を入力します

新しい制作はリストに表示されるので、開いてアセットの追加を開始できます。

アセットはプロジェクトの構成要素です。キャラクター、小道具、環境、車両... 制作管理が必要なものは何でも対象になります。

  1. Productions → あなたの制作名へ移動します。
  2. 制作内のAssetsタブに切り替えます。
  3. 「Create Asset」をクリックします。
  4. アセット名(例:「RobotHead」)とアセット種別(Character, Prop, Setなど)を入力します。

これでアセットが作成され、3つのタスクが割り当てられました。 

タスクは、各アセットに対してアーティストが行う制作手順(モデリング、シェーディング、リギングなど)を定義します。

これで、アドオンをテストするための準備が整いました。


2. 現在のBlenderプロジェクトをKitsuのタスクに紐づける

まずは、UIの配置を定義し、gazuを読み込み、ドロップダウンメニューで公開するデータを準備する最小限のアドオン宣言から始めます:

bl_info = {
    "name": "Model Versioning (Production/Task/Asset/Revisions)",
    "author": "cgwire",
    "version": (1, 0, 0),
    "blender": (2, 80, 0),
    "location": "View3D > Sidebar > ModelVersioning",
    "description": "Browse productions, tasks, assets, and manage revisions (list/create/load)",
     "category": "3D View",
}

import sys

sys.path.append("~/.local/lib/python3.11/site-packages")

import os import tempfile

import bpy import gazu from bpy.props import EnumProperty, PointerProperty from bpy.types import Operator, Panel, PropertyGroup

注目点として、sys.path.append("~/.local/lib/python3.11/site-packages")により、gazuのような外部パッケージへアクセスするためにローカルのPythonインストールを使用できます。デフォルトではBlenderが独自のPython環境を動かすため、パッケージのインストールはやや面倒です。そこで、ローカルモジュールを参照するようBlenderに伝えます。このパスは、あなたのシステム設定に合わせて適宜更新してください。

バージョニングを自動化する前に、BlenderがKitsu上のどこに現在のモデルが属するのかを理解する必要があります。つまり、プロジェクト、アセット、タスク、そして最終的にそれに紐づくリビジョンを特定します。

最初のステップは簡単です。Kitsuで認証し、利用可能な制作(Productions)を取得し、アーティストがサイドバーUIからコンテキストを直接選べるようにします。

アドオンが読み込まれたら、認証し、アドオンをKitsu APIホストへ向けます:

gazu.set_host("<http://localhost/api>")
user = gazu.log_in("admin@example.com", "mysecretpassword")

temp_dir_path = tempfile.gettempdir()

これにより、制作を閲覧し、タスクを見つけ、そして最終的にリビジョンを作成するために使うセッションが確立されます。

ここから制作の構造を公開し始められます。プロジェクト、アセット、タスク、リビジョンの検索用ヘルパー関数を用意し、各ドロップダウンを動的に埋めます:

def find_project(name):
    return gazu.project.get_project_by_name(name)

def find_asset(project, name):     return gazu.asset.get_asset_by_name(project, name)

def find_task(asset, type_id):     return gazu.task.get_task_by_name(asset, type_id, "main")

EnumPropertyのコールバックは、Kitsuから新しいデータを取得します:

def enum_projects(self, context):
    items = 
    projects = gazu.project.all_projects()
    for p in projects:
        items.append((p"name", p"name", ""))
    if not items:
        items.append(("NONE", "--- no productions ---", ""))
    return items

アセット、タスク、リビジョンも同じパターンに従います:

def enum_assets(self, context):
    project = find_project(context.scene.mv_state.project)
    items = 
    if project:
        assets = gazu.asset.all_assets_for_project(project)
        for t in assets:
            items.append((t"name", t"name", ""))
    if not items:
        items.append(("NONE", "--- no tasks ---", ""))
    return items

def enum_tasks(self, context):     project = find_project(context.scene.mv_state.project)     asset = find_asset(project, context.scene.mv_state.asset)     items =     if asset:         tasks = gazu.task.all_tasks_for_asset(asset)         for t in tasks:             items.append((t"task_type_id", t"task_type_name", ""))     if not items:         items.append(("NONE", "--- no tasks ---", ""))     return items

def enum_revisions(self, context):     project = find_project(context.scene.mv_state.project)     asset = find_asset(project, context.scene.mv_state.asset)     task = find_task(asset, context.scene.mv_state.task)     items =     if task:         revisions = gazu.files.get_all_preview_files_for_task(task)         for r in revisions:             items.append((str(r"revision"), str(r"revision"), ""))     if not items:         items.append(("NONE", "--- no revisions ---", ""))     return items

最後に、すべてのUI選択を1つの状態(state)オブジェクトに保存します:

class MV_State(PropertyGroup):
    project: EnumProperty(
        name="Project", description="Select project", items=enum_projects
    )
    asset: EnumProperty(name="Asset", description="Select asset", items=enum_assets)
    task: EnumProperty(name="Task", description="Select task", items=enum_tasks)
    revision: EnumProperty(
        name="Revision", description="Select revision", items=enum_revisions
    )

これはパイプライン統合の土台です。これでBlenderはKitsuを閲覧でき、アーティストが作業中の“正確なタスク”に自分自身を紐づけられるようになりました。ここから、リビジョンのライフサイクルに取り組み始めます。


3. 「新規リビジョン」ボタンを作成する

まずアーティストが最も頻繁に触れる部分の自動化を始められます。それが新しいリビジョンの作成です。通常の手作業ワークフローでは、ファイルをエクスポートして、正しいタスクに対してKitsuへアップロードします。私たちのアドオンでは、その作業をBlender内の1つのボタン操作にまとめます。

Kitsuはpublish_preview()を通じて新しいリビジョンを処理します。これはファイルとメタデータの両方を送信します:

temp_file_path = os.path.join(temp_dir_path, "new_version.glb")

bpy.ops.export_scene.gltf(filepath=temp_file_path, export_format="GLB")

(comment, preview_file) = gazu.task.publish_preview(     task,     task_status,     revision=new_revision,     comment="increment revision",     preview_file_path=temp_file_path, )

os.remove(temp_file_path)

アドオンでは、これをサイドバーのボタンからトリガーします。

オペレーターは主に3つのステップを実行します。アドオンの状態からユーザーの選択を取得し、次のリビジョン番号を計算し、エクスポートしたファイルを新しいリビジョンとしてアップロードします:

class MV_OT_create_revision(Operator):
    bl_idname = "mv.create_revision"
    bl_label = "Create Revision"

    def invoke(self, context, event):         wm = context.window_manager         return wm.invoke_props_dialog(self, width=400)

    def execute(self, context):         project = find_project(context.scene.mv_state.project)         asset = find_asset(project, context.scene.mv_state.asset)         task = find_task(asset, context.scene.mv_state.task)         revision = context.scene.mv_state.revision         new_revision = int(revision) + 1

        task_status = gazu.task.get_task_status_by_name("todo")

        temp_file_path = os.path.join(temp_dir_path, "new_version.glb")

        bpy.ops.export_scene.gltf(filepath=temp_file_path, export_format="GLB")

        (comment, preview_file) = gazu.task.publish_preview(             task,             task_status,             revision=new_revision,             comment="increment revision",             preview_file_path=temp_file_path,         )

        os.remove(temp_file_path)

        self.report({"INFO"}, "Revision created")         return {"FINISHED"}


4. リビジョンをBlenderへ取り込む

バージョニングは、公開することだけではありません。戻ることも重要です。以前の段階をレビューしたり、トポロジを比較したり、前回の反復から細部を復元したりする場合、Blenderへ新しいリビジョンや古いリビジョンを素早く確実に読み込む手段が必要です。

タスクが選択されると、Kitsuからリビジョンを取り出すのは簡単な2ステップになります。選択したリビジョンに紐づくプレビューファイルをダウンロードし、それをBlenderへインポートします。

現在のタスクに対するすべてのプレビューファイルを取得したら、インデックスで目的のリビジョンを特定し、アセットを直接Blenderへ取り込みます:

temp_file_path = os.path.join(temp_dir_path, "new_version.glb")

preview_file = preview_filesint(revision) - 1 gazu.files.download_preview_file(preview_file, temp_file_path) bpy.ops.import_scene.gltf(filepath=temp_file_path)

os.remove(temp_file_path)

これにより、制作のその時点での状態そのままのアセットを、統一された手順で取得できるようになります。

このワークフローを、作成(Create Revision)ボタンの構造と同様のオペレーターにまとめます:

class MV_OT_load_revision(Operator):
    bl_idname = "mv.load_revision"
    bl_label = "Load Revision"

    def execute(self, context):         project = find_project(context.scene.mv_state.project)         asset = find_asset(project, context.scene.mv_state.asset)         task = find_task(asset, context.scene.mv_state.task)         revision = context.scene.mv_state.revision         preview_files = gazu.files.get_all_preview_files_for_task(task)

        temp_file_path = os.path.join(temp_dir_path, "new_version.glb")

        preview_file = preview_filesint(revision) - 1         gazu.files.download_preview_file(preview_file, temp_file_path)         bpy.ops.import_scene.gltf(filepath=temp_file_path)

        os.remove(temp_file_path)

        self.report({"INFO"}, "Opened Revision")         return {"FINISHED"}

このオペレーターにより、アーティストはBlenderを離れることなく、Kitsuに保存されている任意のバージョンを閲覧して読み込むことが簡単になります。


5. アドオンを登録する

このパネルが、リビジョンのワークフロー全体をつなぎます

  • プロジェクトを選択
  • アセットを選択
  • タスクを選択
  • リビジョンを閲覧
  • クリックひとつでバージョンを作成または読み込み
class MV_PT_panel(Panel):
    bl_label = "Model Versioning"
    bl_idname = "MV_PT_panel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "ModelVersion"

    def draw(self, context):         layout = self.layout         scene = context.scene         mv = scene.mv_state

        layout.label(text="Project")          layout.prop(mv, "project", text="")         layout.separator()

        layout.label(text="Asset")          layout.prop(mv, "asset", text="")         layout.separator()

        layout.label(text="Task")          layout.prop(mv, "task", text="")         layout.separator()

        layout.label(text="Revision")          layout.prop(mv, "revision", text="")         layout.separator()

        row = layout.row(align=True)         row.operator("mv.create_revision", text="Create Revision", icon="ADD")

        layout.operator(             "mv.load_revision", text="Load Selected Revision", icon="IMPORT"         )

最後に、オペレーター、パネル、状態(state)を登録して、BlenderがUIを構築できるようにします:

classes = (
    MV_State,
    MV_OT_create_revision,
    MV_OT_load_revision,
    MV_PT_panel,
)

def register():     for c in classes:         bpy.utils.register_class(c)     bpy.types.Scene.mv_state = PointerProperty(type=MV_State)

def unregister():     for c in reversed(classes):         bpy.utils.unregister_class(c)     if hasattr(bpy.types.Scene, "mv_state"):         del bpy.types.Scene.mv_state

if name == "main":     register()

この時点で、モデルのバージョニングワークフローは完全に双方向になっています。Blenderから新しいリビジョンを公開でき、以前のものを即座に取得できます。


結論

Blender APIのオペレーターを数個と、Gazu SDKの便利さを組み合わせることで、Blenderの中にそのまま存在し、Kitsuと同期し続ける、実用的(ただし基本的な)バージョニングワークフローを構築しました。アーティストはBlenderのシーンをKitsuのプロジェクト、アセット、タスクに紐づけ、新しいリビジョンをボタンひとつで作成し、任意のタスクのリビジョン履歴をすべて閲覧し、比較や復元が必要になったときは古いバージョンを直接Blenderへ取り込めます。

このワークフローは、まだ始まりにすぎません。ここから、アドオンを拡張して自動エクスポート、サムネイルやトゥルーターンテーブルのレンダリング、複数の出力形式の対応、スーパーバイザー向けレビュー用ツール、さらにはレンダーファームへの連携などに広げられるでしょう。

まずは、このバージョニングアドオンの GitHubリポジトリをクローンして、自分でも試してみてください!

📽️
アニメーション制作のプロセスについてさらに学ぶには、Discordコミュニティへの参加をご検討ください。私たちは1,000人以上の専門家とつながっており、ベストプラクティスを共有し、時には現地イベントも開催しています。ぜひ歓迎します! 😊

この記事はいかがでしたか?

ニュースレターを購読して、さらなる考察、チュートリアル、業界ニュースをお受け取りください。