511 lines
19 KiB
C#
511 lines
19 KiB
C#
|
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
|
|||
|
}
|
|||
|
}
|