Claude Media
Claude CodeでUnityのインポート設定を一括点検する — テクスチャとFBXをCSVに出す

Claude CodeでUnityのインポート設定を一括点検する — テクスチャとFBXをCSVに出す

テクスチャの圧縮形式やFBXのRead/Write設定を、Editorスクリプトで全アセットからCSVに書き出す手順です。-batchmode -executeMethodで回し、結果をClaude Codeに分類させます。

Unityのインポート設定は、アセットごとに数十項目あります。数千枚のテクスチャとFBXを目視で点検するのは現実的ではありません。Claude CodeにEditorスクリプトを書かせ、バッチモードで全アセットの圧縮形式やRead/Write設定をCSVに出せば、点検は「表を読む作業」に変わります。

ここでの方針は一つです。.metaをテキストとして読ませるのではなく、Unity自身のImporter APIで値を読み、CSVに落とします。点検は読み取り専用で回し、修正は別メソッドに分けます。

.metaを直接読ませず、Importer APIで読む理由

インポート設定の保存先は.metaファイルです。Unityのマニュアルによると、.metaはアセットごとに作られ、固有IDとインポート設定のすべての値を持ちます。設定を変えると新しい値が.metaに保存され、Unityがその設定で再インポートします。

つまり.metaをgrepすれば値は拾えます。ただしYAMLのキー名と、Editor上の項目名は一対一には並びません。プラットフォーム別の上書きも、デフォルト設定とは別のブロックに入ります。Claude Codeに正規表現で拾わせると、読み違いの検証が重くなります。

TextureImporterとModelImporterは、同じ設定をC#のプロパティとして公開しています。次のような項目です。

対象プロパティ点検の狙い
テクスチャプロパティmaxTextureSize点検の狙い必要以上に大きい画像の洗い出し
テクスチャプロパティtextureCompression / crunchedCompression点検の狙い無圧縮のまま残った画像の検出
テクスチャプロパティisReadable点検の狙いCPU側に追加コピーを持つ画像の検出
テクスチャプロパティmipmapEnabled / sRGBTexture点検の狙いUI用と3D用の設定の取り違え
FBXプロパティisReadable / meshCompression点検の狙いスクリプトから読めるメッシュと圧縮の有無
FBXプロパティimportBlendShapes / importCameras / importLights点検の狙い使っていない要素の取り込み

isReadableは、マニュアルでは「CPUからアクセスできる領域に、ピクセルデータの追加コピーを保持するか」と説明されています。スクリプトから読む必要がない画像で有効になっていると、メモリを余計に使います。一括点検で最初に洗い出す価値がある項目です。

.metaが無いアセットの検出にも使えます。AssetImporter.importSettingsMissingは、メタファイルが無いアセットでtrueになります。

点検ルールをCLAUDE.mdに書く

ルールの数値は、プロジェクトごとに違います。Claude Codeに「適切なサイズ」を推測させず、基準をCLAUDE.mdに置きます。次は書き方の一例で、数値はあくまで仮置きです。

## インポート設定の点検
- 点検スクリプトは Assets/Editor/ImportAudit.cs に置く。アセットは変更しない
- Assets/Art/UI 配下: maxTextureSize 2048 以下、mipmapEnabled は false
- Assets/Art 配下の isReadable は原則 false。true にするのは理由がコメントにあるものだけ
- FBX の importCameras / importLights は false が既定
- 結果は audit/import-report.csv に書く。1 行 1 アセット、列名は固定

例外も同じ場所に書いておきます。たとえばスクリプトからピクセルを読む画像は、isReadableがtrueで正しい状態です。例外のパスをCLAUDE.mdに列挙しておけば、Claude Codeは毎回それを違反として報告せず、報告の中で本当に直すべき行が埋もれません。例外の理由もコメントで残すと、数か月後に見直すときの判断材料になります。

基準がファイルにあれば、次のセッションでも同じ物差しで点検が回ります。数値を変えたときはこの1か所だけ直せば済みます。

ステップ1: 点検用のEditorスクリプトを書かせる

Claude Codeには、次のように依頼します。

