PSDデータで作成したイラストなどの階層構造を維持したままPrefab化し、
レイヤーごとに個別PNG画像として一括出力する方法を解説します。
Unity 2DでPSDデータを階層保持のままPrefabとPNGへ一括出力する手順
Unity標準のインポート機能とエディタ拡張を組み合わせることで、手動での書き出しや配置の手間を省けます。
PSDファイルの準備
テスト用としてsample.psdを用意します。
レイヤーグループの入れ子や日本語のレイヤー名を含めた構成でも問題なく処理できます。
シェイプやスマートオブジェクトなどは、インポート時の崩れを防ぐため事前にPhotoshop側でラスタライズしておきます。

Unityプロジェクトの準備とフォルダ構成
Unityプロジェクトを2Dテンプレートで作成します。
Assets配下に以下の作業フォルダを作成します。
| 親フォルダ | 子フォルダ | 用途 |
|---|---|---|
| Assets | Editor | エディタ拡張スクリプト(C#)を格納 |
| Prefabs | 生成されたPrefabおよびPNG画像の出力先 | |
| PSD | インポート対象のPSDファイルを配置 |
作成したPSDフォルダへsample.psdを配置します。
PSDインポート設定の変更
配置したsample.psdを選択し、Inspectorウィンドウでインポーターを
UnityEditor.TextureImporter (Default)からUnityEditor.U2D.PSD.PSDImporterへ切り替えます。

Inspector内の各オプションで、以下の項目を有効にします。

Layer Import設定
- Include Hidden Layers:非表示レイヤーも含めて取り込む
- Use Layer Group:レイヤーグループの階層構造を保持する
インポート設定をPreset(PSDImporter.preset)として保存し、Preset Managerのデフォルトに登録しておくと、PSD配置時の自動適用が可能です。

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

Prefabsフォルダ内にPSD名と同名のフォルダが作成され、階層を再現したPrefabと各レイヤーのPNG画像が書き出されます。

以上で一括出力の基本フローは完了です。
今回使用した2つのエディタ拡張スクリプトを紹介します。
- PsdOverridePostprocessor.cs(PSDインポート時にImporterをPSDImporterへ自動切り替え)
- PsdToPrefabExporter.cs(PSDの階層構造を保持したままPrefabとPNG画像を一括生成)
Unity関連の関連記事は一覧まとめから確認できます。

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

PsdOverridePostprocessor.cs
Assets/Editorフォルダに以下のスクリプトを配置します。
プロジェクトにPSDファイルを追加した際、自動でインポーターがUnityEditor.U2D.PSD.PSDImporterへ適用されます。
// Assets/Editor/PsdOverridePostprocessor.cs
using UnityEditor;
using UnityEditor.U2D.PSD;
using System;
public class PsdOverridePostprocessor : AssetPostprocessor
{
// PSD を Texture として読み込む前に呼ばれる
void OnPreprocessTexture()
{
// assetPath は「Assets/.../サンプル.psd」のような文字列
if (assetPath.EndsWith(".psd", StringComparison.OrdinalIgnoreCase))
{
// 既に PSDImporter なら何もしない
if (AssetImporter.GetAtPath(assetPath) is PSDImporter) return;
// .psd を PSDImporter に差し替え
AssetDatabase.SetImporterOverride<PSDImporter>(assetPath);
}
}
}
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 = Path.Combine(prefabRoot, Path.GetFileNameWithoutExtension(psdPath));
Directory.CreateDirectory(dir);
// ---------- ② PSDImporter が生成した階層付き GO ----------
var rootGo = AssetDatabase.LoadAllAssetsAtPath(psdPath)
.OfType<GameObject>()
.FirstOrDefault();
if (rootGo == null)
{
Debug.LogWarning($"Sprite のルートが見つかりません : {psdPath}");
continue;
}
// ---------- ③ 一時インスタンス化 ----------
var instance = (GameObject)PrefabUtility.InstantiatePrefab(rootGo);
// ---------- ④ PNG 書き出し&置換 ----------
foreach (var sr in instance.GetComponentsInChildren<SpriteRenderer>(true))
{
if (sr.sprite == null) continue;
var sprite = sr.sprite;
// ④‑A: PNG 出力
string pngPath = Path.Combine(dir, $"{sprite.name}.png");
SaveSpriteAsPng(sprite, pngPath);
// ④‑B: インポート設定を Sprite に
SetPngAsSprite(pngPath);
// ④‑C: SpriteRenderer が参照先を差し替え
sr.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(pngPath);
}
// ---------- ⑤ Prefab 保存 ----------
string prefabPath = Path.Combine(dir, $"{rootGo.name}.prefab");
PrefabUtility.SaveAsPrefabAsset(instance, prefabPath);
// ---------- ⑥ 後片付け ----------
Object.DestroyImmediate(instance);
AssetDatabase.Refresh();
Debug.Log($"{psd.name} 変換完了 → {prefabPath}");
}
}
// .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)
{
int w = (int)sprite.rect.width;
int h = (int)sprite.rect.height;
int x = (int)sprite.rect.x;
int y = (int)sprite.rect.y;
// 圧縮フォーマットでも確実に取れる RenderTexture → ReadPixels 方式
var rt = RenderTexture.GetTemporary(sprite.texture.width,
sprite.texture.height,
0, RenderTextureFormat.ARGB32,
RenderTextureReadWrite.Linear);
Graphics.Blit(sprite.texture, rt);
var prev = RenderTexture.active;
RenderTexture.active = rt;
var tex = new Texture2D(w, h, TextureFormat.RGBA32, false);
tex.ReadPixels(new Rect(x, y, w, h), 0, 0);
tex.Apply();
RenderTexture.active = prev;
RenderTexture.ReleaseTemporary(rt);
File.WriteAllBytes(pngPath, ImageConversion.EncodeToPNG(tex));
}
/// <summary>PNG を Sprite として再インポート</summary>
private static void SetPngAsSprite(string path)
{
AssetDatabase.ImportAsset(path);
if (AssetImporter.GetAtPath(path) is TextureImporter ti)
{
ti.textureType = TextureImporterType.Sprite;
ti.spritePixelsPerUnit = 100;
ti.alphaIsTransparency = true;
ti.textureCompression = TextureImporterCompression.Uncompressed;
ti.isReadable = false;
ti.SaveAndReimport();
}
}
}
処理が完了すると、Prefabsフォルダ配下にPSD名のフォルダが生成され、Prefabとレイヤー別PNG画像が出力されます。

手順は以上となります。
この記事で紹介しているコードは、GitHubのMOTOKI-LLC/cg-method-codeにもまとめています。
2Dとスプライトの記事は、ほかにもあります。



