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]);
}
}
}
/// <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]);
}
}
}
亲,如果您觉得本文不错,愿意给我一些动力的话,请用手机扫描二维码即可向我打赏
打赏