当前位置:网站首页>Unity drawing plug-in = = [support the update of the original atlas]
Unity drawing plug-in = = [support the update of the original atlas]
2022-07-07 15:53:00 【Le_ Sam】
Preface :
Project needs ,1. It needs to be provided to the art collection tool ,2. Atlas update function , So that the subgraphs in the new atlas do not have to be dragged and positioned again
Solutions :
1.unity Call external TexturePacker The command line tool executes the composite ,unity according to TP The generated data cuts out multiple pieces of the atlas sprite
2. When dragging and positioning subgraphs in the atlas , Corresponding GUID And FileID. Therefore, the new atlas updates the corresponding GUID And FileID that will do , however API No corresponding interface found , So start with the resource itself txt Mode on , Force the replacement of the corresponding ID
Reference documents :
https://www.xuanyusong.com/archives/4207
effect :
Source code :
The following three files , Placed in the project Assets\Editor that will do
using System;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
using System.Text;
using System.Diagnostics;
using System.Linq;
using System.Xml;
using System.Collections;
using LuaFramework;
public class TexturePackerBuild : Editor
{
private const string BuildDir = "Assets/TexturePacker/ Package the atlas ";
/// <summary>
/// TexturePacker.exe ###https://www.codeandweb.com/texturepacker/documentation/texture-settings
/// </summary>
private const string Paramet = " --sheet {0}.png --data {1}.xml --format sparrow --trim-mode CropKeepPos --pack-mode Best --algorithm MaxRects --max-size 4096 --size-constraints POT --disable-rotation {2}";
/// <summary>
/// The output directory
/// </summary>
private const string OutPutDirRoot = "Assets/TPSpriteBuild/";
private static string tpDir = "";
private static string argument = "";
[MenuItem(BuildDir, false)]
public static void BuildOneTP()
{
if (Directory.Exists(OutPutDirRoot) == false)
{
Directory.CreateDirectory(OutPutDirRoot);
}
var assetPaths = Selection.assetGUIDs.Select(AssetDatabase.GUIDToAssetPath).ToList();
List<string> filePathList = new List<string>();
foreach (var assetPath in assetPaths)
{
if (AssetDatabase.IsValidFolder(assetPath))
{
string[] filesPath = Directory.GetFiles(assetPath);
foreach (var filePath in filesPath)
{
if (filePathList.Contains(filePath) == false)
{
filePathList.Add(filePath);
}
else
{
UnityEngine.Debug.LogErrorFormat(" Same file detected {0}", assetPath);
}
}
}
else
{
filePathList.Add(assetPath);
}
}
Dictionary<string, FileData> fileDic = new Dictionary<string, FileData>();
foreach (var path in filePathList)
{
var dir = Path.GetFileName(Path.GetDirectoryName(path));
var fileName = Path.GetFileName(path);
UnityEngine.Debug.LogFormat("_TP dirName {0} _TP fileName {1} _TP fullPath {2}", dir, fileName, path);
if (fileDic.ContainsKey(dir) == false)
{
FileData fileData = new FileData();
fileData.filesList = new List<string>();
fileDic[dir] = fileData;
fileDic[dir].dirName = dir;
}
fileDic[dir].filesList.Add(path);
}
foreach (var data in fileDic)
{
TexturePackerBuild tpBuild = new TexturePackerBuild();
tpBuild.Build(data.Value);
}
}
public void Build(FileData data)
{
StringBuilder sb = new StringBuilder("");
GetImageName(data.filesList, ref sb);
string sheetName = OutPutDirRoot + data.dirName;
argument = string.Format(Paramet, sheetName, sheetName, sb.ToString());
tpDir = PlayerPrefs.GetString("_TPInstallDir", "");
RunExternalApp(tpDir, argument);
}
private StringBuilder GetImageName(List<string> fileName, ref StringBuilder sb)
{
foreach (var file in fileName)
{
string extenstion = Path.GetExtension(file);
if (extenstion == ".png")
{
sb.Append(file);
sb.Append(" ");
}
}
return sb;
}
private void RunExternalApp(string command, string argument)
{
UnityEngine.Debug.Log("TPSprite Recover");
ClearOtherFiles();
ProcessStartInfo start = new ProcessStartInfo(command);
start.Arguments = argument;
start.CreateNoWindow = false;
start.ErrorDialog = true;
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.RedirectStandardInput = true;
start.StandardOutputEncoding = System.Text.UTF8Encoding.UTF8;
start.StandardErrorEncoding = System.Text.UTF8Encoding.UTF8;
try
{
Process p = Process.Start(start);
p.WaitForExit();
p.Close();
AssetDatabase.Refresh();
bool isNullFile; // Judge whether the file in the output directory is empty
string outPngPath;
BuildTexturePacker(out isNullFile,out outPngPath);
if (isNullFile == false)
{
tpDir = command;
PlayerPrefs.SetString("_TPInstallDir", command);
SelectAtlasUpdataWindow(outPngPath);
}
else
{
// The output file is empty , guess exe Incorrect use , Re import exe
OnError(" No pictures were detected in the output directory , Please re import ");
}
}
catch (Exception ex)
{
OnError(ex.Message);
}
}
/// <summary>
/// Clean up the original image under the output directory
/// </summary>
private void ClearOtherFiles()
{
string[] fileName = Directory.GetFiles(OutPutDirRoot);
if (fileName != null && fileName.Length > 0)
{
for (int i = 0; i < fileName.Length; i++)
{
string extenstion = Path.GetExtension(fileName[i]);
if (extenstion == ".png" || extenstion == ".xml")
{
File.Delete(fileName[i]);
}
}
}
}
/// <summary>
/// establish Texture
/// </summary>
/// <param name="isNull"></param>
/// <param name="outPngPath"></param>
public void BuildTexturePacker(out bool isNull, out string outPngPath)
{
isNull = true;
outPngPath = "";
string[] imagePath = Directory.GetFiles(OutPutDirRoot);
foreach (string path in imagePath)
{
if (Path.GetExtension(path) == ".png" || Path.GetExtension(path) == ".PNG")
{
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
string rootPath = OutPutDirRoot + texture.name;
string pngPath = rootPath + "/" + texture.name + "_" + DateTime.Now.ToString("hh_mm_ss") + ".png";
outPngPath = pngPath;
isNull = false;
if (Directory.Exists(rootPath) == false)
{
Directory.CreateDirectory(rootPath);
}
File.Copy(OutPutDirRoot + texture.name + ".png", pngPath);
AssetDatabase.Refresh();
FileStream fs = new FileStream(OutPutDirRoot + texture.name + ".xml", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string jText = sr.ReadToEnd();
fs.Close();
sr.Close();
WriteMeta(jText, pngPath);
}
}
ClearOtherFiles();
AssetDatabase.Refresh();
}
void SelectAtlasUpdataWindow(string pngPath)
{
TPSelectFileWindow win = new TPSelectFileWindow();
win.Popup(pngPath, UpdataAssetRes);
}
void UpdataAssetRes(string opPath, Texture pendingTex)
{
var srcObj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(opPath);
TPFindReplaceRes tpFindRep = new TPFindReplaceRes();
tpFindRep.OnTPReplaceAssetData(pendingTex, srcObj);
}
// Write a message to SpritesSheet in
void WriteMeta(string jText, string path)
{
UnityEngine.Debug.Log("WriteMeta " + path);
XmlDocument xml = new XmlDocument();
xml.LoadXml(jText);
XmlNodeList elemList = xml.GetElementsByTagName("SubTexture");
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
string impPath = AssetDatabase.GetAssetPath(texture);
TextureImporter asetImp = TextureImporter.GetAtPath(impPath) as TextureImporter;
SpriteMetaData[] metaData = new SpriteMetaData[elemList.Count];
for (int i = 0, size = elemList.Count; i < size; i++)
{
XmlElement node = (XmlElement)elemList.Item(i);
Rect rect = new Rect();
rect.x = int.Parse(node.GetAttribute("x"));
rect.y = texture.height - int.Parse(node.GetAttribute("y")) - int.Parse(node.GetAttribute("height"));
rect.width = int.Parse(node.GetAttribute("width"));
rect.height = int.Parse(node.GetAttribute("height"));
metaData[i].rect = rect;
metaData[i].pivot = new Vector2(0.5f, 0.5f);
metaData[i].name = node.GetAttribute("name");
}
asetImp.spritesheet = metaData;
asetImp.textureType = TextureImporterType.Sprite;
asetImp.spriteImportMode = SpriteImportMode.Multiple;
asetImp.mipmapEnabled = false;
asetImp.SaveAndReimport();
}
private string OpenTPEXE()
{
string path = EditorUtility.OpenFilePanel(" Please locate TexturePacker.exe Program , For subsequent operations ", "", "exe");
return path;
}
private void OnError(string err)
{
UnityEngine.Debug.LogError("TPBuild Err:" + err);
EditorUtility.DisplayDialog(" Please reposition TexturePacker.exe Program !", "Err:" + err, " determine ");
var path = OpenTPEXE();
if (path.Length != 0)
{
RunExternalApp(path, argument);
}
}
public class FileData
{
public string dirName;
public List<string> filesList;
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
/// <summary>
/// Editor main interface
/// </summary>
public class TPSelectFileWindow : EditorWindow {
private Action<string, Texture> _callBack;
private string _opPath;
private Texture _selectTex;
public void Popup(string opPath, Action<string, Texture> cb)
{
_callBack = cb;
_opPath = opPath;
var isSeek = EditorUtility.DisplayDialog(" Waiting for execution ...", " Whether to update the original atlas , Currently, only a single atlas can be updated ", " determine ", " Cancel ");
if (isSeek == true)
{
TPSelectFileWindow window = EditorWindow.GetWindow(typeof(TPSelectFileWindow), true, " Waiting for execution ...") as TPSelectFileWindow;
window.minSize = new Vector2(450, 300);
window.Show();
}
else
{
if (_callBack != null)
{
_callBack.Invoke(_opPath, _selectTex);
}
_callBack = null;
}
}
private void OnGUI()
{
ShowEditorGUI();
}
private void ShowEditorGUI()
{
_selectTex = EditorGUILayout.ObjectField(" Add the original bound Texture", _selectTex, typeof(Texture), true) as Texture;
if (_selectTex != null && string.IsNullOrEmpty(_selectTex.name) == false)
{
EditorGUILayout.TextField(AssetDatabase.GetAssetOrScenePath(_selectTex));
}
if (GUILayout.Button(" Close the window and continue "))
{
// close window
this.Close();
}
}
private void OnDestroy()
{
if (_callBack != null)
{
_callBack.Invoke(_opPath, _selectTex);
}
_callBack = null;
_selectTex = null;
}
}
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
using System.Collections;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
public class TPFindReplaceRes {
Dictionary<string, AssetData> assetDic;
string srcGUID;
string tarGUID;
/// <summary>
/// to update Asset data
/// </summary>
/// <param name="srcObj"> Retrieve the located OBJ, It can be discarded after operation </param>
/// <param name="tarObj"> Wait for the updated data to be clean OBJ</param>
public void OnTPReplaceAssetData(Object srcObj, Object tarObj) {
AssetDatabase.Refresh();
EditorSettings.serializationMode = SerializationMode.ForceText;
string srcPath = AssetDatabase.GetAssetPath(srcObj);
string tarPath = AssetDatabase.GetAssetPath(tarObj);
if (string.IsNullOrEmpty(tarPath) || string.IsNullOrEmpty(srcPath))
{
Debug.Log("srcObj = null || tarObj = null");
return;
}
Debug.LogFormat("srcPath:{0} , tarPath:{1}", srcPath, tarPath);
srcGUID = AssetDatabase.AssetPathToGUID(srcPath);
tarGUID = AssetDatabase.AssetPathToGUID(tarPath);
OnCreateMetaData(srcPath, tarPath);
var withoutExtensions = new List<string>() { ".prefab", ".unity", ".mat", ".asset" };
string[] files = Directory.GetFiles(Application.dataPath, "*.*", SearchOption.AllDirectories).Where(s => withoutExtensions.Contains(Path.GetExtension(s).ToLower())).ToArray();
int startIndex = 0;
EditorApplication.update = delegate () {
string file = files[startIndex];
bool isCancel = EditorUtility.DisplayCancelableProgressBar(" Matching resources ", file, (float)startIndex / (float)files.Length);
if (Regex.IsMatch(File.ReadAllText(file), srcGUID))
{
OnUpdateData(file);
var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(GetRelativeAssetsPath(file));
Debug.Log(" Replacement object " + file, obj);
}
startIndex++;
if (isCancel || startIndex >= files.Length)
{
EditorUtility.ClearProgressBar();
EditorApplication.update = null;
startIndex = 0;
Debug.Log(" End of data update ");
}
};
}
void OnCreateMetaData(string srcPath, string tarPath)
{
string srcMeta = AssetDatabase.GetTextMetaFilePathFromAssetPath(srcPath);
string tarMeta = AssetDatabase.GetTextMetaFilePathFromAssetPath(tarPath);
string[] srcFile = File.ReadAllLines(srcMeta);
string[] tarFile = File.ReadAllLines(tarMeta);
List<string> smList = new List<string>();
List<string> tempList = new List<string>();
TextureImporter srcImp = TextureImporter.GetAtPath(srcPath) as TextureImporter;
TextureImporter tarImp = TextureImporter.GetAtPath(tarPath) as TextureImporter;
foreach (var spMD in tarImp.spritesheet)
{
tempList.Add(spMD.name);
}
foreach (var spMD in srcImp.spritesheet)
{
if (tempList.Contains(spMD.name))
{
smList.Add(spMD.name);
//Debug.Log(" matching SpriteSheetMeta " + spMeta.name);
}
}
assetDic = new Dictionary<string, AssetData>();
foreach (var key in smList)
{
AssetData data = new AssetData();
data.name = key;
assetDic.Add(key, data);
foreach (var srcStr in srcFile)
{
if (srcStr.IndexOf(key) >= 0)
{
var str = srcStr.Trim();
var spMetaId = str.Substring(0, str.IndexOf(":"));
//Debug.LogFormat("src ==> {0} {1}", key, spMetaId);
if (string.IsNullOrEmpty(assetDic[key].src))
{
assetDic[key].src = spMetaId;
}
}
}
foreach (var tarStr in tarFile)
{
if (tarStr.IndexOf(key) >= 0)
{
var str = tarStr.Trim();
var spMetaId = str.Substring(0, str.IndexOf(":"));
//Debug.LogFormat("tar ==> {0} {1}", key, spMetaId);
if (string.IsNullOrEmpty(assetDic[key].tar))
{
assetDic[key].tar = spMetaId;
}
}
}
if (string.IsNullOrEmpty(assetDic[key].src) || string.IsNullOrEmpty(assetDic[key].tar))
{
assetDic.Remove(key);
}
}
//foreach (var meta in assetDic)
//{
// var data = meta.Value;
// Debug.LogFormat("meta ==> name:{0} src:{1} tar:{2}", data.name, data.src, data.tar);
//}
}
void OnUpdateData(string file)
{
var allInfo = File.ReadAllLines(file);
for (int i = 0; i < allInfo.Length; i++)
{
var str = allInfo[i];
if (str.IndexOf(srcGUID) >= 0)
{
if (str.IndexOf("guid") >= 0)
{
// Replace old GUID
str = str.Replace(srcGUID, tarGUID);
// Replace old fileID
if (str.IndexOf("fileID") >= 0)
{
foreach (var meta in assetDic)
{
if (str.IndexOf(meta.Value.src) >= 0)
{
str = str.Replace(meta.Value.src, meta.Value.tar);
}
}
}
}
allInfo[i] = str;
}
}
File.WriteAllLines(file, allInfo);
}
static string GetRelativeAssetsPath(string path) {
return "Assets" + Path.GetFullPath(path).Replace(Path.GetFullPath(Application.dataPath), "").Replace('\\', '/');
}
public class AssetData
{
public string name;
public string src;
public string tar;
}
}
边栏推荐
- numpy--数据清洗
- Limit of total fields [1000] in index has been exceeded
- 【微信小程序】Chapter(5):微信小程序基础API接口
- The "go to definition" in VS2010 does not respond or prompts the solution of "symbol not found"
- 神经网络c语言中的指针是怎么回事
- Vertex shader to slice shader procedure, varying variable
- Please supervise the 2022 plan
- L'application à l'échelle de la normalisation mature des produits ai des compagnies maritimes, cimc, leader mondial de l'intelligence artificielle portuaire et maritime / intelligence artificielle des
- unnamed prototyped parameters not allowed when body is present
- Nacos conformance protocol cp/ap/jraft/distro protocol
猜你喜欢
Async and await
JS array foreach source code parsing
讲师征集令 | Apache SeaTunnel(Incubating) Meetup 分享嘉宾火热招募中!
Annexb and avcc are two methods of data segmentation in decoding
Vertex shader to slice shader procedure, varying variable
The bank needs to build the middle office capability of the intelligent customer service module to drive the upgrade of the whole scene intelligent customer service
有钱人买房就是不一样
Webgl texture
Three. JS introductory learning notes 11:three JS group composite object
【数字IC验证快速入门】19、SystemVerilog学习之基本语法6(线程内部通信...内含实践练习)
随机推荐
Limit of total fields [1000] in index has been exceeded
融云斩获 2022 中国信创数字化办公门户卓越产品奖!
Points for attention in porting gd32 F4 series programs to gd32 F3 series
[quick start of Digital IC Verification] 24. AHB sramc of SystemVerilog project practice (4) (AHB continues to deepen)
Cut ffmpeg as needed, and use emscripten to compile and run
Webgl texture
无线传感器网络--ZigBee和6LoWPAN
webgl_ Enter the three-dimensional world (2)
Share the technical details of super signature system construction
Starting from 1.5, build a microservice framework link tracking traceid
A link opens the applet code. After compilation, it is easy to understand
15. Using the text editing tool VIM
Ue4/ue5 multi thread development attachment plug-in download address
Please supervise the 2022 plan
Zhongang Mining: Fluorite continues to lead the growth of new energy market
XMIND frame drawing tool
Syntaxhighlight highlights the right scroll bar
LeetCode2_ Add two numbers
L'application à l'échelle de la normalisation mature des produits ai des compagnies maritimes, cimc, leader mondial de l'intelligence artificielle portuaire et maritime / intelligence artificielle des
Three. JS introductory learning notes 19: how to import FBX static model