using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; using UnityEngine; using UnityEngine.Gonbest.MagicCube; namespace Thousandto.Launcher.ExternalLibs { /// /// Shader工厂 /// [ExecuteAlways] public class ShaderFactory : MonoBehaviour { [Header("重新刷新ShaderFactory中的Shader列表和变体的资源对象")] public bool RefreshShaderList = false; //不把变体保存了,先加进来,虽然现在来说可能没有什么用处. [Header("将所有变体保存这里")] [SerializeField] private List _warmupVariantCollections; [SerializeField] private List _noWarmupVariantCollection; [Header("将所有要用的shader绑定到此")] [SerializeField] private List _shaders; //属性名字 [Header("所有的属性名字和类型列表")] [SerializeField] private List _propertys; //shader的字典 private Dictionary _shaderDict; #if UNITY_EDITOR && FUNCELL_LAUNCHER //是否使用当前工厂的Shader private bool _isUseFactoryShader = false; #else private bool _isUseFactoryShader = true; #endif void Awake() { if (_instance != null) { Debug.LogError("重复创建shaderFactory"); } _instance = this; } private void Start() { if (Application.isPlaying) { DontDestroyOnLoad(gameObject); } StartCoroutine(WarmupAllShaders()); } //重新制作所有的shader private IEnumerator WarmupAllShaders() { yield return null; if (_isUseFactoryShader) { for (int i = 0; i < _warmupVariantCollections.Count; i++) { _warmupVariantCollections[i].WarmUp(); yield return null; } } else { Shader.WarmupAllShaders(); } yield return null; } //获取Shader的字典 public Dictionary GetShaderTable() { if (_shaderDict == null && _shaders != null) { _shaderDict = new Dictionary(); if (_isUseFactoryShader) { for (int i = 0; i < _shaders.Count; i++) { if (_shaders[i] != null && _shaders[i].Shader != null) _shaderDict[_shaders[i].Shader.name] = _shaders[i].Shader; } Debug.Log("ShaderFactory生成了ShaderTable"); } } return _shaderDict; } //给运行时填充格式化数据使用. public void FillShaderInfo(object[] arr) { if (arr != null && arr.Length >= 2) { System.Action propertyCallBack = arr[0] as System.Action; System.Action shaderInfoCallBack = arr[1] as System.Action; if (propertyCallBack != null && shaderInfoCallBack != null) { for (int i = 0; i < _propertys.Count; i++) { propertyCallBack(_propertys[i].Key, _propertys[i].Value); } for (int i = 0; i < _shaders.Count; i++) { var si = _shaders[i]; if (si.Shader != null) { var tmpShader = si.Shader; if (!_isUseFactoryShader) { var shName = si.Shader.name; tmpShader = Shader.Find(shName); } var pi = Array.ConvertAll(si.Properties, x => { return x.Key; }); var v4 = Array.ConvertAll(si.Properties, x => { return x.Value; }); shaderInfoCallBack(tmpShader, pi, v4); } } } else { Debug.LogError("FillShaderInfo 回调函数为null"); } } else { Debug.LogError("FillShaderInfo 的参数为null"); } } #region//静态处理 //Shader工厂静态示例 private static ShaderFactory _instance = null; public static Shader Find(string shaderName) { if (_instance != null) { if (_instance._isUseFactoryShader) { var dict = _instance.GetShaderTable(); if (dict != null && dict.ContainsKey(shaderName)) { return dict[shaderName]; } } } return Shader.Find(shaderName); } #endregion #region // 编辑器使用 #if UNITY_EDITOR private void Update() { if (RefreshShaderList) { RefreshShaderList = false; ClearVariantCollect(_noWarmupVariantCollection); ClearVariantCollect(_warmupVariantCollections); var list = Execute(_warmupVariantCollections); for (int i = _warmupVariantCollections.Count - 1; i >= 0; i--) { if (_warmupVariantCollections[i].name.IndexOf("_Hidden") >= 0) { _noWarmupVariantCollection.Add(_warmupVariantCollections[i]); _warmupVariantCollections.RemoveAt(i); } } ProcessShader(list, out _shaders, out _propertys); } } public const string CN_SHADER_PATH = "Assets/GameAssets/RawResources/shader"; //Shader的集合文件 public const string CN_SHADER_VARIANT_COLLECTION_PATH = "Assets/GameAssets/Resources/Shader/ShaderCollect_{0}.shadervariants"; /// /// 刷新Shader变体的集合 /// private static List Execute(List svc) { var list = Create(svc, CN_SHADER_PATH, CN_SHADER_VARIANT_COLLECTION_PATH, new string[] { "Gonbest/Shadertoy/", "Gonbest/PBR/", "Gonbest/Legacy/", "Gonbest/Function/", "Gonbest/Experiment/", "Gonbest/Include/", "Base/", "External/T4M", }); return list; } private static void ClearVariantCollect(List svc) { for (int i = 0; i < svc.Count; i++) { if (svc[i] != null) { svc[i].Clear(); } } svc.Clear(); } /// /// 创建一个ShaderVariantCollection资源 /// /// /// /// /// private static List Create(List svcList, string shaderDir, string svcpath, string[] ignoreSubDirs = null) { var shaderList = DoScanShader(shaderDir, ignoreSubDirs, new string[] { "Ares/SpecialEffect/FS_Shadow" }); var list = DoScanVariant(shaderList); Dictionary dict = new Dictionary(); foreach (var sv in list) { var sName = sv.shader.name.Split('/'); var key = sName[0]; if (!dict.ContainsKey(key)) { var path = string.Format(svcpath, key); var svc = UnityEditor.AssetDatabase.LoadAssetAtPath(path); if (svc == null) { svc = new ShaderVariantCollection(); UnityEditor.AssetDatabase.CreateAsset(svc, path); svc = UnityEditor.AssetDatabase.LoadAssetAtPath(path); } dict[key] = svc; } dict[key].Add(sv); } svcList.AddRange(dict.Values); UnityEditor.AssetDatabase.SaveAssets(); return shaderList; } private static List DoScanShader(string shaderDir, string[] ignoreSubDirs = null, string[] appendShaders = null) { var outshaderList = new List(); //查找目录中的所有Shader文件 string[] files = System.IO.Directory.GetFiles(shaderDir, "*.shader", SearchOption.AllDirectories); foreach (var f in files) { var file = f.Replace('\\', '/'); //1.忽略的目录 bool ignore = false; if (ignoreSubDirs != null) { foreach (var sd in ignoreSubDirs) { if (file.IndexOf(sd) >= 0) { Debug.LogWarning("忽略Shader:" + file); ignore = true; break; } } } if (!ignore) { Debug.Log("开始处理Shader:" + file); var shader = UnityEditor.AssetDatabase.LoadAssetAtPath(file); if (shader != null) { outshaderList.Add(shader); } } } //另外追加的Shader if (appendShaders != null) { foreach (var sn in appendShaders) { var s = Shader.Find(sn); if (s != null) { var idx = outshaderList.IndexOf(s); if (idx < 0) { outshaderList.Add(s); } } } } return outshaderList; } //进行扫描Shader目录 private static List DoScanVariant(List shaderList) { List result = new List(); foreach (var shader in shaderList) { ShaderVariantCollection.ShaderVariant sv = new ShaderVariantCollection.ShaderVariant(); var svkeysList = GetShaderAllKeywords(shader); if (svkeysList.Count > 0) { foreach (var keys in svkeysList) { sv = new ShaderVariantCollection.ShaderVariant(); sv.shader = shader; sv.passType = UnityEngine.Rendering.PassType.Normal; sv.keywords = keys; result.Add(sv); } } // 说明他没有任何keyworld if (sv.shader == null) { sv = new ShaderVariantCollection.ShaderVariant(); sv.shader = shader; sv.passType = UnityEngine.Rendering.PassType.Normal; result.Add(sv); } } Debug.Log("ShaderVariantCollection Shader Count:" + result.Count); return result; } //处理Keyword分割的字符数组 private static char[] CN_SPLIT_CHAR_ARR = new char[] { ' ', '\t' }; /// /// 获取某个Shader的所有Keywords /// /// /// public static List GetShaderAllKeywords(Shader shader) { List keySets = new List(); int[] types; string[] keywords; GetShaderVariantEntries(shader, out types, out keywords); if (keywords != null) { List varList = new List(); foreach (var keys in keywords) { if (!string.IsNullOrEmpty(keys) && keys.IndexOf("FOG_EXP") < 0) { var arr = keys.Split(CN_SPLIT_CHAR_ARR, System.StringSplitOptions.RemoveEmptyEntries); keySets.Add(arr); } } } return keySets; } /// /// 获取当前Shader的所有变体, The GetShaderVariantEntries private method. /// private static void GetShaderVariantEntries(Shader shader, out int[] types, out string[] keywords) { var svc = new ShaderVariantCollection(); try { var param = new object[] { shader, svc, null, null }; typeof(UnityEditor.ShaderUtil).InvokeMember("GetShaderVariantEntries", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, param); types = (int[])param[2]; keywords = (string[])param[3]; } finally { UnityEngine.Object.DestroyImmediate(svc); svc = null; } } //分析Shader,并读取出所有的属性和类型 private static void ProcessShader(List allShaderList, out List shaderPropertys, out List propertys) { shaderPropertys = new List(); propertys = new List(); var propertyDict = new Dictionary(); var propertyIndexDict = new Dictionary(); foreach (var s in allShaderList) { if (s != null && !string.IsNullOrEmpty(s.name)) { Material mat = new Material(s); //获取属性的数量 int cnt = UnityEditor.ShaderUtil.GetPropertyCount(s); var defaultValueArr = new ShaderInfo(cnt); defaultValueArr.Shader = s; for (int i = 0; i < cnt; i++) { //获取属性名字 var name = UnityEditor.ShaderUtil.GetPropertyName(s, i); var stype = UnityEditor.ShaderUtil.GetPropertyType(s, i); //获取属性的类型 int type = (int)stype; int t; if (propertyDict.TryGetValue(name, out t)) { if (t != type) { //如果是Range和Float,那么就设定默认为Float if ((t == (int)UnityEditor.ShaderUtil.ShaderPropertyType.Float && type == (int)UnityEditor.ShaderUtil.ShaderPropertyType.Range) || (t == (int)UnityEditor.ShaderUtil.ShaderPropertyType.Range && type == (int)UnityEditor.ShaderUtil.ShaderPropertyType.Float)) { propertyDict[name] = (int)UnityEditor.ShaderUtil.ShaderPropertyType.Float; } else if (t > 100 && type == (t / 100)) { var td = (int)UnityEditor.ShaderUtil.GetTexDim(s, i); if (td != t % 100) { Debug.LogError("在Shader[" + s.name + "]中发现纹理属性" + name + "的维度是:" + td + ";;而其他的是" + (t % 100)); } } else { Debug.LogError("在Shader[" + s.name + "]中发现属性" + name + "是类型:" + type + ";;而其他的是" + t); } } } else { //如果类型是纹理型 if (type == (int)UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv) { var td = (int)UnityEditor.ShaderUtil.GetTexDim(s, i); type = type * 100 + td; } propertyDict[name] = type; propertys.Add(new StringIntegerPair() { Key = name, Value = type }); propertyIndexDict[name] = propertys.Count - 1; } Vector4 pDefaultVal = Vector4.zero; switch (stype) { case UnityEditor.ShaderUtil.ShaderPropertyType.Color: pDefaultVal = mat.GetColor(name); break; case UnityEditor.ShaderUtil.ShaderPropertyType.Vector: pDefaultVal = mat.GetVector(name); break; case UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv: { var to = mat.GetTextureOffset(name); var ts = mat.GetTextureScale(name); pDefaultVal = new Vector4(to.x, to.y, ts.x, ts.y); } break; case UnityEditor.ShaderUtil.ShaderPropertyType.Float: case UnityEditor.ShaderUtil.ShaderPropertyType.Range: pDefaultVal = new Vector4(mat.GetFloat(name), 0, 0, 0); break; } defaultValueArr.Properties[i] = new IntegerVectorPair() { Key = propertyIndexDict[name], Value = pDefaultVal }; } shaderPropertys.Add(defaultValueArr); GameObject.DestroyImmediate(mat, true); } else { shaderPropertys.Add(null); } } } #endif #endregion #region//子类定义 [System.Serializable] public class ShaderInfo { [SerializeField] public Shader Shader; [SerializeField] public IntegerVectorPair[] Properties; public ShaderInfo(int cnt) { Properties = new IntegerVectorPair[cnt]; } } #endregion } }