Assets/Editor/ImportAudit.cs に、CSV を書き出す静的メソッド ImportAudit.Run を作って。
t:Texture2D と t:Model を AssetDatabase.FindAssets で列挙し、TextureImporter と
ModelImporter から値を読む。アセットの設定は一切変更しない。
-auditRoot と -auditOut はコマンドライン引数から受け取り、失敗したら終了コード 1 で終わる。

Unityのマニュアルは、-executeMethodで呼ぶスクリプトをEditorフォルダに置き、メソッドをstaticにするよう求めています。依頼文にこの2点を入れておくと、置き場所の間違いを避けられます。生成される実装の一例は次の形です。TextureImporter / ModelImporterのAPIリファレンスにあるプロパティ名だけで組んだ例なので、Unityのバージョンによってプロパティの有無が変わります。生成後はまず狭いフォルダで1回実行し、CSVの列が埋まるかを確かめます。

using System;
using System.IO;
using System.Text;
using UnityEditor;
 
public static class ImportAudit
{
    public static void Run()
    {
        try
        {
            string root = GetArg("-auditRoot") ?? "Assets";
            string outPath = GetArg("-auditOut") ?? "audit/import-report.csv";
            var sb = new StringBuilder();
            sb.AppendLine("kind,path,hasMeta,maxSize,compression,crunched,mipmap,srgb,readable,androidOverride,meshCompression,blendShapes,cameras,lights");
 
            foreach (string guid in AssetDatabase.FindAssets("t:Texture2D", new[] { root }))
            {
                string path = AssetDatabase.GUIDToAssetPath(guid);
                var t = AssetImporter.GetAtPath(path) as TextureImporter;
                if (t == null) continue;
                var android = t.GetPlatformTextureSettings("Android");
                sb.AppendLine(string.Join(",", "texture", Q(path), !t.importSettingsMissing,
                    t.maxTextureSize, t.textureCompression, t.crunchedCompression,
                    t.mipmapEnabled, t.sRGBTexture, t.isReadable, android.overridden, "", "", "", ""));
            }
 
            foreach (string guid in AssetDatabase.FindAssets("t:Model", new[] { root }))
            {
                string path = AssetDatabase.GUIDToAssetPath(guid);
                var m = AssetImporter.GetAtPath(path) as ModelImporter;
                if (m == null) continue;
                sb.AppendLine(string.Join(",", "model", Q(path), !m.importSettingsMissing,
                    "", "", "", "", "", m.isReadable, "", m.meshCompression, m.importBlendShapes,
                    m.importCameras, m.importLights));
            }
 
            Directory.CreateDirectory(Path.GetDirectoryName(outPath));
            File.WriteAllText(outPath, sb.ToString(), new UTF8Encoding(false));
            UnityEngine.Debug.Log("ImportAudit: rows=" + (sb.ToString().Split('\n').Length - 2));
            EditorApplication.Exit(0);
        }
        catch (Exception e)
        {
            UnityEngine.Debug.LogError(e);
            EditorApplication.Exit(1);
        }
    }
 
    static string Q(string s) => "\"" + s.Replace("\"", "\"\"") + "\"";
 
    static string GetArg(string name)
    {
        string[] args = Environment.GetCommandLineArgs();
        int i = Array.IndexOf(args, name);
        return (i >= 0 && i + 1 < args.Length) ? args[i + 1] : null;
    }
}

CSVの列は、点検表の項目と1対1に対応させています。srgbはsRGBTexture、camerasとlightsはimportCamerasとimportLightsの値です。テクスチャ行ではモデル用の列が空欄、モデル行ではテクスチャ用の列が空欄になります。列名と並びを固定しておけば、Claude Codeが行を読むときに列の取り違えが起きにくくなります。

読むべきところは4つあります。

  • 引数はSystem.Environment.GetCommandLineArgsで受けます。マニュアルがこの方法を案内しています。
  • 失敗時は例外を投げるか、EditorApplication.Exitに0以外を渡します。どちらでもプロセスの終了コードが変わり、CIやシェルから失敗を検知できます。
  • パス列はQで引用符を付けます。フォルダ名にカンマを含むプロジェクトで、列がずれるのを防ぎます。
  • 最後に出力行数をログへ書きます。結果が少ないときに、スクリプトが動いたのか対象が無かったのかを切り分けられます。

