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,False1行目のテクスチャは、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か所に置き、点検のたびに同じ物差しで回せます。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。
- code.claude.com/docs/en/headless
- docs.unity3d.com/6000.0/Documentation/Manual/AssetMetadata.html
- docs.unity3d.com/6000.0/Documentation/Manual/EditorCommandLineArguments.html
- docs.unity3d.com/6000.0/Documentation/ScriptReference/TextureImporter.html
- docs.unity3d.com/6000.0/Documentation/ScriptReference/ModelImporter.html