FM/Assets/Test/MultiImageBlender.cs

214 lines
5.5 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System.IO;
public class MultiImageBlender : MonoBehaviour
{
[Header("Base Settings")] public RectTransform container;
public Shader blendShader;
public string fileName = "MultiBlendResult";
public string saveFolder = "Exports";
[Header("Advanced Settings")] [Tooltip("Render order: from bottom to top (child index)")]
public bool useHierarchyOrder = true;
public Vector2Int outputResolution = new Vector2Int(1024, 1024);
private List<Image> targetImages = new List<Image>();
private RenderTexture compositeRT;
[ContextMenu("Execute Blend Export")]
public void ExecuteBlendExport()
{
// 初始化目标列表
CollectImages();
// 创建渲染目标
CreateRenderTexture();
// 初始化画布
ClearRenderTexture(compositeRT, Color.clear);
// 混合所有图片
foreach (Image img in targetImages)
{
if (!img.gameObject.activeInHierarchy) continue;
if (img.sprite == null)
{
continue;
}
// 准备纹理数据
Texture2D coloredTex = ProcessImageTexture(img);
Vector2 offset = CalculatePositionOffset(img.rectTransform);
// 执行混合
BlendLayer(coloredTex, img.color, offset);
DestroyImmediate(coloredTex);
}
// 保存结果
SaveResult();
// 清理资源
ReleaseResources();
}
void CollectImages()
{
targetImages.Clear();
if (useHierarchyOrder)
{
// 按层级顺序收集(从底到顶)
foreach (Transform child in container)
{
CollectRecursive(child);
}
}
else
{
// 使用无序模式
Image[] images = container.GetComponentsInChildren<Image>();
targetImages.AddRange(images);
}
void CollectRecursive(Transform parent)
{
Image img = parent.GetComponent<Image>();
if (img != null) targetImages.Add(img);
foreach (Transform child in parent)
{
CollectRecursive(child);
}
}
}
Texture2D ProcessImageTexture(Image image)
{
// 获取原始纹理
Texture2D sourceTex = image.sprite.texture;
// 应用颜色
Color[] pixels = sourceTex.GetPixels();
for (int i = 0; i < pixels.Length; i++)
{
pixels[i] = pixels[i] * image.color;
}
// 创建新纹理
Texture2D coloredTex = new Texture2D(
sourceTex.width,
sourceTex.height,
sourceTex.format,
false
);
coloredTex.SetPixels(pixels);
coloredTex.Apply();
return coloredTex;
}
Vector2 CalculatePositionOffset(RectTransform rt)
{
// 将局部坐标转换为容器空间坐标
Vector2 anchoredPos = rt.anchoredPosition;
// 计算标准化偏移(相对于输出分辨率)
return new Vector2(
anchoredPos.x / outputResolution.x,
anchoredPos.y / outputResolution.y
);
}
void CreateRenderTexture()
{
if (compositeRT != null)
compositeRT.Release();
compositeRT = new RenderTexture(
outputResolution.x,
outputResolution.y,
24,
RenderTextureFormat.ARGB32
);
}
void ClearRenderTexture(RenderTexture rt, Color clearColor)
{
RenderTexture.active = rt;
GL.Clear(true, true, clearColor);
RenderTexture.active = null;
}
void BlendLayer(Texture2D sourceTex, Color blendColor, Vector2 offset)
{
Material blendMat = new Material(blendShader);
blendMat.SetTexture("_MainTex", sourceTex);
blendMat.SetColor("_BlendColor", blendColor);
blendMat.SetVector("_BlendOffset", offset);
// 临时RT用于混合
RenderTexture tempRT = RenderTexture.GetTemporary(
compositeRT.width,
compositeRT.height,
0,
compositeRT.format
);
// 复制当前状态
Graphics.Blit(compositeRT, tempRT);
// 执行混合
Graphics.Blit(tempRT, compositeRT, blendMat);
// 清理临时RT
RenderTexture.ReleaseTemporary(tempRT);
DestroyImmediate(blendMat);
}
void SaveResult()
{
Texture2D outputTex = new Texture2D(
compositeRT.width,
compositeRT.height,
TextureFormat.ARGB32,
false
);
RenderTexture.active = compositeRT;
outputTex.ReadPixels(new Rect(0, 0, compositeRT.width, compositeRT.height), 0, 0);
outputTex.Apply();
// 保存文件
string dirPath = Path.Combine(Application.dataPath, saveFolder);
Directory.CreateDirectory(dirPath);
string filePath = Path.Combine(dirPath, fileName + ".png");
File.WriteAllBytes(filePath, outputTex.EncodeToPNG());
Debug.Log($"导出成功:{filePath}");
DestroyImmediate(outputTex);
}
void ReleaseResources()
{
if (compositeRT != null)
{
compositeRT.Release();
DestroyImmediate(compositeRT);
}
Resources.UnloadUnusedAssets();
}
void OnDestroy()
{
ReleaseResources();
}
}