1.描述
我们在做项目的时候,美术会放很多shader在项目中,有一部分是没有用到的,想删又怕删错,会导致一些材质球丢shader,显示紫色。
今天就来想办法把多余的shader删干净。
2.分析
在写代码之前,先分析下思路。首先我们要分析shader会被哪些文件引用,我找到了下面的两种情况。
1.material 这种情况是最常规的,所有用到的材质球都会依赖自己的shader
2.scene 这种情况不多,但是也会有,一般是屏幕特效之类的东西,在相机上挂了一个脚本,然后脚本里面挂上shader,并没有产生材质球。
研究了一下发现,这种shader是依赖在scene文件中。
3.游戏的时候动态运用的shader,这种情况只要在c#文件中搜索,如果包含shader名字,说明shader是用到的。
3.思路
根据上面的分析,我们先整理出一个框架,然后再开始写代码,这是一个好的习惯,在写代码之前先用中文把思路表达清楚,写起来
就不会乱了,扯远了哈,继续说框架。
1.指定目录,一般只要在项目的某个路径里执行就可以了
1.查找出项目中所有的材质球,特点是文件名包含 “.mat”,将其文件路径加入到数组A
2.查找出项目中所有的scene,特点是文件名包含“.unity”,将其文件路径加入到数组B
3.查找出项目中所有的shader,特点是文件名包含“.shader”,将其文件路径加入到数组C
4.查找出c#文件使用的shader,将其加到数组C里面
5.通过shaderGuid将引用在mat和scene的shader找出来,将其加入数组D
6.通过数组C与D ,得出没有用到的shader路径,将其加入到数组E
7.删除E
这样我们就可以开始写代码了
4.代码
里面的代码全部是加上详细注释的,应该不难看懂
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; using System.Text.RegularExpressions; public class DelectShader : EditorWindow { private static List<string> matPahtList = new List<string>(); //所有的material路径数组 private static List<string> scenePathList = new List<string>();//所有的scene路径数组 private static List<string> allshaderPahtList = new List<string>();//所有shader路径数组 private static List<string> useShaderPathList = new List<string>();//所有用到的shader路径数组 private static List<string> noUseShaderList = new List<string>();//没用到shader路径 private static List<string> allCsPathList = new List<string>(); //所有c#数组 [MenuItem("Game-X/删除多余shader")] //菜单调用这个函数 static void GetNotQuoteShaderPath() { instantPathList(); //实例化三个数组:1 所有的shader 2 在材质球中用到的shader 3 在scene中用到的shader addMat(); // 将 在材质球中用到的shader + 到用到的shader数组里 addScene();// 将 在scene中用到的shader + 到用到的shader数组里 addCs(); // 将 在 c#中用到的shader + 到用到的shader数组里 noUseShader();//通过 “所有的shader” 和 “所有用到的shader” 得出没有用到的shader deletes();//删除没有用到的shader } //获取所有的shader 和 mat 和 scene的路径 static void instantPathList() { //Application.dataPath:Assets路径 这里相当于“Assets/resourcex” 项目里用到的shader跟mat只在这个文件夹里面 string path = Application.dataPath+ "/resourcex"; //Directory.GetFiles():得到所有这个路径里包含.shader的文件。 得到文件夹用Directory.GetDirectories(); allshaderPahtList = new List<string>(Directory.GetFiles(path, "*.shader", SearchOption.AllDirectories)); matPahtList = new List<string>(Directory.GetFiles(path, "*.mat", SearchOption.AllDirectories)); scenePathList = new List<string>(Directory.GetFiles(path, "*.unity", SearchOption.AllDirectories)); //因为c#文件不一定在resourcex下面,所以把路径设为整个Assets string pathCs = Application.dataPath; allCsPathList = new List<string>(Directory.GetFiles(pathCs, "*.cs", SearchOption.AllDirectories)); } /// <summary> /// 通过shader的路径获取Shader的guid 在下面的 addMat() 与 addScene()中取shaderGUID时使用 /// </summary> /// <param name="shaderPath"></param> /// <returns></returns> //通过shader的路径获取Shader的guid 在下面的 addMat() 与 addScene()中取shaderGUID时使用 static string FindShaderGuid(string shaderPath) { //得到shader guid的方法 return AssetDatabase.AssetPathToGUID(shaderPath); } /// 将材质用到的shader路径加到useShaderPathList数组里 //检查shaderGuid是否有引用在mat文件里 这个方法会在下面的addMat()方法中调用 static bool CheckGuidInMat(string shaderGuid) { for (int j = 0; j < matPahtList.Count; j++) { string matFilePath = matPahtList[j]; //搜索路径文件里是否包含 shaderguid,如果包含 则返回true if (Regex.IsMatch(File.ReadAllText(matFilePath), shaderGuid))//在文件里查找是否有shaderGuid return true; } return false; } //将材质用到的shader路径加到useShaderPathList数组里 static void addMat() { //遍历整个shader数组,将mat用到shader加到useShaderPathList数组里(要是里面没包含这个shader才需要加) for (int i = 0; i < allshaderPahtList.Count; i++) { //得到shader的guid string shaderGuid = FindShaderGuid(allshaderPahtList[i].Substring(allshaderPahtList[i].IndexOf("Assets"))); //如果shaderGuid不为空的时候 if (!string.IsNullOrEmpty(shaderGuid)) { //上面的方法CheckGuidInMat()返回为true if (CheckGuidInMat(shaderGuid)) { //如果useShaderPathList数组里没包含这个shader路径,将其加进数组 if (!useShaderPathList.Contains(allshaderPahtList[i])) useShaderPathList.Add(allshaderPahtList[i]); Debug.Log("材质球中用到的shader有:" + allshaderPahtList[i]); } } } } /// <summary> /// 将scene用到的shader路径加到useShaderPathList数组里 /// </summary> /// <param name="shaderGuid"></param> /// <returns></returns> //检查shaderGuid是否有引用在scene文件里 这个方法会在下面的addScene()方法中调用 static bool CheckGuidInScene (string shaderGuid) { for (int i = 0; i < scenePathList.Count; i++) { string SceneFilePath = scenePathList[i]; if (Regex.IsMatch(File.ReadAllText(SceneFilePath), shaderGuid)) return true; } return false; } //将scene用到的shader路径加到useShaderPathList数组里 static void addScene() { for (int i = 0; i < allshaderPahtList.Count; i++) { string shaderGuid = FindShaderGuid(allshaderPahtList[i].Substring(allshaderPahtList[i].IndexOf("Assets"))); if ((!string.IsNullOrEmpty(shaderGuid))) { if (CheckGuidInScene(shaderGuid)) { if (!useShaderPathList.Contains(allshaderPahtList[i])) { useShaderPathList.Add(allshaderPahtList[i]); Debug.Log("场景中用到的shader有:" + allshaderPahtList[i]); } } } } } /// <summary> /// 将所有cs用到的shader加入到数组 /// </summary> /// <param name="Name"></param> /// <returns></returns> //检查c#是否被shader引用 //因为c#跟shader没有guid依赖关系,说以要根据shader名来查找 static bool CheckNameCs (string Name) { //遍历c#数组,如果他包含指定的shader名,返回true for (int i = 0; i < allCsPathList.Count; i++) { string csPath = allCsPathList[i]; if (Regex.IsMatch(File.ReadAllText(csPath), Name)) return true; } return false; } //将所有cs用到的shader加入到数组 static void addCs() { for (int i = 0; i < allshaderPahtList.Count; i++) { //得到shader数组里的shader名(不包含扩展名 ,即“.”后面的名字) string Name = Path.GetFileNameWithoutExtension(allshaderPahtList[i]); //给上面的方法输入shader名,如果返回为true if (CheckNameCs(Name)) { //如果useShaderPathList没包含这个shader,将其加到useShaderPathList数组里 if (!useShaderPathList.Contains(allshaderPahtList[i])) { useShaderPathList.Add(allshaderPahtList[i]); Debug.Log("c#中用到的材质球有:" + allshaderPahtList[i]); } } } } //通过所有的shader路径 很已经用到的shader路径 得出没用到的shader路径 static void noUseShader() { //遍历allshaderPahtList路径 如果 useShaderPathList没包含 将加到noUseShaderList路径里 for (int i = 0; i < allshaderPahtList.Count; i++) { string shaderPath = allshaderPahtList[i]; if (!useShaderPathList.Contains(allshaderPahtList[i])) { if (!noUseShaderList.Contains(allshaderPahtList[i])) { noUseShaderList.Add(allshaderPahtList[i]); } } } } // 删除没有用到的shader static void deletes() { for (int i = 0; i < noUseShaderList.Count; i++) { Debug.Log("删除的shader有:" + noUseShaderList[i]); File.Delete(noUseShaderList[i]); } } }