プラットフォーム別の上書きは、GetPlatformTextureSettingsにビルドターゲット名を渡して読みます。上の例はAndroidだけの一例です。iOSやデスクトップ向けの上書きも見たいなら、GetPlatformTextureSettingsをターゲットごとに呼ぶ行と、overriddenの列を足すよう依頼します。上書きが有効なターゲットでは、デフォルト設定のmaxTextureSizeや圧縮形式より、上書き側の値が書き出し結果に効きます。そのため、デフォルト列だけを見た点検は、上書きのあるアセットで実態とずれることがあります。

ステップ2: バッチモードで実行してCSVを出す

実行は-batchmodeと-executeMethodの組み合わせです。マニュアルによれば、バッチモードはダイアログを出さずに引数だけを処理し、例外や操作の失敗では終了コード1で終わります。

/Applications/Unity/Hub/Editor/<version>/Unity.app/Contents/MacOS/Unity \
  -batchmode -nographics \
  -projectPath . \
  -executeMethod ImportAudit.Run \
  -auditRoot Assets/Art -auditOut audit/import-report.csv \
  -logFile /tmp/unity-audit.log
echo "exit code: $?"

-nographicsを付けるとログ出力が止まるため、-logFileでファイルを指定します。同じプロジェクトをEditorで開いたままの状態では、バッチモードで開けません。起動に失敗したときは、まず開いているEditorを閉じます。

Claude Codeに実行まで任せる場合は、Bash権限をこのコマンドに絞って許可します。Bash(.../Unity -batchmode *)のように、先頭の引数をそろえるのがコツです。照合の仕様と注意点はBash権限ルールの複合コマンド判定にまとめています。バッチモードの基本形はClaude CodeでUnityゲーム開発を進める手順で扱っています。

ステップ3: CSVをClaude Codeに読ませて分類する

CSVができたら、判断の部分をClaude Codeに任せます。非対話のclaude -pで、読み取りだけを許可して実行する形が使えます。公式ドキュメントでは、-pで非対話実行でき、--allowedToolsにReadを入れるとファイルの読み取りを確認なしで許可できます。

claude -p "audit/import-report.csv を CLAUDE.md の点検ルールと照らし、
違反を『容量に効くもの』『挙動に影響しうるもの』『要確認』に分けて、
パスと理由を一覧にして。修正はしない。" \
  --allowedTools "Read"

読ませるCSVは、たとえば次のような形になります(列の並びを示すための架空の2行です)。

kind,path,hasMeta,maxSize,compression,crunched,mipmap,srgb,readable,androidOverride,meshCompression,blendShapes,cameras,lights
texture,"Assets/Art/UI/icon_menu.png",True,4096,Compressed,False,True,True,True,False,,,,
model,"Assets/Art/Props/crate.fbx",True,,,,,,True,,Off,True,True,False

1行目のテクスチャは、Assets/Art/UI配下なのにmaxSizeが4096でmipmapが有効、readableもtrueです。先ほどのルールに照らすと3項目が違反になります。2行目のFBXはreadableがtrueで、カメラも取り込まれています。このように、1行の中で複数の違反が重なることがあるので、依頼文には「1アセットにつき違反をすべて列挙する」と添えておきます。

行数が多いCSVは、パスの接頭辞で分割して渡します。標準入力に流す場合の上限はclaude -pにログを渡すときの10MB上限にまとめています。ファイルパスで渡せば、この上限を避けられます。

分類の観点は、CLAUDE.mdで固定しておくのが安全です。「容量に効くもの」はmaxTextureSizeや無圧縮、「挙動に影響しうるもの」はsRGBTextureの取り違えやimportBlendShapesなどです。後者は、直した結果が見た目に出るので、人が確認する対象に回します。

ステップ4: 修正は別メソッドに分け、dry-runを先にする

点検と修正を同じメソッドに混ぜると、点検のたびにアセットが書き換わり、差分が追えなくなります。修正用のメソッドを別に作り、既定は「何を変えるかをログに出すだけ」にします。

