PSDデータで作成したイラストなどの階層構造を維持したままPrefab化し、
レイヤーごとに個別PNG画像として一括出力する方法を解説します。
Unity 2DでPSDデータを階層保持のままPrefabとPNGへ一括出力する手順
Unity標準のインポート機能とエディタ拡張を組み合わせることで、手動での書き出しや配置の手間を省けます。
PSDファイルの準備
テスト用としてsample.psdを用意します。
入れ子のレイヤーグループや日本語名を使う場合も、出力後に階層と表示を比較します。描画モードや調整レイヤーなど、Photoshopの合成結果を完全には再現できない要素があります。
編集用のPSD原稿を別に残し、Unityへ渡す複製でシェイプやスマートオブジェクトなどをラスタライズします。元の編集情報を失わないよう、原稿へ上書きしないでください。

Unityプロジェクトの準備とフォルダ構成
Unityプロジェクトを2Dテンプレートで作成し、Package Managerで2D PSD Importerと2D Animationの導入を確認します。元記事にはパッケージのバージョン記録がないため、使用中の版のマニュアルも確認してください。
Assets配下に以下の作業フォルダを作成します。
| 親フォルダ | 子フォルダ | 用途 |
|---|---|---|
| Assets | Editor | エディタ拡張スクリプト(C#)を格納 |
| Prefabs | 生成されたPrefabおよびPNG画像の出力先 | |
| PSD | インポート対象のPSDファイルを配置 |
作成したPSDフォルダへsample.psdを配置します。
PSDインポート設定の変更
配置したsample.psdを選択し、Inspectorウィンドウでインポーターを
UnityEditor.TextureImporter (Default)からUnityEditor.U2D.PSD.PSDImporterへ切り替えます。

Texture TypeをSprite (2D and UI)、Sprite ModeをMultiple、Import ModeをIndividual Sprites (Mosaic)にします。Character RigのUse as Rigを有効にして階層付きPrefabを生成し、次のレイヤー設定を確認します。名称はパッケージの版により異なります。設定後はApplyを押してください。

Layer Import設定
- Include Hidden Layers:必要な場合のみ有効にする。非表示レイヤーも取り込むため、Photoshopで表示していた合成結果とは見え方が変わり得る
- Use Layer Group(またはLayer GroupのAs Per Source File):レイヤーグループの階層構造を保持する
インポート設定をPreset(PSDImporter.preset)として保存し、Preset Managerのデフォルトに登録しておくと、PSD配置時の自動適用が可能です。

PrefabおよびPNG画像の一括出力手順
Projectウィンドウで対象のsample.psdを選択します。
右クリックメニューから出力スクリプトを実行します。

Prefabsフォルダ内に実行ごとの専用フォルダが作成され、Prefabと連番付きのレイヤー別PNG画像が書き出されます。同名レイヤーや再実行による上書きを避ける構成です。

以上で一括出力の基本フローは完了です。
以下は元記事のコードを修正した2つのエディタ拡張です。骨・ウェイトやアニメーション参照の移行は対象外です。静止したSpriteRendererの階層で試し、色・透明部分・重なり順・サイズ・基準点を比較してください。
- PsdOverridePostprocessor.cs(選択したPSDのImporterをメニューからPSDImporterへ切り替え)
- PsdToPrefabExporter.cs(PSDの階層構造を保持したままPrefabとPNG画像を一括生成)
Unity関連の関連記事は一覧まとめから確認できます。

uGUIへ変換する方法については以下の記事を参照してください。

PsdOverridePostprocessor.cs
Assets/Editorフォルダに以下のスクリプトを配置します。
PSDを選択し、Assets → BG → PSD Importerに切り替えを実行します。Inspectorで手動切り替え済みなら、この補助スクリプトは不要です。旧版のOnPreprocessTextureによる自動切り替えコードは削除してから置き換えてください。
// Assets/Editor/PsdOverridePostprocessor.cs
using UnityEditor;
using UnityEditor.U2D.PSD;
using System;
using System.IO;
public static class PsdOverridePostprocessor
{
[MenuItem("Assets/BG/PSD Importerに切り替え")]
private static void SwitchSelected()
{
foreach (var asset in Selection.objects)
{
string path = AssetDatabase.GetAssetPath(asset);
if (!string.Equals(Path.GetExtension(path), ".psd",
StringComparison.OrdinalIgnoreCase)) continue;
if (AssetImporter.GetAtPath(path) is PSDImporter) continue;
AssetDatabase.SetImporterOverride<PSDImporter>(path);
}
}
}
PsdToPrefabExporter.cs
こちらも同様にAssets/Editorフォルダへ配置します。
ProjectウィンドウでPSDファイルを右クリックし、コンテキストメニューから実行コマンドを選択します。

// Assets/Editor/PsdToPrefabExporter.cs
using UnityEditor;
using UnityEngine;
using System.IO;
using System.Linq;
public static class PsdToPrefabExporter
{
/// <summary>
/// 選択 PSD → Prefab+PNG 一括変換
/// </summary>
[MenuItem("Assets/BG/PSD → Prefab+PNG (階層保持)", false, 30)]
private static void ConvertSelectedPsd()
{
foreach (var psd in Selection.objects)
{
string psdPath = AssetDatabase.GetAssetPath(psd);
if (Path.GetExtension(psdPath).ToLower() != ".psd") continue;
// ---------- ① 出力ディレクトリ ----------
string prefabRoot = "Assets/Prefabs";
string dir = prefabRoot + "/Export_" + System.Guid.NewGuid().ToString("N");
Directory.CreateDirectory(dir);
AssetDatabase.Refresh();
// ---------- ② PSDImporter が生成した階層付き GO ----------
var rootGo = AssetDatabase.LoadAllAssetsAtPath(psdPath)
.OfType<GameObject>()
.FirstOrDefault();
if (rootGo == null)
{
Debug.LogWarning($"Sprite のルートが見つかりません : {psdPath}");
continue;
}
// ---------- ③ 一時インスタンス化 ----------
var instance = (GameObject)PrefabUtility.InstantiatePrefab(rootGo);
try
{
PrefabUtility.UnpackPrefabInstance(instance, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
int index = 0;
// ---------- ④ PNG 書き出し&置換 ----------
foreach (var sr in instance.GetComponentsInChildren<SpriteRenderer>(true))
{
if (sr.sprite == null) continue;
var sprite = sr.sprite;
// ④‑A: PNG 出力
string pngPath = dir + $"/layer_{index++:D4}.png";
SaveSpriteAsPng(sprite, pngPath);
// ④‑B: インポート設定を Sprite に
SetPngAsSprite(pngPath, sprite);
// ④‑C: SpriteRenderer が参照先を差し替え
var replacement = AssetDatabase.LoadAssetAtPath<Sprite>(pngPath);
if (replacement == null) throw new System.InvalidOperationException("PNGをSpriteとして読み込めません: " + pngPath);
sr.sprite = replacement;
}
if (index == 0)
throw new System.InvalidOperationException("出力できるSpriteがありません。Layer Managementの取り込み対象とUse as Rigを確認してください");
// ---------- ⑤ Prefab 保存 ----------
string prefabPath = dir + "/export.prefab";
if (PrefabUtility.SaveAsPrefabAsset(instance, prefabPath) == null)
throw new System.InvalidOperationException("Prefabの保存に失敗しました");
// ---------- ⑥ 後片付け ----------
// 一時オブジェクトはfinallyで破棄します。
AssetDatabase.Refresh();
Debug.Log($"{psd.name} 変換完了 → {prefabPath}");
}
catch (System.Exception ex)
{
Debug.LogError($"変換失敗: {psdPath}\n途中の出力: {dir}\n{ex}");
}
finally
{
if (instance != null) Object.DestroyImmediate(instance);
}
}
}
// .psd が選択されていないとメニューを無効化
[MenuItem("Assets/BG/PSD → Prefab+PNG (階層保持)", true)]
private static bool Validate() =>
Selection.objects.Any(o => Path.GetExtension(AssetDatabase.GetAssetPath(o)).ToLower() == ".psd");
// ---------- Utility ----------
/// <summary>Sprite 部分だけ切り取って PNG 書き出し</summary>
private static void SaveSpriteAsPng(Sprite sprite, string pngPath)
{
if (sprite.packed) throw new System.NotSupportedException("AtlasにパックされたSpriteは対象外です");
int w = (int)sprite.rect.width;
int h = (int)sprite.rect.height;
int x = (int)sprite.rect.x;
int y = (int)sprite.rect.y;
if (w <= 0 || h <= 0) throw new System.InvalidOperationException("Spriteの寸法が不正です");
var prev = RenderTexture.active;
bool previousSrgbWrite = GL.sRGBWrite;
RenderTexture rt = null;
Texture2D tex = null;
try
{
rt = RenderTexture.GetTemporary(sprite.texture.width, sprite.texture.height,
0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
GL.sRGBWrite = QualitySettings.activeColorSpace == ColorSpace.Linear;
Graphics.Blit(sprite.texture, rt);
RenderTexture.active = rt;
tex = new Texture2D(w, h, TextureFormat.RGBA32, false, false);
tex.ReadPixels(new Rect(x, y, w, h), 0, 0);
tex.Apply();
File.WriteAllBytes(pngPath, ImageConversion.EncodeToPNG(tex));
}
finally
{
RenderTexture.active = prev;
GL.sRGBWrite = previousSrgbWrite;
if (rt != null) RenderTexture.ReleaseTemporary(rt);
if (tex != null) Object.DestroyImmediate(tex);
}
}
/// <summary>PNG を Sprite として再インポート</summary>
private static void SetPngAsSprite(string path, Sprite source)
{
AssetDatabase.ImportAsset(path);
if (AssetImporter.GetAtPath(path) is TextureImporter ti)
{
ti.textureType = TextureImporterType.Sprite;
ti.spriteImportMode = SpriteImportMode.Single;
ti.spritePixelsPerUnit = source.pixelsPerUnit;
ti.sRGBTexture = true;
ti.mipmapEnabled = false;
ti.npotScale = TextureImporterNPOTScale.None;
ti.maxTextureSize = 16384;
var settings = new TextureImporterSettings();
ti.ReadTextureSettings(settings);
settings.spriteAlignment = (int)SpriteAlignment.Custom;
settings.spritePivot = new Vector2(source.pivot.x / source.rect.width,
source.pivot.y / source.rect.height);
ti.SetTextureSettings(settings);
ti.alphaIsTransparency = true;
ti.textureCompression = TextureImporterCompression.Uncompressed;
ti.isReadable = false;
ti.SaveAndReimport();
}
}
}
処理が完了すると、Prefabsフォルダ配下に実行ごとの専用フォルダが生成され、Prefabとレイヤー別PNG画像が出力されます。

出力後は元Prefabと並べ、Pixels Per Unitが100以外の場合や中央以外のPivotも含めて確認します。Gamma/Linear、透明部分、プラットフォーム別のテクスチャ上書き設定による縮小も比較してください。Spriteが割り当てられたSpriteRendererを1件も処理できない場合は、Prefab保存前にエラーで止めます。失敗時は専用フォルダに途中の出力が残ります。Consoleのエラーを確認し、完成したPrefabとして扱わないでください。
仕様の参照先:PSD Importerの設定、PSDのImporter切り替え、Sprite.pivot、Sprite.pixelsPerUnit。
元記事のコードは、GitHubのMOTOKI-LLC/cg-method-codeにもあります。この記事の修正版との同期は未確認なので、差分を確認して利用してください。
2Dとスプライトの記事は、ほかにもあります。



よくある質問:PSDを階層保持でPrefabとPNGに一括出力する
この記事では、何ができますか?
PSDデータで作成したイラストなどの階層構造を維持したままPrefab化し、レイヤーごとに個別PNG画像として一括出力します。Unity標準のインポート機能とエディタ拡張を組み合わせることで、手動での書き出しや配置の手間を省けます。
どのバージョンで確認していますか?
元記事の検証環境はUnity 6.1です。今回の修正版コードは、Unityでのコンパイル・出力比較をまだ行っていません。お使いのバージョンでの最新の手順は、Unityの公式マニュアルで確認してください。
PSDは、どう準備しますか?
テスト用にsample.psdを用意しています。入れ子のレイヤーグループや日本語名を使う場合も、出力後に階層と表示を比較します。描画モードや調整レイヤーなど、Photoshopの合成結果を完全には再現できない要素があります。シェイプやスマートオブジェクトなどは、インポート時の崩れを防ぐため、事前にPhotoshop側でラスタライズしておきます。
Unityプロジェクトのフォルダ構成は?
Assets配下に、エディタ拡張スクリプト(C#)を格納するEditor、生成されたPrefabおよびPNG画像の出力先であるPrefabs、インポート対象のPSDファイルを配置するPSDの各フォルダを作成します。
PSDインポート設定では、何を変更しますか?
配置したsample.psdを選択し、Inspectorウィンドウでインポーターを切り替えます。Multiple、Individual Sprites (Mosaic)、Use as Rigと階層保持の設定を確認し、Applyを押します。Include Hidden Layersは非表示レイヤーも必要な場合だけ有効にします。
2つのスクリプトは、それぞれ何をしますか?
PsdOverridePostprocessor.csは、選択したPSDのImporterをメニュー操作でPSDImporterへ切り替えます。PsdToPrefabExporter.csは、PSDの階層構造を保持したままPrefabとPNG画像を一括生成します。どちらもAssets/Editorフォルダへ配置します。
どうやって一括出力しますか?
ProjectウィンドウでPSDファイル(sample.psd)を右クリックし、コンテキストメニューから実行コマンドを選択します。処理が完了すると、Prefabsフォルダ配下に実行ごとの専用フォルダが生成され、Prefabとレイヤー別PNG画像が出力されます。修正版はインポーターが生成した階層・Transformを複製し、元SpriteのPixels Per UnitとPivotをPNG側に引き継ぎます。元のPSDと同じ見た目になるかは出力後に比較してください。
コードはどこで確認できますか?
修正版はこの記事内に掲載しています。GitHubのMOTOKI-LLC/cg-method-codeは元記事の参照先で、今回の修正との同期は未確認です。処理内容は、プロジェクトの仕様に合わせて調整してください。
