155 lines
4.2 KiB
C#
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));
|
||
|
|
}
|
||
|
|
}
|