Framwork/Assets/Test/ImageHierarchyBlender.cs

175 lines
5.6 KiB
C#
Raw Normal View History

2025-05-23 16:24:00 +08:00
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}");
}
}
}