unity中通过预制体生成Png图片

功能:在预制体编辑窗口选择带有MeshFilter的物体,预览窗口会显示截图按钮,可以将当前预览窗口中的图片保存为透明背景的Png格式图片

目前存在的问题:1.不能对整个预制体预览截图
2.灯光效果,不能像编辑器内置的那样跟随旋转(或者不应该转动相机)

在这里插入图片描述
在这里插入图片描述

using UnityEngine;
using UnityEditor;
using System.IO;

[CustomEditor(typeof(MeshFilter))]
[CanEditMultipleObjects]
public class MeshFilterPreview : Editor
{
    private PreviewRenderUtility m_PreviewRenderUtility;
    private MeshFilter m_TargetMeshFilter;
    private MeshRenderer m_TargetMeshRenderer;
    private static int sliderHash = "Slider".GetHashCode();
    private Vector2 m_Drag;
    Texture result_render;

    private void ValidateData()
    {
        if (m_PreviewRenderUtility == null)
        {
            m_PreviewRenderUtility = new PreviewRenderUtility();

            m_PreviewRenderUtility.camera.transform.position = new Vector3(0, 0, -6);
            m_PreviewRenderUtility.camera.transform.rotation = Quaternion.identity;
        }

        m_TargetMeshFilter = target as MeshFilter;       
        m_TargetMeshRenderer = m_TargetMeshFilter.GetComponent<MeshRenderer>();
    }

    public override bool HasPreviewGUI()
    {
        ValidateData();

        return true;
    }

    public override void OnPreviewGUI(Rect r, GUIStyle background)
    {
        m_Drag = Drag2D(m_Drag, r);

        if (Event.current.type == EventType.Repaint)
        {
            if (m_TargetMeshRenderer == null)
            {
                EditorGUI.DropShadowLabel(r, "Mesh Renderer Required");
            }
            else
            {
                m_PreviewRenderUtility.BeginPreview(r, background);

                m_PreviewRenderUtility.DrawMesh(m_TargetMeshFilter.sharedMesh, Matrix4x4.identity, m_TargetMeshRenderer.sharedMaterial, 0);


                var mesh = m_TargetMeshFilter.sharedMesh;
                var bounds = mesh.bounds;                           
                var cameraPos = bounds.center;

                m_PreviewRenderUtility.camera.transform.position = Vector2.zero;
                m_PreviewRenderUtility.camera.transform.rotation = Quaternion.Euler(new Vector3(-m_Drag.y, -m_Drag.x, 0));

                float cameraDis = bounds.center.y / Mathf.Tan(Mathf.Deg2Rad * 4);               

                m_PreviewRenderUtility.camera.transform.position = m_PreviewRenderUtility.camera.transform.forward * -cameraDis + Vector3.up*mesh.bounds.center.y;
                m_PreviewRenderUtility.camera.Render();

                result_render = m_PreviewRenderUtility.EndPreview();
                GUI.DrawTexture(r, result_render, ScaleMode.StretchToFill, false);
            }
        }
    }

    public override void OnPreviewSettings()
    {
        if (GUILayout.Button("Reset Camera", EditorStyles.miniButtonLeft))
        {
            m_Drag = Vector2.zero;
        }
        else if (GUILayout.Button("截图", EditorStyles.miniButtonRight))
        {
            PreviewShot();
        }
    }

    private void OnDisable()
    {
        if (m_PreviewRenderUtility != null)
        {
            m_PreviewRenderUtility.Cleanup();
        }
    }

    public static Vector2 Drag2D(Vector2 scrollPosition, Rect position)
    {
        int controlID = GUIUtility.GetControlID(sliderHash, FocusType.Passive);
        Event current = Event.current;
        switch (current.GetTypeForControl(controlID))
        {
            case EventType.MouseDown:
                if (position.Contains(current.mousePosition) && position.width > 50f)
                {
                    GUIUtility.hotControl = controlID;
                    current.Use();
                    EditorGUIUtility.SetWantsMouseJumping(1);
                }

                break;
            case EventType.MouseDrag:
                if (GUIUtility.hotControl == controlID)
                {
                    scrollPosition -= current.delta * ((!current.shift) ? 1 : 3) / Mathf.Min(position.width, position.height) * 140f;
                    current.Use();
                    GUI.changed = true;
                }

                break;
            case EventType.MouseUp:
                if (GUIUtility.hotControl == controlID)
                {
                    GUIUtility.hotControl = 0;
                }

                EditorGUIUtility.SetWantsMouseJumping(0);
                break;
        }

        return scrollPosition;
    }

    private void PreviewShot()
    {
        var name = Selection.gameObjects[0].name;
        string path = "/Resources/PreviewShot/";

        if (!System.IO.Directory.Exists(Application.dataPath + path))
        {
            System.IO.Directory.CreateDirectory(Application.dataPath + path);
        }

        Texture2D texture2D = TextureToTexture2D(result_render);

        int offsetx = Mathf.RoundToInt((texture2D.width - 512)/2);
        int offsetY = Mathf.RoundToInt((texture2D.height - 512)/2);
        texture2D = TextureCutOut(texture2D,offsetx,offsetY,512,512);

        SaveTexture(texture2D,path,name);

        Application.OpenURL(Application.dataPath + path);       
    }

    
    private Texture2D TextureToTexture2D(Texture texture)
    {
        Texture2D texture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);         
        RenderTexture currentRT = RenderTexture.active;
        RenderTexture renderTexture = RenderTexture.GetTemporary(texture.width, texture.height, 32);
        Graphics.Blit(texture, renderTexture);

