namespace Runtime { // ImageHierarchyBlender.cs using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; using System.IO; public class ImageHierarchyBlender : MonoBehaviour { public RectTransform parentContainer; // 父级容器 public Shader blendShader; // 混合Shader public string fileName = "BlendedResult"; // 混合模式枚举 public enum BlendMode { AlphaBlend, Multiply, Screen } public BlendMode blendMode = BlendMode.AlphaBlend; [ContextMenu("Export Blended Image")] public void ExportBlendedImage() { // 获取所有图形组件 List graphics = GetAllGraphics(parentContainer.gameObject); // 创建RenderTexture Vector2Int size = GetTotalSize(parentContainer); RenderTexture rt = new RenderTexture(size.x, size.y, 0); // 初始化画布 Texture2D finalTexture = InitializeCanvas(size); Graphics.Blit(finalTexture, rt); // 混合所有层 foreach (Graphic graphic in graphics) { if (!graphic.gameObject.activeInHierarchy) continue; // 获取元素信息 Texture2D elementTex = CaptureGraphic(graphic); Vector2 position = GetRelativePosition(graphic.rectTransform, parentContainer); // 混合到画布 BlendLayer(ref finalTexture, elementTex, position, rt); DestroyImmediate(elementTex); } // 保存结果 SaveTexture(finalTexture); // 清理资源 RenderTexture.active = null; DestroyImmediate(rt); DestroyImmediate(finalTexture); } // 获取所有子物体的Graphic组件(递归) List GetAllGraphics(GameObject parent) { List graphics = new List(); Graphic parentGraphic = parent.GetComponent(); if (parentGraphic != null) graphics.Add(parentGraphic); foreach (Transform child in parent.transform) { graphics.AddRange(GetAllGraphics(child.gameObject)); } return graphics; } // 计算容器总尺寸 Vector2Int GetTotalSize(RectTransform rectTransform) { return new Vector2Int( Mathf.RoundToInt(rectTransform.rect.width), Mathf.RoundToInt(rectTransform.rect.height) ); } // 初始化画布 Texture2D InitializeCanvas(Vector2Int size) { Texture2D tex = new Texture2D(size.x, size.y, TextureFormat.ARGB32, false); Color[] pixels = new Color[size.x * size.y]; for (int i = 0; i < pixels.Length; i++) pixels[i] = Color.clear; tex.SetPixels(pixels); tex.Apply(); return tex; } // 捕获单个图形元素 Texture2D CaptureGraphic(Graphic graphic) { // 创建临时RenderTexture RenderTexture rt = new RenderTexture( (int)graphic.rectTransform.rect.width, (int)graphic.rectTransform.rect.height, 0 ); // 渲染元素 graphic.material = null; // 重置材质 GraphicCapture(graphic, rt); // 转换为Texture2D Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false); RenderTexture.active = rt; tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); tex.Apply(); RenderTexture.active = null; DestroyImmediate(rt); return tex; } // 渲染单个图形到RenderTexture void GraphicCapture(Graphic graphic, RenderTexture rt) { Material material = new Material(blendShader); material.mainTexture = graphic.mainTexture; material.color = graphic.color; Graphics.SetRenderTarget(rt); GL.PushMatrix(); GL.LoadOrtho(); material.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0, 0); GL.Vertex3(0, 0, 0); GL.TexCoord2(1, 0); GL.Vertex3(1, 0, 0); GL.TexCoord2(1, 1); GL.Vertex3(1, 1, 0); GL.TexCoord2(0, 1); GL.Vertex3(0, 1, 0); GL.End(); GL.PopMatrix(); } // 获取相对位置 Vector2 GetRelativePosition(RectTransform child, RectTransform parent) { Vector2 localPosition = child.anchoredPosition; // 处理锚点差异 Vector2 parentPivot = parent.pivot; Vector2 childAnchorMin = child.anchorMin; Vector2 parentSize = parent.rect.size; return new Vector2( localPosition.x + (childAnchorMin.x - parentPivot.x) * parentSize.x, localPosition.y + (childAnchorMin.y - parentPivot.y) * parentSize.y ); } // 混合单层 void BlendLayer(ref Texture2D baseTex, Texture2D blendTex, Vector2 position, RenderTexture rt) { Material blendMaterial = new Material(blendShader); blendMaterial.SetTexture("_BlendTex", blendTex); blendMaterial.SetVector("_Position", position); blendMaterial.SetFloat("_BlendMode", (float)blendMode); Graphics.Blit(baseTex, rt, blendMaterial); RenderTexture.active = rt; baseTex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); baseTex.Apply(); } // 保存为PNG void SaveTexture(Texture2D tex) { byte[] bytes = tex.EncodeToPNG(); string path = Path.Combine(Application.streamingAssetsPath, "Exports", fileName + ".png"); Directory.CreateDirectory(Path.GetDirectoryName(path)); File.WriteAllBytes(path, bytes); Debug.Log($"Saved to: {path}"); } } }