ImportFix.Run を別に作って。-fixApply true が付いたときだけ SaveAndReimport を呼ぶ。
付かないときは、変更予定の path / プロパティ / 変更前 / 変更後をログに出すだけにして。

生成される実装の骨格は次のとおりです。isReadableをfalseに戻す例です。

public static void Run()
{
    bool apply = Array.IndexOf(Environment.GetCommandLineArgs(), "-fixApply") >= 0;
    foreach (string guid in AssetDatabase.FindAssets("t:Texture2D", new[] { "Assets/Art/UI" }))
    {
        string path = AssetDatabase.GUIDToAssetPath(guid);
        var t = AssetImporter.GetAtPath(path) as TextureImporter;
        if (t == null || !t.isReadable) continue;
        UnityEngine.Debug.Log($"{path}: isReadable true -> false");
        if (!apply) continue;
        t.isReadable = false;
        t.SaveAndReimport();
    }
    EditorApplication.Exit(0);
}

対象フォルダを定数で固定しているので、点検で絞った範囲の外には触れません。ログの行を点検CSVと突き合わせれば、変更予定が意図どおりかを実行前に確かめられます。

AssetImporter.SaveAndReimportは、インポーターに変更があるときだけ保存して再インポートします。変更後は.metaが書き換わるので、Gitの差分でどの設定が変わったかを一覧できます。.metaをアセット本体と別のコミットにすると、片方だけが戻ったときに参照が壊れます。マニュアルが、.metaを失うと参照が壊れると警告しているためです。

修正後は、もう一度ImportAudit.Runを回してCSVを作り直し、違反の行が消えたことを確かめます。点検と修正で同じ列名を使っているので、前後のCSVを比べるだけで効果を確認できます。

再インポートには時間がかかります。まず-auditRootでAssets/Art/UIのような狭い範囲に絞り、差分と見た目を確かめてから範囲を広げると安全です。

よくあるつまずき

  • メソッドが見つからない: スクリプトがEditorフォルダの外にあるか、メソッドがstaticでない可能性があります。名前空間付きなら-executeMethod Namespace.Class.Methodと書きます。
  • CSVが空になる: AssetDatabase.FindAssetsの第2引数に渡すフォルダがAssetsで始まっていない可能性があります。-auditRootのパスを確かめます。
  • 終了コードが0なのに結果が少ない: 例外が無いだけで、条件に合うアセットが無かった場合です。CSVの行数を最後にログへ出すよう、スクリプトに足しておくと切り分けが早くなります。
  • .metaを持たないアセットが混ざる: importSettingsMissingがtrueの行は、初回インポート前の可能性があります。コミット前に.metaが揃っているか確認します。
  • 修正後に点検CSVの値が変わらない: ImportFixを-fixApplyなしで回していないか、SaveAndReimportの前にプロパティを変えていない可能性があります。ログの「変更予定」行と-fixApplyの有無を見直します。
  • 同じプロジェクトを別のEditorが開いている: バッチモードは同じプロジェクトを同時に開けません。

Editor上でシーンやアセットを直接触りたい局面では、Unity公式MCPサーバーをClaude Codeにつなぐ方法のほうが向きます。一括の棚卸しは、バッチ実行のほうが再現しやすい作業です。

まとめ

.metaをClaudeに読ませるより、Importer APIで読むEditorスクリプトを書かせ、CSVに出すほうが確かめやすく、再実行もできます。点検と修正を別メソッドに分け、修正はdry-runから始めると、差分を追えます。基準値はCLAUDE.mdの1か所に置き、点検のたびに同じ物差しで回せます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/headless
  2. docs.unity3d.com/6000.0/Documentation/Manual/AssetMetadata.html
  3. docs.unity3d.com/6000.0/Documentation/Manual/EditorCommandLineArguments.html
  4. docs.unity3d.com/6000.0/Documentation/ScriptReference/TextureImporter.html
  5. docs.unity3d.com/6000.0/Documentation/ScriptReference/ModelImporter.html
この記事を共有:XはてブLinkedIn