Files
Main/Assets/Launcher/ExternalLibs/ShaderGlobal/ShaderFactory.cs

511 lines
19 KiB
C#
Raw Normal View History

2025-01-25 04:38:09 +08:00
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
{
/// <summary>
/// Shader工厂
/// </summary>
[ExecuteAlways]
public class ShaderFactory : MonoBehaviour
{
[Header("重新刷新ShaderFactory中的Shader列表和变体的资源对象")]
public bool RefreshShaderList = false;
//不把变体保存了,先加进来,虽然现在来说可能没有什么用处.
[Header("将所有变体保存这里")]
[SerializeField]
private List<ShaderVariantCollection> _warmupVariantCollections;
[SerializeField]
private List<ShaderVariantCollection> _noWarmupVariantCollection;
[Header("将所有要用的shader绑定到此")]
[SerializeField]
private List<ShaderInfo> _shaders;
//属性名字
[Header("所有的属性名字和类型列表")]
[SerializeField]
private List<StringIntegerPair> _propertys;
//shader的字典
private Dictionary<string, Shader> _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<string, Shader> GetShaderTable()
{
if (_shaderDict == null && _shaders != null)
{
_shaderDict = new Dictionary<string, Shader>();
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<string, int> propertyCallBack = arr[0] as System.Action<string, int>;
System.Action<Shader, int[], Vector4[]> shaderInfoCallBack = arr[1] as System.Action<Shader, int[], Vector4[]>;
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<IntegerVectorPair, int>(si.Properties, x => { return x.Key; });
var v4 = Array.ConvertAll<IntegerVectorPair, Vector4>(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";
/// <summary>
/// 刷新Shader变体的集合
/// </summary>
private static List<Shader> Execute(List<ShaderVariantCollection> 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<ShaderVariantCollection> svc)
{
for (int i = 0; i < svc.Count; i++)
{
if (svc[i] != null)
{
svc[i].Clear();
}
}
svc.Clear();
}
/// <summary>
/// 创建一个ShaderVariantCollection资源
/// </summary>
/// <param name="shaderDir"></param>
/// <param name="svcpath"></param>
/// <param name="ignoreKeys"></param>
/// <param name="reset"></param>
private static List<Shader> Create(List<ShaderVariantCollection> svcList, string shaderDir, string svcpath, string[] ignoreSubDirs = null)
{
var shaderList = DoScanShader(shaderDir, ignoreSubDirs, new string[] { "Ares/SpecialEffect/FS_Shadow" });
var list = DoScanVariant(shaderList);
Dictionary<string, ShaderVariantCollection> dict = new Dictionary<string, ShaderVariantCollection>();
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<ShaderVariantCollection>(path);
if (svc == null)
{
svc = new ShaderVariantCollection();
UnityEditor.AssetDatabase.CreateAsset(svc, path);
svc = UnityEditor.AssetDatabase.LoadAssetAtPath<ShaderVariantCollection>(path);
}
dict[key] = svc;
}
dict[key].Add(sv);
}
svcList.AddRange(dict.Values);
UnityEditor.AssetDatabase.SaveAssets();
return shaderList;
}
private static List<Shader> DoScanShader(string shaderDir, string[] ignoreSubDirs = null, string[] appendShaders = null)
{
var outshaderList = new List<Shader>();
//查找目录中的所有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<Shader>(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<ShaderVariantCollection.ShaderVariant> DoScanVariant(List<Shader> shaderList)
{
List<ShaderVariantCollection.ShaderVariant> result = new List<ShaderVariantCollection.ShaderVariant>();
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' };
/// <summary>
/// 获取某个Shader的所有Keywords
/// </summary>
/// <param name="shader"></param>
/// <returns></returns>
public static List<string[]> GetShaderAllKeywords(Shader shader)
{
List<string[]> keySets = new List<string[]>();
int[] types;
string[] keywords;
GetShaderVariantEntries(shader, out types, out keywords);
if (keywords != null)
{
List<string[]> varList = new List<string[]>();
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;
}
/// <summary>
/// 获取当前Shader的所有变体, The GetShaderVariantEntries private method.
/// </summary>
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<Shader> allShaderList, out List<ShaderInfo> shaderPropertys, out List<StringIntegerPair> propertys)
{
shaderPropertys = new List<ShaderInfo>();
propertys = new List<StringIntegerPair>();
var propertyDict = new Dictionary<string, int>();
var propertyIndexDict = new Dictionary<string, int>();
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
}
}