Files
5.24BuYu/Assets/Framework/Tool/Sprite/Editor/AtlasAutoSplitter.cs
T
2026-05-22 19:30:02 +08:00

155 lines
4.2 KiB
C#

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class AtlasAutoSplitter : EditorWindow
{
Texture2D sourceTexture;
Color32[] pixels;
int width, height;
bool[,] visited;
[MenuItem("Tools/Atlas Auto Splitter")]
static void Open()
{
GetWindow<AtlasAutoSplitter>("Atlas Splitter");
}
void OnGUI()
{
sourceTexture = (Texture2D)EditorGUILayout.ObjectField("图集 Texture2D", sourceTexture, typeof(Texture2D), false);
if (sourceTexture == null)
return;
if (GUILayout.Button("开始自动分割"))
{
SplitAtlas();
}
}
void SplitAtlas()
{
string path = AssetDatabase.GetAssetPath(sourceTexture);
TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
if (importer == null)
{
Debug.LogError("无法获取 TextureImporter");
return;
}
// 强制读取像素
importer.isReadable = true;
// 如果不是 Multiple,自动改
if (importer.spriteImportMode != SpriteImportMode.Multiple)
{
importer.spriteImportMode = SpriteImportMode.Multiple;
}
// 应用修改并重新加载
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
sourceTexture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
width = sourceTexture.width;
height = sourceTexture.height;
pixels = sourceTexture.GetPixels32();
visited = new bool[width, height];
List<SpriteMetaData> metas = new List<SpriteMetaData>();
for (int y = height - 1; y >= 0; y--)
{
for (int x = 0; x < width; x++)
{
if (visited[x, y])
continue;
if (!IsSolidPixel(x, y))
{
visited[x, y] = true;
continue;
}
// 找到一个区域,开始 FloodFill
Rect rect = FloodFill(x, y);
SpriteMetaData meta = new SpriteMetaData();
meta.name = $"sprite_{metas.Count}";
// 修正坐标系:Unity 的 rect 原点在左下角
meta.rect = new Rect(rect.x, height - rect.y - rect.height, rect.width, rect.height);
meta.pivot = new Vector2(0.5f, 0.5f);
meta.alignment = (int)SpriteAlignment.Center; // 必须设置
metas.Add(meta);
}
}
importer.spritesheet = metas.ToArray();
// 确保写入并刷新
EditorUtility.SetDirty(importer);
AssetDatabase.WriteImportSettingsIfDirty(path);
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
AssetDatabase.Refresh();
Debug.Log($"分割完成,共生成 {metas.Count} 个 Sprite");
}
bool IsSolidPixel(int x, int y)
{
Color32 c = pixels[y * width + x];
return c.a > 10; // 透明度阈值
}
Rect FloodFill(int startX, int startY)
{
Queue<Vector2Int> q = new Queue<Vector2Int>();
q.Enqueue(new Vector2Int(startX, startY));
int minX = startX, maxX = startX;
int minY = startY, maxY = startY;
visited[startX, startY] = true;
while (q.Count > 0)
{
Vector2Int p = q.Dequeue();
int x = p.x;
int y = p.y;
// 更新边界
if (x < minX) minX = x;
if (x > maxX) maxX = x;
if (y < minY) minY = y;
if (y > maxY) maxY = y;
// 四方向扩散
TryAdd(x + 1, y, q);
TryAdd(x - 1, y, q);
TryAdd(x, y + 1, q);
TryAdd(x, y - 1, q);
}
// 注意 Unity 的 rect 是左下角为原点
return new Rect(minX, minY, maxX - minX + 1, maxY - minY + 1);
}
void TryAdd(int x, int y, Queue<Vector2Int> q)
{
if (x < 0 || x >= width || y < 0 || y >= height)
return;
if (visited[x, y])
return;
visited[x, y] = true;
if (!IsSolidPixel(x, y))
return;
q.Enqueue(new Vector2Int(x, y));
}
}