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}");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|