diff --git a/.tools/result_rot_scale/main.exe b/.tools/result_rot_scale/main.exe deleted file mode 100644 index 41ca888..0000000 Binary files a/.tools/result_rot_scale/main.exe and /dev/null differ diff --git a/.tools/result_rot_scale/start.bat b/.tools/result_rot_scale/start.bat deleted file mode 100644 index d481630..0000000 --- a/.tools/result_rot_scale/start.bat +++ /dev/null @@ -1,3 +0,0 @@ -call main.exe -src image -target image_2 -distance_difference 0.06 - -pause \ No newline at end of file diff --git a/Assets/Editor/Entity/IEntity.cs b/Assets/Editor/Entity/IEntity.cs index 95ef9fe..3abd2e7 100644 --- a/Assets/Editor/Entity/IEntity.cs +++ b/Assets/Editor/Entity/IEntity.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR +using Sirenix.OdinInspector; using System; using Unity.Mathematics; using UnityEngine; @@ -8,8 +9,10 @@ namespace UguiToolkit.Editor { public interface IEntity { + void SetOriginalMatrix(Transform tf); void ApplyTransform(Transform tf); - void ApplyTransformByParent(Transform parentTf); + void InternalApplyTransform(Transform tf); + void ApplyTransformByParent(Transform parentTf, Transform tf); bool IsInside(Transform tf); void ApplyData(T ui) where T: Component; void InitPreview(); @@ -23,6 +26,8 @@ namespace UguiToolkit.Editor // ElementInfo private T2 m_elementInfo; private UnityEngine.UI.Image m_selectionImg; + private Matrix4x4 lastMoveMatrix; + private Matrix4x4 oldTransformMatrix; public T2 ElementInfo => m_elementInfo; public void ShowSelectionImg(bool show) @@ -33,13 +38,45 @@ namespace UguiToolkit.Editor } } - - public abstract void ApplyTransform(Transform tf); public abstract void InitPreview(); + protected abstract void OnApplyTransform(Transform tf); protected abstract void OnApplyData(T1 ui); - public virtual void ApplyTransformByParent(Transform parentTf) { } + public virtual void ApplyTransformByParent(Transform parentTf, Transform tf) + { + var position = lastMoveMatrix.GetColumn(3); // 提取位置 + var rotation = Quaternion.LookRotation(lastMoveMatrix.GetColumn(2), lastMoveMatrix.GetColumn(1)); // 提取旋转 + Debug.Log($"[I] ApplyTransformByParent {position}, {rotation.eulerAngles}"); + parentTf.position += new Vector3(position.x, position.y, position.z); + parentTf.rotation *= rotation; + if (tf) + { + var lastTransformMatrixInverse = lastMoveMatrix.inverse; + position = lastTransformMatrixInverse.GetColumn(3); // 提取位置 + rotation = Quaternion.LookRotation(lastTransformMatrixInverse.GetColumn(2), lastTransformMatrixInverse.GetColumn(1)); // 提取旋转 + tf.position += new Vector3(position.x, position.y, position.z); + tf.rotation *= rotation; + } + } + + public void SetOriginalMatrix(Transform tf) + { + oldTransformMatrix = Matrix4x4.TRS(tf.position, tf.rotation, tf.localScale); + } + + public void InternalApplyTransform(Transform tf) + { + OnApplyTransform(tf); + } + + public void ApplyTransform(Transform tf) + { + Debug.Log($"[I] ApplyTransform {tf.name}"); + OnApplyTransform(tf); + Matrix4x4 newTransformMatrix = Matrix4x4.TRS(tf.position, tf.rotation, tf.localScale); + lastMoveMatrix = newTransformMatrix * oldTransformMatrix.inverse; + } public bool IsInside(Transform tf) { @@ -74,7 +111,7 @@ namespace UguiToolkit.Editor rtf.sizeDelta = new Vector2(m_elementInfo.w, m_elementInfo.h); m_selectionImg = go.AddComponent(); - m_selectionImg.color = new Color(0, 1, 0, 0.3f); + m_selectionImg.color = new Color(0, 1, 0, 0.4f); } } } diff --git a/Assets/Editor/Entity/ImageEntity.cs b/Assets/Editor/Entity/ImageEntity.cs index 9bac622..57d3469 100644 --- a/Assets/Editor/Entity/ImageEntity.cs +++ b/Assets/Editor/Entity/ImageEntity.cs @@ -22,6 +22,7 @@ namespace UguiToolkit.Editor [ShowInInspector] private Matrix4x4 lastTransformMatrix; + private Image m_previewImage; // ʱ @@ -34,14 +35,6 @@ namespace UguiToolkit.Editor this.needFillTransform = true; } - public override void ApplyTransformByParent(Transform parentTf) - { - var position = lastTransformMatrix.GetColumn(3); // ȡλ - var rotation = Quaternion.LookRotation(lastTransformMatrix.GetColumn(2), lastTransformMatrix.GetColumn(1)); // ȡת - parentTf.position += new Vector3(position.x, position.y, position.z); - parentTf.rotation *= rotation; - } - private void LoadImageFromFile(string path) { if (System.IO.File.Exists(path)) @@ -83,14 +76,11 @@ namespace UguiToolkit.Editor } - public override void ApplyTransform(Transform tf) + protected override void OnApplyTransform(Transform tf) { var rt = tf as RectTransform; if (needFillTransform) { - Matrix4x4 oldTransformMatrix = Matrix4x4.TRS(tf.position, tf.rotation, tf.localScale); - - var pos = ElementInfo.Position; var worldPos = StageManager.Instance.PrefabContentsRoot.transform.TransformPoint(new Vector3(pos.x, pos.y, 0)); var anchorMin = rt.anchorMin; @@ -118,6 +108,7 @@ namespace UguiToolkit.Editor // С rt.anchorMin = rt.pivot; rt.anchorMax = rt.pivot; + var oldSizeDelta = rt.sizeDelta; rt.sizeDelta = new Vector2(size.x, size.y); rt.anchorMin = anchorMin; rt.anchorMax = anchorMax; @@ -131,10 +122,6 @@ namespace UguiToolkit.Editor rt.pivot = oldPiovt; var offsetRectPos = oldRect.position - rt.rect.position; rt.Translate(offsetRectPos); - - - Matrix4x4 newTransformMatrix = Matrix4x4.TRS(tf.position, tf.rotation, tf.localScale); - lastTransformMatrix = newTransformMatrix * oldTransformMatrix.inverse; } else { diff --git a/Assets/Editor/Entity/PrefabEntity.cs b/Assets/Editor/Entity/PrefabEntity.cs index bea328f..e3f8d03 100644 --- a/Assets/Editor/Entity/PrefabEntity.cs +++ b/Assets/Editor/Entity/PrefabEntity.cs @@ -13,7 +13,7 @@ namespace UguiToolkit.Editor { public class PrefabEntity : BaseEntity { - public override void ApplyTransform(Transform tf) + protected override void OnApplyTransform(Transform tf) { var position = ElementInfo.Position; tf.position = StageManager.Instance.PrefabContentsRoot.transform.TransformPoint(new Vector3(position.x, position.y, 0)); @@ -22,10 +22,9 @@ namespace UguiToolkit.Editor public override void InitPreview() { // Ԥ - var setting = GlobalManager.Instance.setting; - var asset = GetPrefabAsset(setting.commonPrefabForUIDirPath); - if (asset != null) { - var go = GameObject.Instantiate(asset, transform); + var asset = GetPrefabAsset(GetCommonDirPath()); + if (asset) { + var go = PrefabUtility.InstantiatePrefab(asset, transform) as GameObject; EntityHelper.UpdateHierarchyAndSceneVisibilityOfEntity(false, go); go.name = asset.name; @@ -43,12 +42,7 @@ namespace UguiToolkit.Editor ApplyTransform(ui); } - public GameObject CopyPrefabGo() - { - return null; - } - - private GameObject GetPrefabAsset(string commonDirPath) + public GameObject GetPrefabAsset(string commonDirPath) { var elementInfo = ElementInfo; var guids = AssetDatabase.FindAssets(elementInfo.prefabName, new string[] { commonDirPath }); @@ -73,6 +67,12 @@ namespace UguiToolkit.Editor var setting = GlobalManager.Instance.setting; return PrefabUtility.IsAnyPrefabInstanceRoot(asset) && PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(asset).StartsWith(setting.commonPrefabForUIDirPath); } + + public static string GetCommonDirPath() + { + var setting = GlobalManager.Instance.setting; + return setting.commonPrefabForUIDirPath; + } } } diff --git a/Assets/Editor/Entity/TextEntity.cs b/Assets/Editor/Entity/TextEntity.cs index 2165594..281a7ab 100644 --- a/Assets/Editor/Entity/TextEntity.cs +++ b/Assets/Editor/Entity/TextEntity.cs @@ -36,7 +36,7 @@ namespace UguiToolkit.Editor ApplyTransform(transform); } - public override void ApplyTransform(Transform tf) + protected override void OnApplyTransform(Transform tf) { var position = ElementInfo.Position; tf.position = StageManager.Instance.PrefabContentsRoot.transform.TransformPoint(new Vector3(position.x, position.y, 0)); diff --git a/Assets/Editor/Entity/TextMeshProEntity.cs b/Assets/Editor/Entity/TextMeshProEntity.cs index da7c5a8..81ea71b 100644 --- a/Assets/Editor/Entity/TextMeshProEntity.cs +++ b/Assets/Editor/Entity/TextMeshProEntity.cs @@ -13,7 +13,7 @@ namespace UguiToolkit.Editor { private TextMeshProUGUI m_previewText; - public override void ApplyTransform(Transform tf) + protected override void OnApplyTransform(Transform tf) { var rt = tf as RectTransform; @@ -37,11 +37,6 @@ namespace UguiToolkit.Editor protected override void OnApplyData(TextMeshProUGUI ui) { - ui.text = ElementInfo.text; - ui.fontSize = (int)ElementInfo.size; - ui.color = ElementInfo.color; - ui.alignment = TextAlignmentOptions.Center; - SetTMPByTextInfo(ui, ElementInfo); } @@ -60,9 +55,15 @@ namespace UguiToolkit.Editor private static void SetTMPByTextInfo(TextMeshProUGUI ui, LayoutInfo.TextInfo textInfo) { + // TODO: չ float2 sizeOffset = float2.zero; - // TODO: չ + + if (!ui.hasStringID) ui.text = textInfo.text; + ui.fontSize = (int)textInfo.size; + ui.color = textInfo.color; + ui.alignment = TextAlignmentOptions.Center; + if (GetTextFontPreset(textInfo, out var textFontPreset)) { ui.font = textFontPreset.tmpAsset; diff --git a/Assets/Editor/Helper/CommandHelper.cs b/Assets/Editor/Helper/CommandHelper.cs deleted file mode 100644 index a51a746..0000000 --- a/Assets/Editor/Helper/CommandHelper.cs +++ /dev/null @@ -1,92 +0,0 @@ - -#if UNITY_EDITOR -using UnityEngine; -using System.IO; -using Newtonsoft.Json; -using System.Threading.Tasks; -using System; - -namespace UguiToolkit.Editor -{ - public static class CommandHelper - { - public static void CalcRotScale(string srcImgDirPath, string targetImgDirPath, float distanceDifference, Action callback) - { - var rotScaleInfoFilePath = Path.GetFullPath(EditorConst.RotScaleInfoFilePath); - var rotScaleInfoToolFilePath = Path.GetFullPath(EditorConst.RotScaleInfoToolFilePath); - if (File.Exists(rotScaleInfoFilePath)) File.Delete(rotScaleInfoFilePath); - - var cmd = string.Format("{0} -src {1} -target {2} -distance_difference {3} -output_path {4} -filter __background__.png", - rotScaleInfoToolFilePath, - Path.GetFullPath(srcImgDirPath), - Path.GetFullPath(targetImgDirPath), - distanceDifference, - Path.GetFullPath(rotScaleInfoFilePath)); - Debug.Log("cmd: " + cmd); - _ = RunCmdAsync(cmd, (output, error) => - { - Debug.Log(output); - if (!File.Exists(rotScaleInfoFilePath)) - { - Debug.LogError($"[E] 文件{rotScaleInfoFilePath} 未能正确获得"); - Debug.LogError(error); - return; - } - - using (StreamReader reader = File.OpenText(rotScaleInfoFilePath)) - { - var jsonData = reader.ReadToEnd(); - RotScaleJsonData rotScaleJsonData = JsonConvert.DeserializeObject(jsonData); - callback(rotScaleJsonData); - } - }); - } - - // 执行 cmd 命令 - public static void RunCmd(in string cmd) - { - var p = new System.Diagnostics.Process(); - p.StartInfo.FileName = "cmd.exe"; - p.StartInfo.Arguments = "/c " + cmd; // 使用 /c 参数执行命令并关闭 cmd 窗口 - p.StartInfo.UseShellExecute = false; - p.StartInfo.CreateNoWindow = true; - p.StartInfo.RedirectStandardOutput = true; - p.StartInfo.RedirectStandardError = true; - p.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; - p.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8; - - p.Start(); - var output = p.StandardOutput.ReadToEnd(); - var error = p.StandardError.ReadToEnd(); - p.WaitForExit(); - - UnityEngine.Debug.Log("cmd output : " + output); - UnityEngine.Debug.Log("cmd error : " + error); - } - - // 异步执行 cmd 命令 - public static async Task RunCmdAsync(string cmd, Action callback = null) - { - var p = new System.Diagnostics.Process(); - p.StartInfo.FileName = "cmd.exe"; - p.StartInfo.Arguments = "/c " + cmd; // 使用 /c 参数执行命令并关闭 cmd 窗口 - p.StartInfo.UseShellExecute = false; - p.StartInfo.CreateNoWindow = true; - p.StartInfo.RedirectStandardOutput = true; - p.StartInfo.RedirectStandardError = true; - p.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; - p.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8; - - p.Start(); - - var output = await p.StandardOutput.ReadToEndAsync(); - var error = await p.StandardError.ReadToEndAsync(); - // 异步等待进程退出 - await Task.Run(() => p.WaitForExit()); - - // 在主线程上调用回调函数 - UnityMainThreadDispatcher.Instance().Enqueue(() => callback?.Invoke(output, error)); - } - } -} -#endif \ No newline at end of file diff --git a/Assets/Editor/Helper/CommandHelper.cs.meta b/Assets/Editor/Helper/CommandHelper.cs.meta deleted file mode 100644 index b275b00..0000000 --- a/Assets/Editor/Helper/CommandHelper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: c5a6dac91d434baab2b66ee97122eaf3 -timeCreated: 1718813946 \ No newline at end of file diff --git a/Assets/Editor/Helper/ImageUtils.cs b/Assets/Editor/Helper/ImageUtils.cs index 8d119a4..ad5066a 100644 --- a/Assets/Editor/Helper/ImageUtils.cs +++ b/Assets/Editor/Helper/ImageUtils.cs @@ -1,7 +1,10 @@ +#if UNITY_EDITOR + using OpenCVForUnity.CoreModule; using OpenCVForUnity.Features2dModule; using OpenCVForUnity.ImgprocModule; using OpenCVForUnity.Calib3dModule; +using OpenCVForUnity.UnityUtils; using System; using System.IO; using System.Collections.Generic; @@ -9,9 +12,16 @@ using UnityEngine; using OpenCVForUnity.ImgcodecsModule; using System.Threading.Tasks; using UguiToolkit.Editor; +using System.Security.Cryptography; +using System.Text; public static class ImageUtils { + public static void SetDebugMode(bool debug) + { + Utils.setDebugMode(debug); + } + public static string FormatImgFilePath(string imgFilePath) { string projectPath = Directory.GetParent(Application.dataPath).FullName; @@ -31,31 +41,60 @@ public static class ImageUtils } } - public static async Task ProcessFolderAsync(List images, string targetFilePath, RotationScaleDetector detector, - double distanceDifference, Action callback, + static List> tasks; + static ObjectPool detectorPool; + + public static async Task ProcessFolderAsync(List images, string targetFilePath, + double distanceDifference, Action callback, Action endCallback) { - Debug.Log("GetRotationScaleAsync: " + targetFilePath); + if (tasks == null) tasks = new (images.Count); + if (detectorPool == null) detectorPool = new (images.Count); + Mat targetImage = Imgcodecs.imread(targetFilePath); - for (int index = 0; index < images.Count; index++) + + List detectors = new(images.Count); + tasks.Clear(); + foreach (var img in images) + { + RotationScaleDetector detector = detectorPool.GetObject(); + tasks.Add(detector.GetRotationScaleAsync(targetImage, img, distanceDifference)); + detectors.Add(detector); + } + + var resultsTask = await Task.WhenAll(tasks.ToArray()); + foreach (var detector in detectors) detectorPool.ReturnObject(detector); + + for (int index = 0; index < resultsTask.Length; index++) { - var img = images[index]; - var result = await detector.GetRotationScaleAsync(targetImage, img, distanceDifference); int _index = index; + var result = resultsTask[index]; UnityMainThreadDispatcher.Instance().Enqueue(() => { - if (result.Item1.HasValue && result.Item2.HasValue) + if (result.Item1.HasValue) { double rotationAngleDegrees = result.Item1.Value; - var scale = result.Item2.Value; - double scaleX = scale.Item1; - double scaleY = scale.Item2; + double scaleX = 0; + double scaleY = 0; + + if (result.Item2.HasValue) + { + var scale = result.Item2.Value; + scaleX = scale.Item1; + scaleY = scale.Item2; + + callback(_index, (rotationAngleDegrees, (scaleX, scaleY), false)); + } + else + { // SimilarityCalc + callback(_index, (rotationAngleDegrees, (scaleX, scaleY), true)); + } - callback(_index, (rotationAngleDegrees, (scaleX, scaleY))); Debug.Log($"Target Image -> Image {_index}"); Debug.Log($"Rotation Angle: {rotationAngleDegrees} degrees"); Debug.Log($"Scale X: {scaleX}"); Debug.Log($"Scale Y: {scaleY}"); + Debug.Log($"SimilarityCalc : {result.Item2 == null}"); } }); } @@ -80,6 +119,9 @@ public class RotationScaleDetector private List goodMatches; private List srcPts; private List dstPts; + private Mat resizedImage; + private Mat dctImage; + StringBuilder sb; public RotationScaleDetector() { @@ -94,6 +136,9 @@ public class RotationScaleDetector goodMatches = new List(); srcPts = new List(); dstPts = new List(); + resizedImage = new Mat(); + dctImage = new Mat(); + sb = new StringBuilder(); } private KeyPoint[] Sift(Mat image, Mat descriptors) @@ -103,59 +148,192 @@ public class RotationScaleDetector return keypoints.toArray(); } - public async Task<(double?, (double, double)?)> GetRotationScaleAsync(Mat img0, Mat img1, double distanceDifference) + #region MD5 + public string CalculateMD5(Mat image) { - KeyPoint[] kp1 = Sift(img0, descriptors1); - KeyPoint[] kp2 = Sift(img1, descriptors2); + // MatתΪֽ + byte[] imageBytes = new byte[image.total() * image.elemSize()]; + image.get(0, 0, imageBytes); - if (kp1.Length == 0 || kp2.Length == 0) + // MD5ϣ㷨ʵ + using (MD5 md5 = MD5.Create()) { - return (null, null); + // ϣֵ + byte[] hashBytes = md5.ComputeHash(imageBytes); + + // ϣֽתΪʮַ + sb.Clear(); + foreach (byte b in hashBytes) + { + sb.Append(b.ToString("x2")); + } + + return sb.ToString(); + } + } + #endregion + + #region Phash + private Mat CalculatePhash(Mat image) + { + Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY); + // СΪ32x32תΪ32λ + Imgproc.resize(gray, resizedImage, new Size(32, 32), 0, 0, Imgproc.INTER_AREA); + resizedImage.convertTo(resizedImage, CvType.CV_32F); + // ɢұ任DCT + Core.dct(resizedImage, dctImage); + // С + if (dctImage.rows() < 8 || dctImage.cols() < 8) + { + Debug.LogError("DCT matrix is too small!"); + return new Mat(); + } + // ȡϽ8x8DCTϵ + Mat dctLowFreq = dctImage.submat(new OpenCVForUnity.CoreModule.Rect(0, 0, 8, 8)); + // DCTϵתΪ + float[] dctArray = new float[64]; + dctLowFreq.get(0, 0, dctArray); + // ֵ + float medianValue = GetMedian(dctArray); + // pHash + Mat phash = new Mat(dctLowFreq.size(), CvType.CV_8U); + for (int i = 0; i < dctLowFreq.rows(); i++) + { + for (int j = 0; j < dctLowFreq.cols(); j++) + { + phash.put(i, j, dctLowFreq.get(i, j)[0] > medianValue ? 1 : 0); + } + } + return phash; + } + + private float GetMedian(float[] array) + { + // + System.Array.Sort(array); + // ֵ + int middle = array.Length / 2; + if (array.Length % 2 == 0) + { + return (array[middle - 1] + array[middle]) / 2.0f; + } + else + { + return array[middle]; + } + } + + private bool IsPhashValid(Mat phash) + { + // pHashΪ1λ + return Core.countNonZero(phash) >= 13; + } + + private int CalculateHammingDistance(Mat phash1, Mat phash2) + { + if (phash1.rows() != phash2.rows() || phash1.cols() != phash2.cols()) + { + Debug.LogError("pHash sizes do not match!"); + return -1; } - knnMatches.Clear(); - goodMatches.Clear(); - bf.knnMatch(descriptors1, descriptors2, knnMatches, 2); - - foreach (MatOfDMatch matofDMatch in knnMatches) + int hammingDistance = 0; + for (int i = 0; i < phash1.rows(); i++) { - DMatch[] matches = matofDMatch.toArray(); - if (matches[0].distance < distanceDifference * matches[1].distance) + for (int j = 0; j < phash1.cols(); j++) { - goodMatches.Add(matches[0]); + if (phash1.get(i, j)[0] != phash2.get(i, j)[0]) + { + hammingDistance++; + } } } - if (goodMatches.Count < 3) - { - return (null, null); - } + return hammingDistance; + } - srcPts.Clear(); - dstPts.Clear(); - foreach (DMatch match in goodMatches) - { - srcPts.Add(kp1[match.queryIdx].pt); - dstPts.Add(kp2[match.trainIdx].pt); - } + #endregion - MatOfPoint2f srcMatOfPoint2f = new MatOfPoint2f(srcPts.ToArray()); - MatOfPoint2f dstMatOfPoint2f = new MatOfPoint2f(dstPts.ToArray()); + public async Task<(double?, (double, double)?)> GetRotationScaleAsync(Mat img0, Mat img1, double distanceDifference) + { + return await Task.Run<(double?, (double, double)?)>(() => { + try + { + string md5Hash0 = CalculateMD5(img0); + string md5Hash1 = CalculateMD5(img1); + if (md5Hash0 == md5Hash1) + { + return (0, null); + } - Mat M = Calib3d.estimateAffinePartial2D(srcMatOfPoint2f, dstMatOfPoint2f, inliers, Calib3d.RANSAC, 5); - if (M.empty()) - { - return (null, null); - } + Mat phash1 = CalculatePhash(img0); + Mat phash2 = CalculatePhash(img1); - Mat R = M.colRange(0, 2); - double theta = Math.Atan2(R.get(1, 0)[0], R.get(0, 0)[0]); - double rotationAngleDegrees = theta * 180.0 / Math.PI; + if (IsPhashValid(phash1) && IsPhashValid(phash2) && CalculateHammingDistance(phash1, phash2) < 10) + { + return (0, null); + } - double scaleX = Core.norm(R.row(0)); - double scaleY = Core.norm(R.row(1)); + KeyPoint[] kp1 = Sift(img0, descriptors1); + KeyPoint[] kp2 = Sift(img1, descriptors2); - return (rotationAngleDegrees, (scaleX, scaleY)); + if (kp1.Length == 0 || kp2.Length == 0) + { + return (null, null); + } + + knnMatches.Clear(); + goodMatches.Clear(); + bf.knnMatch(descriptors1, descriptors2, knnMatches, 2); + + foreach (MatOfDMatch matofDMatch in knnMatches) + { + DMatch[] matches = matofDMatch.toArray(); + if (matches[0].distance < distanceDifference * matches[1].distance) + { + goodMatches.Add(matches[0]); + } + } + + if (goodMatches.Count < 3) + { + return (null, null); + } + + srcPts.Clear(); + dstPts.Clear(); + foreach (DMatch match in goodMatches) + { + srcPts.Add(kp1[match.queryIdx].pt); + dstPts.Add(kp2[match.trainIdx].pt); + } + + MatOfPoint2f srcMatOfPoint2f = new MatOfPoint2f(srcPts.ToArray()); + MatOfPoint2f dstMatOfPoint2f = new MatOfPoint2f(dstPts.ToArray()); + + Mat M = Calib3d.estimateAffinePartial2D(srcMatOfPoint2f, dstMatOfPoint2f, inliers, Calib3d.RANSAC, 5); + if (M.empty()) + { + return (null, null); + } + + Mat R = M.colRange(0, 2); + double theta = Math.Atan2(R.get(1, 0)[0], R.get(0, 0)[0]); + double rotationAngleDegrees = theta * 180.0 / Math.PI; + + double scaleX = Core.norm(R.row(0)); + double scaleY = Core.norm(R.row(1)); + + return (rotationAngleDegrees, (scaleX, scaleY)); + } + catch (Exception e) + { + Debug.LogException(e); + + return (null, null); + } + }); } } +#endif \ No newline at end of file diff --git a/Assets/Editor/Helper/ObjectPool.cs b/Assets/Editor/Helper/ObjectPool.cs new file mode 100644 index 0000000..e03808f --- /dev/null +++ b/Assets/Editor/Helper/ObjectPool.cs @@ -0,0 +1,49 @@ + +#if UNITY_EDITOR + +using System.Collections.Generic; + +namespace UguiToolkit.Editor +{ + public class ObjectPool where T : new() + { + public int initialSize = 10; // ʼС + private Queue pool; + + public ObjectPool(int initialSize) + { + this.initialSize = initialSize; + this.pool = new Queue(initialSize); + // ԤȴһЩ + for (int i = 0; i < initialSize; i++) + { + T obj = new T(); + pool.Enqueue(obj); + } + } + + // ȡ + public T GetObject() + { + if (pool.Count > 0) + { + T obj = pool.Dequeue(); + return obj; + } + else + { + // ûпö򴴽µĶ + T obj = new T(); + return obj; + } + } + + // ͷŶ + public void ReturnObject(T obj) + { + pool.Enqueue(obj); + } + } +} + +#endif \ No newline at end of file diff --git a/Assets/Editor/Helper/ObjectPool.cs.meta b/Assets/Editor/Helper/ObjectPool.cs.meta new file mode 100644 index 0000000..0927470 --- /dev/null +++ b/Assets/Editor/Helper/ObjectPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc8e87f03da56414b9de0b42bc4fd282 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor/Helper/PanelHelper.cs b/Assets/Editor/Helper/PanelHelper.cs index 47b01bb..2edd89d 100644 --- a/Assets/Editor/Helper/PanelHelper.cs +++ b/Assets/Editor/Helper/PanelHelper.cs @@ -35,6 +35,23 @@ namespace UguiToolkit.Editor PanelCacheWindow.CloseWindow(); EditWindow.CloseWindow(); } + + /// + /// 创建热键 SPACE + /// + /// + [MenuItem("GameObject/拼接助手/应用上次变换 _SPACE", false, 5)] + public static void JumpOfGameCameraByCurPos(MenuCommand menuCommand) + { + if (StageManager.Instance) + { + var entityMng = StageManager.Instance.GetManager(); + if (entityMng && Selection.activeGameObject) + { + entityMng.EffectLastApplyTransform(Selection.activeGameObject.transform); + } + } + } } } #endif \ No newline at end of file diff --git a/Assets/Editor/Manager/EntityManager.cs b/Assets/Editor/Manager/EntityManager.cs index 2190101..2005e34 100644 --- a/Assets/Editor/Manager/EntityManager.cs +++ b/Assets/Editor/Manager/EntityManager.cs @@ -36,14 +36,10 @@ namespace UguiToolkit.Editor private bool m_useTMP; private EditWindow editWindow; - private string m_runningImgDirPath = null; - private bool isRunning = false; - private HashSet m_runningImgFilePaths = new(); - private List m_preCheckImgDirPaths = new (); + private bool isCalcRotationScaleRunning = false; private List targetImages; private List targetPaths; - private RotationScaleDetector detector; public Transform Background => m_background; @@ -62,7 +58,13 @@ namespace UguiToolkit.Editor editWindow.showHierarchyOfEntityChanged += OnUpdateHierarchyOfEntityAllEntity; editWindow.showBackgroundChanged += OnUpdateBackgroundShow; editWindow.createAllTextEntity += CreateAllTextEntity; + editWindow.createAllPrefabEntity += CreateAllPrefabEntity; + editWindow.effectLastApplyTransform += EffectLastApplyTransform; } + + EditorApplication.hierarchyWindowItemOnGUI += HandleHierarchyWindowItemOnGUI; + + ImageUtils.SetDebugMode(true); } private void OnDisable() @@ -74,7 +76,15 @@ namespace UguiToolkit.Editor editWindow.showHierarchyOfEntityChanged -= OnUpdateHierarchyOfEntityAllEntity; editWindow.showBackgroundChanged -= OnUpdateBackgroundShow; editWindow.createAllTextEntity -= CreateAllTextEntity; + editWindow.createAllPrefabEntity -= CreateAllPrefabEntity; + editWindow.effectLastApplyTransform -= EffectLastApplyTransform; } + + EditorApplication.hierarchyWindowItemOnGUI -= HandleHierarchyWindowItemOnGUI; + + ImageUtils.SetDebugMode(false); + if (m_stageManager.PrefabAsset || m_panelCache != null) + GlobalManager.Instance.SaveCache(m_stageManager.PrefabAsset, m_panelCache); } private void Update() @@ -100,7 +110,7 @@ namespace UguiToolkit.Editor entity.ApplyTransform(tf); if (PrefabEntity.IsPrefab(tf.gameObject)) { - entity.ApplyData(tf); + entity.ApplyData(tf); } else if (tf.TryGetComponent(out var image)) { @@ -115,7 +125,6 @@ namespace UguiToolkit.Editor entity.ApplyData(temp); } - if (editWindow) editWindow.SetLastApplyEntity(entity); m_lastSelectionGo = m_curSelectionGo; m_lastSelectionEntity = entity; @@ -124,58 +133,33 @@ namespace UguiToolkit.Editor } } } - - // 及时更新PanelCache - CheckPanelCache(); } - public void AddCheckImgDirPath(string dirPath) + public void EffectLastApplyTransform(Transform parent) { - //if (string.IsNullOrEmpty(dirPath)) return; - //dirPath = dirPath.Replace("\\", "/"); - - //if (m_runningImgDirPath != null && m_runningImgDirPath == dirPath) return; - - //if (m_panelCache.IsValidOfImgDirPath(dirPath)) - //{ - // return; - //} - - //if (Directory.Exists(dirPath)) - //{ - // if (m_preCheckImgDirPaths.Contains(dirPath)) - // { - // m_preCheckImgDirPaths.Remove(dirPath); - // } - - // Debug.Log($"[I] AddCheckImgDirPath {dirPath}"); - // m_preCheckImgDirPaths.Insert(0, dirPath); - //} - } - - private string GetCheckImgDirPath() - { - if (m_preCheckImgDirPaths.Count > 0) + if (m_lastSelectionEntity != null) { - string dirPath = m_preCheckImgDirPaths[0]; - m_preCheckImgDirPaths.RemoveAt(0); - if (Directory.Exists(dirPath)) - { - return dirPath; - } + m_lastSelectionEntity.ApplyTransformByParent(parent, m_lastSelectionGo ? m_lastSelectionGo.transform: null); } - return null; } - private void CheckPanelCache() + private void HandleHierarchyWindowItemOnGUI(int instanceID, Rect selectionRect) { - if (m_runningImgDirPath == null) + if (!m_stageManager) return; + var go = EditorUtility.InstanceIDToObject(instanceID) as GameObject; + if (!go) return; + if (go == m_lastSelectionGo) { - var srcImgDirPath = GetCheckImgDirPath(); - if (srcImgDirPath != null) + var goLabel = new GUIContent(go.name); + var goSize = EditorStyles.linkLabel.CalcSize(goLabel) + new Vector2(20, 0); + var label = new GUIContent(" <-----"); + var size = EditorStyles.linkLabel.CalcSize(label) + new Vector2(10, 0); + var offsetRect = + new Rect(selectionRect.position + new Vector2(goSize.x, 0), size); + EditorGUI.LabelField(offsetRect, label, new GUIStyle() { - UpdatePanelCache(srcImgDirPath, m_panelCache.TargetImgDirPath); - } + normal = new GUIStyleState() { textColor = Color.green }, + }); } } @@ -184,7 +168,6 @@ namespace UguiToolkit.Editor var root = m_stageManager.PrefabContentsRoot; var textsTf = root.transform.Find("__texts__"); if (textsTf) DestroyImmediate(textsTf.gameObject); - if (m_textEntities == null) return; var textsGo = new GameObject("__texts__", typeof(RectTransform)); textsGo.transform.parent = root.transform; @@ -199,6 +182,28 @@ namespace UguiToolkit.Editor } } + private void CreateAllPrefabEntity() + { + var root = m_stageManager.PrefabContentsRoot; + var prefabsTf = root.transform.Find("__prefabs__"); + if (prefabsTf) DestroyImmediate(prefabsTf.gameObject); + + if (m_textEntities == null) return; + var prefabsGo = new GameObject("__prefabs__", typeof(RectTransform)); + prefabsGo.transform.parent = root.transform; + + foreach (var prefabEntity in m_prefabEntities) + { + var asset = prefabEntity.GetPrefabAsset(PrefabEntity.GetCommonDirPath()); + if (asset != null) + { + var go = GameObject.Instantiate(asset, prefabsGo.transform); + go.name = asset.name; + prefabEntity.ApplyData(go.transform); + } + } + } + private void InitBackground() { if (m_background) DestroyImmediate(m_background.gameObject); @@ -242,10 +247,10 @@ namespace UguiToolkit.Editor private void UpdatePanelCache(string srcImgPath) { float distanceDifference = GlobalManager.Instance.setting.distanceDifference; - m_runningImgFilePaths.Add(srcImgPath); - isRunning = true; + isCalcRotationScaleRunning = true; List rotScaleItemList = new(); - _ = ImageUtils.ProcessFolderAsync(targetImages, srcImgPath, detector, distanceDifference, (index, result) => + Debug.Log("GetRotationScaleAsync: " + srcImgPath); + _ = ImageUtils.ProcessFolderAsync(targetImages, srcImgPath, distanceDifference, (index, result) => { if (!m_stageManager) return; rotScaleItemList.Add(new() @@ -253,13 +258,13 @@ namespace UguiToolkit.Editor imgPath = ImageUtils.FormatImgFilePath(targetPaths[index]), rotiation = (float)result.Item1, scale = new float2((float)result.Item2.Item1, (float)result.Item2.Item1), - similarityCalc = false + similarityCalc = result.Item3 }); }, () => { - isRunning = false; + Debug.Log("End GetRotationScaleAsync: " + srcImgPath); + isCalcRotationScaleRunning = false; if (!m_stageManager) return; - m_runningImgFilePaths.Remove(srcImgPath); m_panelCache.AddRotScaleInfo(srcImgPath, rotScaleItemList); if (rotScaleItemList.Count > 0) @@ -267,26 +272,6 @@ namespace UguiToolkit.Editor }); } - public void UpdatePanelCache(string srcImgDirPath, string targetImgDirPath) - { - float distanceDifference = GlobalManager.Instance.setting.distanceDifference; - m_runningImgDirPath = srcImgDirPath; - - CacheScriptObject.CalcRotScaleInfos(srcImgDirPath, targetImgDirPath, distanceDifference,(rotScaleInfoMap) => - { - m_runningImgDirPath = null; - if (!m_stageManager) return; - m_panelCache.AddImgDirPathTimestamp(srcImgDirPath); - m_panelCache.ClearRotScaleInfoItem(srcImgDirPath); - - // 拷贝数据 - foreach (var kv in rotScaleInfoMap) m_panelCache.AddRotScaleInfo(kv.Key, kv.Value); - - // 保存缓存 - GlobalManager.Instance.SaveCache(m_stageManager.PrefabAsset, m_panelCache); - }); - } - private void OnSelectionChanged() { if (m_noSelection || !Selection.activeGameObject || Selection.gameObjects.Length > 1) return; @@ -310,6 +295,7 @@ namespace UguiToolkit.Editor { prefabEntity.ShowSelectionImg(true); prefabEntity.gameObject.SetActive(true); + prefabEntity.SetOriginalMatrix(activeGameObject.transform); m_selectionEntities.Add(prefabEntity); @@ -345,6 +331,7 @@ namespace UguiToolkit.Editor if (!string.IsNullOrEmpty(srcImgPath) && m_panelCache.HaveRotScaleInfo(srcImgPath, out var rotScaleInfoItems)) { m_entityRoot.gameObject.SetActive(true); + bool isFind; bool IsInside = false; foreach (var imgEntity in m_imageEntities) @@ -364,8 +351,9 @@ namespace UguiToolkit.Editor imgEntity.SetTransform(rotScale.rotiation, rotScale.scale, false); } - imgEntity.ApplyTransform(imgEntity.transform); + imgEntity.InternalApplyTransform(imgEntity.transform); imgEntity.ShowSelectionImg(true); + imgEntity.SetOriginalMatrix(activeGameObject.transform); m_selectionEntities.Add(imgEntity); if (!IsInside && imgEntity.IsInside(activeGameObject.transform)) IsInside = true; @@ -409,6 +397,7 @@ namespace UguiToolkit.Editor { textEntity.ShowSelectionImg(true); textEntity.gameObject.SetActive(true); + textEntity.SetOriginalMatrix(activeGameObject.transform); m_selectionEntities.Add(textEntity); @@ -444,7 +433,7 @@ namespace UguiToolkit.Editor { var srcImgPath = AssetDatabase.GetAssetPath(image.sprite); if (!string.IsNullOrEmpty(srcImgPath) && !m_panelCache.HaveRotScaleInfo(srcImgPath) && - !isRunning) + !isCalcRotationScaleRunning) { UpdatePanelCache(srcImgPath); @@ -467,7 +456,6 @@ namespace UguiToolkit.Editor targetImages = new (); targetPaths = new (); ImageUtils.LoadPngImagesFromFolder(panelCache.TargetImgDirPath, targetImages, targetPaths); - detector = new RotationScaleDetector(); } private void OnUpdateBackgroundShow(bool show) @@ -482,8 +470,10 @@ namespace UguiToolkit.Editor { UpdateHierarchyOfEntity(show, m_entityRoot.gameObject); UpdateHierarchyOfEntity(show, m_background.gameObject); + foreach (Transform entity in m_background.transform) UpdateHierarchyOfEntity(show, entity.gameObject); foreach (var entity in m_imageEntities) UpdateHierarchyOfEntity(show, entity.gameObject); foreach (var entity in m_textEntities) UpdateHierarchyOfEntity(show, entity.gameObject); + foreach (var entity in m_prefabEntities) UpdateHierarchyOfEntity(show, entity.gameObject); } private void UpdateHierarchyOfEntity(in bool show, in GameObject entity) diff --git a/Assets/Editor/ScriptObject/CacheScriptObject.cs b/Assets/Editor/ScriptObject/CacheScriptObject.cs index 7ccc95c..2f1872e 100644 --- a/Assets/Editor/ScriptObject/CacheScriptObject.cs +++ b/Assets/Editor/ScriptObject/CacheScriptObject.cs @@ -53,35 +53,6 @@ namespace UguiToolkit.Editor return layoutInfo; } } - - public static void CalcRotScaleInfos(string srcImgDirPath, string targetImgDirPath, float distanceDifference, Action>> callback) - { - // 执行cmd - CommandHelper.CalcRotScale(srcImgDirPath, targetImgDirPath, distanceDifference,(jsonData) => - { - if (jsonData == null || jsonData.data == null) return; - Dictionary> rotScaleInfos = new(); - - string projectPath = Directory.GetParent(Application.dataPath).FullName; - foreach (var kv in jsonData.data) - { - List rotScaleItemList = new(); - rotScaleInfos[ImageUtils.FormatImgFilePath(kv.Key)] = rotScaleItemList; - foreach (var jsonItemData in kv.Value) - { - rotScaleItemList.Add(new() - { - imgPath = ImageUtils.FormatImgFilePath(jsonItemData.targetPath), - rotiation = jsonItemData.rot, - scale = new float2(jsonItemData.scale[0], jsonItemData.scale[1]), - similarityCalc = jsonItemData.similarityCalc - }); - } - } - - callback(rotScaleInfos); - }); - } } [Serializable] @@ -94,8 +65,6 @@ namespace UguiToolkit.Editor [Serializable] public class PanelCache { - [LabelText("项目内导出图片文件夹"), FolderPath] - public string srcImgDirPath; [LabelText("目标图片信息文件(psd导出)"), Sirenix.OdinInspector.FilePath(AbsolutePath = true, Extensions = "layout.txt")] public string layoutInfoFilePath; // Sample.layout.txt [LabelText("目标图片文件夹路径")] @@ -123,15 +92,12 @@ namespace UguiToolkit.Editor public LayoutInfo layoutInfo; [SerializeField, HideInInspector] private string m_targetImgDirPath; - [SerializeField] - public Dictionary imgDirPathTimestamp = new(); private PanelCache() { } // public PanelCache(string srcImgDirPath, string layoutInfoFilePath) - public PanelCache(string layoutInfoFilePath, string srcImgDirPath, bool isVertical = false) + public PanelCache(string layoutInfoFilePath, bool isVertical = false) { - this.srcImgDirPath = srcImgDirPath; this.layoutInfoFilePath = layoutInfoFilePath; this.isVertical = isVertical; @@ -141,7 +107,6 @@ namespace UguiToolkit.Editor public void Copy(PanelCache panelCache) { rotScaleInfos = panelCache.rotScaleInfos; - imgDirPathTimestamp = panelCache.imgDirPathTimestamp; } public bool HaveRotScaleInfo(string srcImgPath) @@ -159,32 +124,32 @@ namespace UguiToolkit.Editor rotScaleInfos[srcImgPath] = rotScaleInfo; } - public bool IsValidOfImgDirPath(string imgDirPath) + public void InitRotScaleInfos() { - if (!Directory.Exists(imgDirPath)) return false; - - if (imgDirPathTimestamp.TryGetValue(imgDirPath, out var timestamp)) + HashSet keys = new(); + foreach (var srcImgPath in rotScaleInfos.Keys) { - var curTimestamp = GetTimestampByDirPath(imgDirPath); - return curTimestamp == timestamp; + if (!File.Exists(srcImgPath)) + { + keys.Add(srcImgPath); + } + } + foreach (var key in keys) + { + rotScaleInfos.Remove(key); } - return false; - } - - public void ClearRotScaleInfoItem(string imgDirPath) - { - List indeces = new(); + List indeces = new(); foreach (var rotScaleInfo in rotScaleInfos.Values) { indeces.Clear(); for (var i = 0; i < rotScaleInfo.Count; i++) - { + { var item = rotScaleInfo[i]; - if (item.imgPath.StartsWith(imgDirPath)) + if (!File.Exists(item.imgPath)) { indeces.Add(i); - } + } } indeces.Sort(); @@ -197,27 +162,9 @@ namespace UguiToolkit.Editor } } - public void AddImgDirPathTimestamp(string imgDirPath) - { - var curTimestamp = GetTimestampByDirPath(imgDirPath); - imgDirPathTimestamp[imgDirPath] = curTimestamp; - } - - public void InitRotScaleInfos() - { - foreach(var dirPath in imgDirPathTimestamp.Keys) - { - if (!IsValidOfImgDirPath(dirPath)) - { - ClearRotScaleInfoItem(dirPath); - } - } - } - public void ClearRotScaleInfos() { rotScaleInfos.Clear(); - imgDirPathTimestamp.Clear(); } public IEnumerable GetLayoutElementInfos() where T : LayoutInfo.ElementInfo @@ -243,14 +190,6 @@ namespace UguiToolkit.Editor return System.IO.Path.Join(dirName, split[0]); } - - public static long GetTimestampByDirPath(string dirPath) - { - DirectoryInfo directoryInfo = new DirectoryInfo(dirPath); - // 获取文件夹的最后修改时间 - DateTime lastModified = directoryInfo.LastWriteTime; - return new DateTimeOffset(lastModified).ToUnixTimeSeconds(); - } } [Serializable] diff --git a/Assets/Editor/Windows/EditWindow.cs b/Assets/Editor/Windows/EditWindow.cs index 40a9f2a..5f3e56b 100644 --- a/Assets/Editor/Windows/EditWindow.cs +++ b/Assets/Editor/Windows/EditWindow.cs @@ -24,6 +24,16 @@ namespace UguiToolkit.Editor.Windows /// public event Action createAllTextEntity; + /// + /// PrefabEntity + /// + public event Action createAllPrefabEntity; + + /// + /// Ӧϴα任 + /// + public event Action effectLastApplyTransform; + [SerializeField, HideInInspector] private bool m_showHierarchyOfEntityChange = false; @@ -59,31 +69,26 @@ namespace UguiToolkit.Editor.Windows createAllTextEntity?.Invoke(); } + [Button("ͨԤ")] + private void CreateAllPrefabEntity() + { + createAllPrefabEntity?.Invoke(); + } + [Title("")] - [LabelText("ϴα任Ķ"), SerializeField] - private IEntity m_lastApplyEntity; [LabelText("ҪӦñ任Ķ"), SerializeField] private Transform m_targetTransform; - [Button("Ӧϴα任")] + [Button("Ӧϴα任 (SPACE)")] private void EffectLastApplyTransform() { if (m_targetTransform) { - var m_lastApplyTransform = m_lastApplyEntity.gameObject.transform; - var parent = m_lastApplyTransform.parent; - m_lastApplyTransform.parent = null; - m_lastApplyEntity.ApplyTransformByParent(m_targetTransform); - m_lastApplyTransform.parent = parent; + effectLastApplyTransform?.Invoke(m_targetTransform); } } - public void SetLastApplyEntity(IEntity lastApplyTransform) - { - this.m_lastApplyEntity = lastApplyTransform; - } - public override string GettitleContent() { return "ֱ༭"; diff --git a/Assets/Editor/Windows/PanelCacheWindow.cs b/Assets/Editor/Windows/PanelCacheWindow.cs index d84ebd3..89a6ece 100644 --- a/Assets/Editor/Windows/PanelCacheWindow.cs +++ b/Assets/Editor/Windows/PanelCacheWindow.cs @@ -17,8 +17,6 @@ namespace UguiToolkit.Editor.Windows private bool m_isVertical = false; [Title("psd导出数据设置")] - [LabelText("项目中切图文件夹"), FolderPath, SerializeField] - private string m_srcImgDirPath; [LabelText("layout.txt文件"), Sirenix.OdinInspector.FilePath(AbsolutePath = true, Extensions = "layout.txt"), SerializeField] private string m_layoutInfoFilePath; @@ -30,6 +28,12 @@ namespace UguiToolkit.Editor.Windows [Button("开启助手", ButtonSizes.Medium)] private void DoStart() { + if (string.IsNullOrEmpty(m_layoutInfoFilePath)) + { + EditorUtility.DisplayDialog("提示", "请先填写配置", "好的"); + return; + } + var stageManager = UguiToolkit.StageManager.CreateStageManager(m_prefabStage.scene, m_prefabStage.prefabContentsRoot, m_prefab); stageManager.gameObject.AddComponent(); @@ -37,7 +41,7 @@ namespace UguiToolkit.Editor.Windows EditWindow.ShowWindow(null); var targetImgDirPath = PanelCache.GetTargetImgDirPath(m_layoutInfoFilePath); - var panelCache = new PanelCache(m_layoutInfoFilePath, m_srcImgDirPath, m_isVertical); + var panelCache = new PanelCache(m_layoutInfoFilePath, m_isVertical); panelCache.layoutInfo = CacheScriptObject.PaserLayout(m_layoutInfoFilePath, targetImgDirPath); if (m_panelCache != null) @@ -55,8 +59,6 @@ namespace UguiToolkit.Editor.Windows // stageManager.CreateSubManager(); entityManager.Init(panelCache); - if (!string.IsNullOrEmpty(m_srcImgDirPath)) - entityManager.AddCheckImgDirPath(m_srcImgDirPath); CloseWindow(); } @@ -82,12 +84,10 @@ namespace UguiToolkit.Editor.Windows var panelCache = GlobalManager.Instance.GetCache(m_prefab, m_isVertical); if (panelCache != null) { - m_srcImgDirPath = panelCache.srcImgDirPath; m_layoutInfoFilePath = panelCache.layoutInfoFilePath; m_panelCache = panelCache; } else { - m_srcImgDirPath = null; m_layoutInfoFilePath = null; m_panelCache = null; } diff --git a/README.md b/README.md index c7181f8..9f5ee2f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ > 1. psd 导出自动切图,并处理九宫格 > 2. unity拼接时,对psd上所标记的像素图层进行吸附,设置位置和旋转、缩放 > 3. unity拼接时,对psd上所标记的文本图层进行吸附,设置位置和旋转、缩放,并设置字体、字体大小、字体颜色、描边等 -> 4. (未实现) unity拼接时,对公共组件预制体进行设置位置和旋转、缩放 +> 4. unity拼接时,对公共组件预制体进行设置位置和旋转、缩放 ## 工作流 ![](./.res/流程图.png) @@ -32,13 +32,10 @@ ### unity中如何操作 -上述`yueka_output`为最终进入项目的切图,可自行根据分类放入 `client\Assets\res\ui\atlas` - #### 进入预制体场景 点击开启助手,设置如下路径后,点击`开启助手` -1. 项目内导出图片文件夹:填入项目内该功能的切图目录 -2. 目标图片信息文件夹: 填入导出psd数据的 ` yueka.layout.txt` +1. 目标图片信息文件夹: 填入导出psd数据的 ` yueka.layout.txt` ![img](F:\c1workspace\svn\__workspace__dev__\client\PackagesSource\com.txcombo.c1.ugui-toolkit\.res\开启助手.png) @@ -49,6 +46,6 @@ ##### 文本 ![](./.res/创建text.png) ![](./.res/创建text后的结果.png) -##### 预制体 (未实现) -1. 取消节点选中后,会显示界面所有可供创建的预制体预览 +##### 预制体 +1. 选中预制体节点后,会显示界面所有可供创建的预制体预览 2. 将鼠标光标放入预制体预览框,会自动创建预制体 \ No newline at end of file