175 lines
5.6 KiB
C#
175 lines
5.6 KiB
C#
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<Graphic> 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<Graphic> GetAllGraphics(GameObject parent)
|
||
{
|
||
List<Graphic> graphics = new List<Graphic>();
|
||
Graphic parentGraphic = parent.GetComponent<Graphic>();
|
||
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}");
|
||
}
|
||
}
|
||
} |