有些需求是一键替换模型中的一些shader,这个工具是给美术使用的,只需要填写要替换的sheder名字,和新的名字即可。
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
//一键替换模型上的Shader
public class AutoReplaceShader
{
#region 旧版更换shader工具,要在代码中更换地址
static Shader newShader; //要替换的很挫的shader 路径: Assets/Resources/Shaders/Normal-Diffuse.shader
static string newShaderPath = "Assets/Resources/Shaders/Normal-Diffuse.shader"; //要更换的新shader地址(自定义shader)
static string newShaderName = "Mobile/Diffuse"; //要更换的系统shader路径
//白名单
static string[] writeModelList = { "three004", "parrot_ctrl" }; //如果一个物体,交这个名字,则不更换shader
//黑名单
static string[] blackShaderList = { "MXR_multy_Texture_alphaTest2Side", "Diffuse" }; //如果一个Shader的名字包含这些关键词,则就要被替换掉
static int changeNum; //更换shader的数量
//[MenuItem("Tools/替换Shader")]
public static void ReplaceShader()
{
//1、必须将模型的已生成的预制体Model拖到Actor下面
GameObject model = GameObject.Find("Actor/Model").gameObject;
newShader = AssetDatabase.LoadAssetAtPath(newShaderPath, typeof(Shader)) as Shader;
changeNum = 0;
MeshRenderer[] meshRs = model.GetComponentsInChildren<MeshRenderer>();
for (int i = 0; i < meshRs.Length; ++i)
{
ChangeShader(meshRs[i].gameObject, meshRs[i].sharedMaterials);
}
SkinnedMeshRenderer[] skins = model.GetComponentsInChildren<SkinnedMeshRenderer>();
for (int i = 0; i < skins.Length; ++i)
{
ChangeShader(skins[i].gameObject, skins[i].sharedMaterials);
}
AssetDatabase.Refresh();
Debug.Log("Changer " + changeNum + " shaders over.");
}
//更换材质上的shader
static void ChangeShader(GameObject model, Material[] modelMaters)
{
for (int i = 0; i < writeModelList.Length; ++i)
{
if (writeModelList[i] == model.name)
{
//白名单的物体不修改shader
return;
}
}
for (int i = 0; i < modelMaters.Length; ++i)
{
for (int j = 0; j < blackShaderList.Length; ++j)
{
if (!modelMaters[i].shader.name.Contains(blackShaderList[j]))
{
//只有进黑名单的物体才要更换shader
continue;
}
Debug.Log("Change " + model.name + " shader: " + modelMaters[i].shader.name);
//modelMaters[i].shader = Shader.Find(newShaderName);
modelMaters[i].shader = Shader.Find(newShaderName);
changeNum++;
}
}
}
#endregion
#region 新版可编辑修改shader名单
[MenuItem("Tools/自定义替换Shader")]
static void ShowReplaceShaderWindow()
{
ReplaceShaderWindow shaderWin = EditorWindow.GetWindow<ReplaceShaderWindow>("批量替换Shader界面", true);
shaderWin.Show();
}
#endregion
}
public class ReplaceShaderWindow : BaseEditWindow
{
//将数据记录下来
string infoPath = "Assets/Resources/DllTest/ShaderReplaceData.asset"; //名字一定要跟类名保持一致,否则报错
public static ReplaceShaderWindow _Instance;
ShaderReplaceData srData; //自定义名单数据
UnityEngine.Object SelectObj; //当前选择要修改shader的模型
string shaderPath = "Assets/Resources/Shaders/"; //本地shader的存放路径 例如:"Assets/Resources/Shaders/Normal-Diffuse.shader"
int whiteNum; //白名单的数量
int blackNum; //黑名单的数量
int changeNum; //更换shader的数量
Dictionary<string, string> blackDic = new Dictionary<string, string>(); //将黑名单list转成字典,方便使用
protected override void Init()
{
_Instance = this;
GetAssetData();
whiteNum = srData.whiteList.Count;
blackNum = srData.blackList.Count;
}
protected override void OnGUI()
{
base.OnGUI();
GUILayout.Label("\t\t注意事项\n\n1: 黑名单中必须填写两个shader的名字,前面是要被替换的名字,后面是新的shader名字\n" +
"2: 要替换的物体和白名单的物体,不要使用同一个material,否则白名单不起作用!\n" +
"3: 白名单中填写不替换shader的物体名字");
GUILayout.Space(50);
if (GUILayout.Button(new GUIContent("替换", "编辑替换shader")))
{
//替换shader todo
if (CheckBlackListFormat(srData.blackList))
{
StartReplaceShader();
SaveAssetData();
//关闭
_Instance = null;
Close();
}
}
}
protected override void OnShowGUI()
{
#region white list
whiteNum = EditorGUILayout.IntField(new GUIContent("白名单数量: ", "动画切割的数量"), whiteNum);
//数据比较少,则缩短集合长度
if (whiteNum < srData.whiteList.Count)
{
//数量不一致时,先处理集合
for (int i = whiteNum; i < srData.whiteList.Count; ++i)
{
srData.whiteList.Remove(srData.whiteList[i]);
}
}
for (int i = 0; i < whiteNum; i++)
{
//如果之前数据不够,则先增加集合长度再赋值
if (i + 1 > srData.whiteList.Count)
{
srData.whiteList.Add("");
}
srData.whiteList[i] = EditorGUILayout.TextField(new GUIContent(i + ": ", "动画切割的数量"), srData.whiteList[i]);
}
EditorGUILayout.Space();
EditorGUILayout.Space();
#endregion
#region black list
blackNum = EditorGUILayout.IntField(new GUIContent("黑名单数量: ", "动画切割的数量"), blackNum);
//数据比较少,则缩短集合长度
if (blackNum < srData.blackList.Count)
{
//数量不一致时,先处理集合
for (int i = blackNum; i < srData.blackList.Count; ++i)
{
srData.blackList.Remove(srData.blackList[i]);
}
}
for (int i = 0; i < blackNum; i++)
{
//如果之前数据不够,则先增加集合长度再赋值
if (i + 1 > srData.blackList.Count)
{
srData.blackList.Add("");
}
srData.blackList[i] = EditorGUILayout.TextField(new GUIContent(i + ": ", "动画切割的数量"), srData.blackList[i]);
}
#endregion
}
protected override void OnClose()
{
}
void SaveAssetData()
{
ShaderReplaceData data = ScriptableObject.CreateInstance<ShaderReplaceData>();
data.blackList = srData.blackList;
data.whiteList = srData.whiteList;
AssetDatabase.DeleteAsset(infoPath);
AssetDatabase.CreateAsset(data, infoPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log(infoPath + " save over");
}
void GetAssetData()
{
srData = AssetDatabase.LoadAssetAtPath<ShaderReplaceData>(infoPath);
if (srData == null)
{
srData = ScriptableObject.CreateInstance<ShaderReplaceData>();
Debug.Log("new ShaderReplaceData");
}
//Debug.Log("get data over");
}
//检查黑名单格式是否正确 正确格式"Mobile/Diffuse,UI/Default"
bool CheckBlackListFormat(List<string> list)
{
blackDic.Clear();
//不能为空
if (list == null || list.Count <= 0)
{
Debug.Log("no shader replace");
return false;
}
//必须包含“,”
for (int i = 0; i < list.Count; i++)
{
if (!list[i].Contains(","))
{
Debug.Log(list[i] + ": lack , Please check it");
return false;
}
}
//必须有原始shader和替换shader
for (int i = 0; i < list.Count; i++)
{
string[] temp = list[i].Split(',');
if (temp.Length != 2)
{
Debug.Log(list[i] + ": not right,you must write 2 shader name");
return false;
}
if (string.IsNullOrEmpty(temp[0]) || string.IsNullOrEmpty(temp[0]))
{
Debug.Log(list[i] + ": not right,shader name can not empty");
return false;
}
//将数据放入字典中方便使用
if (!blackDic.ContainsKey(temp[0]))
{
blackDic.Add(temp[0], temp[1]);
}
else
{
//要替换的shader名字不能重复
Debug.Log(list[i] + ": name is repeat");
return false;
}
}
return true;
}
//替换shader
void StartReplaceShader()
{
//替换前需要手动选中模型,如果一次性选择很多物体,则默认是第一个
SelectObj = Selection.activeObject;
GameObject model = SelectObj as GameObject;
changeNum = 0;
if (model == null)
{
Debug.Log("请先在Hierarchy面板中选中要替换的模型");
return;
}
MeshRenderer[] meshRs = model.GetComponentsInChildren<MeshRenderer>();
for (int i = 0; i < meshRs.Length; ++i)
{
ChangeShader(meshRs[i].gameObject, meshRs[i].sharedMaterials);
}
SkinnedMeshRenderer[] skins = model.GetComponentsInChildren<SkinnedMeshRenderer>();
for (int i = 0; i < skins.Length; ++i)
{
ChangeShader(skins[i].gameObject, skins[i].sharedMaterials);
}
AssetDatabase.Refresh();
Debug.Log("Changer " + changeNum + " shaders over.");
}
//更换材质上的shader,一次只替换一个
void ChangeShader(GameObject model, Material[] modelMaters)
{
for (int i = 0; i < srData.whiteList.Count; ++i)
{
if (srData.whiteList[i] == model.name)
{
//白名单的物体不修改shader
return;
}
}
for (int i = 0; i < modelMaters.Length; ++i)
{
if (!blackDic.ContainsKey(modelMaters[i].shader.name))
{
//如果不包含在黑名单中,就不用替换这个shader
continue;
}
Debug.Log("Change " + model.name + " shader: " + modelMaters[i].shader.name);
//因为不知道shader是本地还是系统shader,这里就先从本地查找是否有这个shader
Shader shader = AssetDatabase.LoadAssetAtPath(shaderPath + blackDic[modelMaters[i].shader.name], typeof(Shader)) as Shader;
if (shader == null)
{
//本地shader找不到,就再次尝试使用系统shader "UI/Defualt"
shader = Shader.Find(blackDic[modelMaters[i].shader.name]);
}
if (shader != null)
{
modelMaters[i].shader = shader;
changeNum++;
Debug.Log("success replace shader: " + modelMaters[i].shader.name);
}
else
{
Debug.LogError(modelMaters[i].shader.name + " not find!!!");
}
}
}
}
public class ShaderReplaceData : ScriptableObject
{
public List<string> whiteList = new List<string>(); //白名单,填写Hierarchy面板下物体的名字 "WordTagPlayer"
public List<string> blackList = new List<string>(); //旧名字和新名字,中间用逗号分隔,后面的是新shader名字: "Custom/MXR_multy_Texture_alphaTest2Side,UI/Default,"
}
加载本地shader和加载系统shader方式是不一样的。
该博客介绍了一款专为美术设计的工具,能够方便地一键替换Unity模型中的Shader。使用者只需输入旧Shader名称和新Shader名称,即可完成替换操作。文章强调了处理本地Shader与系统Shader的不同方法。
314

被折叠的 条评论
为什么被折叠?