        RenderTexture.active = renderTexture;
        texture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
        
        texture2D.Apply();

        RenderTexture.active = currentRT;
        RenderTexture.ReleaseTemporary(renderTexture);
        

        return texture2D;
    }

    private void SaveTexture(Texture2D texture2D,string path,string name)
    {
        //保存图片
        byte[] dataBytes = texture2D.EncodeToPNG();
        string savePath = Application.dataPath + path +name+".png";
        FileStream fileStream = File.Open(savePath, FileMode.OpenOrCreate);
        fileStream.Write(dataBytes, 0, dataBytes.Length);
        fileStream.Close();
        UnityEditor.AssetDatabase.SaveAssets();
        UnityEditor.AssetDatabase.Refresh();
    } 

    public static Texture2D TextureCutOut(Texture2D originalTexture, int offsetX, int offsetY, float originalWidth, float originalHeight)
    {
        Texture2D newTexture = new Texture2D(Mathf.CeilToInt(originalWidth), Mathf.CeilToInt(originalHeight));
        int maxX = originalTexture.width - 1;
        int maxY = originalTexture.height - 1;
        for (int y = 0; y < newTexture.height; y++)
        {
            for (int x = 0; x < newTexture.width; x++)
            {
                float targetX = x + offsetX;
                float targetY = y + offsetY;
                int x1 = Mathf.Min(maxX, Mathf.FloorToInt(targetX));
                int y1 = Mathf.Min(maxY, Mathf.FloorToInt(targetY));
                int x2 = Mathf.Min(maxX, x1 + 1);
                int y2 = Mathf.Min(maxY, y1 + 1);

                float u = targetX - x1;
                float v = targetY - y1;
                float w1 = (1 - u) * (1 - v);
                float w2 = u * (1 - v);
                float w3 = (1 - u) * v;
                float w4 = u * v;
                Color color1 = originalTexture.GetPixel(x1, y1);
                Color color2 = originalTexture.GetPixel(x2, y1);
                Color color3 = originalTexture.GetPixel(x1, y2);
                Color color4 = originalTexture.GetPixel(x2, y2);
                Color color = new Color(Mathf.Clamp01(color1.r * w1 + color2.r * w2 + color3.r * w3 + color4.r * w4),
                                        Mathf.Clamp01(color1.g * w1 + color2.g * w2 + color3.g * w3 + color4.g * w4),
                                        Mathf.Clamp01(color1.b * w1 + color2.b * w2 + color3.b * w3 + color4.b * w4),
                                        Mathf.Clamp01(color1.a * w1 + color2.a * w2 + color3.a * w3 + color4.a * w4)
                                        );
                newTexture.SetPixel(x, y, color);
            }
        }
        newTexture.anisoLevel = 2;
        newTexture.Apply();
        return newTexture;
    }
}

### 实现物体的镜像对称 在 Unity 中实现物体的镜像对称可以通过多种方式完成,具体取决于所处理的对象类型以及所需的精度。 对于 UI 元素而言,可以利用 `RectTransformUtility` 提供的功能来改变布局轴向从而达到视觉上的翻转效果[^1]: ```csharp using UnityEngine; using UnityEngine.UI; public class UtilityTest : MonoBehaviour { public RectTransform rectTransform; // 在 Inspector 中设置要翻转的 UI 元素 void Start() { RectTransformUtility.FlipLayoutAxes(rectTransform, true, false); } } ``` 而对于一般的 GameObject 或者 Mesh 对象,则可能需要更复杂的变换逻辑。一种方法是在编辑器外部工具如 Blender 中先做预处理再导回引擎;另一种则是通过脚本动态调整 Transform 属性或修改顶点数据以达成即时反射的效果[^3]。 如果目标是让图像组件呈现出水平或垂直方向上的镜像显示,还可以自定义继承自 `Image` 的类并覆盖其绘制行为,在其中应用相应的矩阵转换[^4]: ```csharp protected override void OnPopulateMesh(VertexHelper vh) { base.OnPopulateMesh(vh); List<UIVertex> vertices = new List<UIVertex>(); vh.GetRawVertices(vertices); foreach (var vertex in vertices) { Vector2 position = vertex.position; // 假设这里要做横向镜像 float width = GetComponent<RectTransform>().rect.width; position.x = -(position.x - width / 2f) + width / 2f; vertex.position = position; } vh.Clear(); vh.AddUIVertexStream(vertices); } ``` 上述代码片段展示了如何通过对顶点坐标的重新计算使图片沿 X 轴发生反转。当然这只是一个基本的例子,实际项目里或许还需要考虑更多细节比如锚点位置的影响等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值