我不是歪神 2025-08-08 19:29 采纳率: 66.7%
浏览 5
已结题

脚本赋值shader贴图,贴图丢失问题qwq

下面这段代码效果是给有_Gradient属性的材质添加渐变纹理,有点小bug折腾了两天也没结果,希望大家帮忙康康了
,感谢了

问题描述:每次编译或者重启编辑器时shader里的_Gradient("Gradient",2D) = "black"{}这个贴图会丢失,但是脚本里创建的贴图文件还在,且可以正常被修改,而丢失后再次点击材质贴图又会回来


using System.IO;
using Unity.Plastic.Newtonsoft.Json;
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Material))]
public class GradientEditor : MaterialEditor
{
    private  string PropertiesGradient = "_Gradient";
    private Material material;
    private Gradient ColorGradient;
    private int Precisione = 512;
    public override void OnEnable()
    {
        base.OnEnable();
        material = null;
        ColorGradient = null;
        material = target as Material;
        if (material == null) return;
        if (!material.HasProperty(PropertiesGradient)) return;
        GradientExists();
    }
    public override void OnInspectorGUI()
    {
        if (material == null || !material.HasProperty(PropertiesGradient))
        {
            base.OnInspectorGUI();
            return;
        }
        if (material == null) return;
        if (material.HasProperty(PropertiesGradient))
        {
            
            ColorGradient = EditorGUILayout.GradientField("Gradient", ColorGradient);
            Precisione = EditorGUILayout.IntField("Precisione", Precisione);
            Precisione = Mathf.Clamp(Precisione, 18, 1024);
            GradientExists();
        }
        base.OnInspectorGUI();
    }
    void GradientExists()
    {
        string directoryPath = Path.Combine(Application.dataPath, "Gradient");
        if (!Directory.Exists(directoryPath))
        {
            Directory.CreateDirectory(directoryPath);
            AssetDatabase.Refresh();
        }
        string filePath = Path.Combine(directoryPath, material.name + "_Gradient.png");

        if (ColorGradient == null)
        {
            ColorGradient = new Gradient();
            if (File.Exists(filePath))
            {
                Texture2D texture2D = new Texture2D(1024, 2);
                texture2D.LoadImage(File.ReadAllBytes(filePath));
                GetGradient(texture2D);
            }
        }
        else
        {
            Texture2D tex = GetGradientColor2D();
            byte[] bytes = tex.EncodeToPNG();
            using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
            {
                fileStream.Write(bytes, 0, bytes.Length);
                fileStream.Close();
            }
            
            tex.LoadImage(File.ReadAllBytes(filePath));
            material.SetTexture(PropertiesGradient, tex);
        }
    }
    void GetGradient(Texture2D texture)
    {
        GradientColorKey[] colorKeys = new GradientColorKey[(int)(texture.GetPixel(0, 2).r * 8)];
        GradientAlphaKey[] alphaKeys = new GradientAlphaKey[(int)(texture.GetPixel(0, 2).g * 8)];
        for (int i = 0; i < 8; i++)
        {
            if(i < colorKeys.Length)
            {
                colorKeys[i].color = texture.GetPixel(i + 1, 2);
                colorKeys[i].time = texture.GetPixel(i + 1, 2).a;
            }
            if(i < alphaKeys.Length)
            {
                alphaKeys[i].alpha = texture.GetPixel(i + 9, 2).g;
                alphaKeys[i].time = texture.GetPixel(i + 9, 2).a;
            }
        }
        ColorGradient.SetKeys(colorKeys, alphaKeys);
        Precisione = (int)(texture.GetPixel(0, 2).b * 1024f);
    }
    Texture2D GetGradientColor2D()
    {
        Texture2D gradientColor2D = new Texture2D(Precisione, 2);

        Color[] newcolor = new Color[18];
        GradientColorKey[] colorKeys = ColorGradient.colorKeys;
        GradientAlphaKey[] alphaKeys = ColorGradient.alphaKeys;
        newcolor[0].r = colorKeys.Length / 8f;
        newcolor[0].g = alphaKeys.Length / 8f;
        newcolor[0].b = Precisione / 1024f;
        for (int i = 1; i < 9; i++)
        {
            if (i - 1 >= (int)(newcolor[0].r * 8)) break;
            newcolor[i] = colorKeys[i - 1].color;
            newcolor[i].a = colorKeys[i - 1].time;
        }
        for (int i = 9; i < 17; i++)
        {
            if (i - 9 >= (int)(newcolor[0].g * 8)) break;
            newcolor[i].g = alphaKeys[i - 9].alpha;
            newcolor[i].a = alphaKeys[i - 9].time;
        }
        for (int i = 0; i < 17; i++)
        {
            gradientColor2D.SetPixel(i, 2, newcolor[i]);
        }
        for (int i = 0; i < gradientColor2D.width; i++)
        {
            gradientColor2D.SetPixel(i, 1, ColorGradient.Evaluate(i / (float)(gradientColor2D.width - 1f)));
        }
        return gradientColor2D;
    }



}

目前推测出问题的地方是GradientExists()的else分支,但不知道怎么改,查找资料也没找到方法,感觉大家帮忙了awa

  • 写回答

5条回答 默认 最新

  • 一杯年华@编程空间 2025-08-08 22:32
    关注

    一杯年华@编程空间帮您解答,本答案结合 ChatGPT4.0和DeepSeek整理
    我曾经遇到过类似的问题,当时也是脚本给材质赋值贴图后,一编译或重启编辑器就丢失,折腾了很久才找到关键原因。

    从你的情况来看,问题核心其实和Unity的资源管理机制有关。贴图文件虽然还在,但材质没有正确“记住”这个贴图的关联,导致重新加载时找不到对应关系。具体来说,可能是这两个原因:一是材质的属性变更没有被Unity识别并保存,它不知道你已经修改了贴图;二是纹理的路径或命名逻辑有小问题,让Unity在重新加载时“认不出”原来的贴图。

    针对这个问题,有两种解决方案:

    第一种是确保材质能记录下属性变更。Unity里的材质默认不会主动记录所有修改,需要明确告诉它“这个材质变了,要保存”。只要让材质正确记录下贴图的赋值操作,重启或编译时就不会丢失了。

    第二种是优化纹理的路径和命名。如果贴图的路径不固定,或者不同材质生成的贴图重名了,Unity可能会混淆。可以让每个材质生成的贴图路径更唯一,比如包含材质的唯一标识,这样就不会找错贴图了。

    这两种方案里,最优的是第一种。因为核心问题是材质没记住贴图的关联,只要让材质正确保存变更,就能从根本上解决。很多时候,贴图丢失不是文件没了,而是材质“忘了”它,只要让材质“记住”这次修改,问题就迎刃而解了。而且这种方式不需要改动太多路径或命名逻辑,更直接有效。

    楼主可以试试从这两个方向调整,应该能解决问题。如果还有疑问,欢迎继续留言,我会尽力帮忙的,还请采纳呀。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

问题事件

  • 系统已结题 8月16日
  • 已采纳回答 8月8日
  • 创建了问题 8月8日