/// <summary> /// 按shader进行剔除 /// </summary> /// <returns>如果需要放弃本次处理,返回true</returns> private bool DoExcludeShader(ShaderKeywordConfig config, Shader currentShader) { Shader[] e = config.ExcludeShader; if (e == null) { return(false); } for (int i = 0; i < e.Length; i++) { if (e[i] == currentShader) { return(true); } } return(false); }
private void DoCreate(BuildTarget materialBuildTarget) { if (exceptionSB == null) { exceptionSB = new StringBuilder(); } else { exceptionSB.Clear(); } //计时开始 System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); if (!writeToFile) { ShaderVariantCollection svc = new ShaderVariantCollection(); currentSVC = svc; svcToShow = svc; AssetDatabase.CreateAsset(svc, m_svcPath); } currentConfig = excludeConfig; isCreating = true; dataDictionary = new Dictionary <Shader, HashSet <string> >(); int totalMaterialsCount = 0; int removedFBXCount = 0; int removedErrorMaterialsCount = 0; int finalMaterialsCount = 0; //Resources目录下的所有材质 string[] guidMats = AssetDatabase.FindAssets("t:Material", new string[] { m_materialsPath }); totalMaterialsCount = guidMats.Length; List <string> assetNameList = new List <string>(); //移除空材质、错误材质和嵌入材质附带的FBX文件 for (int i = 0; i < guidMats.Length; i++) { EditorUtility.DisplayProgressBar("正在扫描材质", i + " / " + guidMats.Length, i * 1.0f / guidMats.Length); string an = AssetDatabase.GUIDToAssetPath(guidMats[i]); if (string.Equals(Path.GetExtension(an), ".fbx", StringComparison.OrdinalIgnoreCase)) { removedFBXCount++; continue; } Material mat = (Material)AssetDatabase.LoadAssetAtPath(an, typeof(Material)); if (mat == null || mat.shader == null) { removedErrorMaterialsCount++; continue; } assetNameList.Add(an); #if DEBUG_ON Debug.Log("Add: " + an); #endif } // Create the array of bundle build details. AssetBundleBuild buildMap = new AssetBundleBuild { assetBundleName = abName, assetNames = assetNameList.ToArray(), }; AssetBundleBuild[] buildMapArray = new AssetBundleBuild[1]; buildMapArray[0] = buildMap; EditorUtility.ClearProgressBar(); finalMaterialsCount = buildMap.assetNames.Length; if (!Directory.Exists(m_tempPath)) { Directory.CreateDirectory(m_tempPath); } BuildPipeline.BuildAssetBundles(m_tempPath, buildMapArray, BuildAssetBundleOptions.None, materialBuildTarget); if (writeToFile) { //StreamWriter第二个参数为false覆盖现有文件,为true则把文本追加到文件末尾 using (StreamWriter file = new StreamWriter(m_txtPath, false)) { foreach (KeyValuePair <Shader, HashSet <string> > kvp in dataDictionary) { file.WriteLine("Shader: " + kvp.Key.name); HashSet <string> v = kvp.Value; foreach (string kws in v) { file.WriteLine(kws); } } file.Close(); } } if (autoDeleteTempFolder) { #if DEBUG_ON Debug.Log("Delete temp bundle"); #endif DeleteTempFolder(); } //计时结束 stopwatch.Stop(); TimeSpan timespan = stopwatch.Elapsed; isCreating = false; currentSVC = null; currentConfig = null; ClearOutput(); outputSB.AppendLine("创建完成,耗时: " + timespan.Hours + "h," + timespan.Minutes + "m," + timespan.Seconds + "s"); outputSB.AppendLine("已扫描材质数量: " + totalMaterialsCount); outputSB.AppendLine("移除FBX数量: " + removedFBXCount); outputSB.AppendLine("移除错误材质数量: " + removedErrorMaterialsCount); outputSB.AppendLine("最终材质数量: " + finalMaterialsCount); if (!writeToFile) { ShowSVCInfo(); } AssetDatabase.SaveAssets(); }
/// <inheritdoc /> public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList <ShaderCompilerData> data) { if (!ShaderVariantCollectionGenerator3.IsCreating) { return; } #if DEBUG_ON Debug.Log("SVCG_ShaderPreprocessor.OnProcessShader(" + shader.name + ")"); #endif ShaderVariantCollection svc = ShaderVariantCollectionGenerator3.CurrentSVC; if (!ShaderVariantCollectionGenerator3.WillWriteToFile && svc == null) { return; } //处理剔除配置 if (ShaderVariantCollectionGenerator3.CurrentConfig != null) { EditorUtility.DisplayProgressBar("正在执行剔除", $"Shader: {shader.name}", 0); ShaderKeywordConfig config = ShaderVariantCollectionGenerator3.CurrentConfig; if (DoExcludeShader(config, shader)) { return; } EditorUtility.DisplayProgressBar("正在执行剔除", $"Shader: {shader.name}", 0.3333f); if (DoExclude(config.GetGlobalConfig(), snippet, data)) { return; } EditorUtility.DisplayProgressBar("正在执行剔除", $"Shader: {shader.name}", 0.6666f); if (DoExclude(config.GetConfigOfShader(shader), snippet, data)) { return; } EditorUtility.DisplayProgressBar("正在执行剔除", $"Shader: {shader.name}", 1); } for (int i = 0; i < data.Count; i++) { EditorUtility.DisplayProgressBar("正在处理变体", $"Shader: {shader.name}, data: {i}/{data.Count}", (float)i / data.Count); ShaderKeyword[] kws = data[i].shaderKeywordSet.GetShaderKeywords(); if (ShaderVariantCollectionGenerator3.WillWriteToFile) { string[] strKWs = new string[kws.Length + 1]; strKWs[0] = ((int)snippet.passType).ToString(); for (int j = 1; j < kws.Length + 1; j++) { #if UNITY_2019_3_OR_NEWER strKWs[j] = ShaderKeyword.GetKeywordName(shader, kws[j - 1]); #else strKWs[j] = kws[j - 1].GetKeywordName(); #endif } HashSet <string> d = null; if (ShaderVariantCollectionGenerator3.DataDictionary.TryGetValue(shader, out d)) { d.Add(DebugUtil.LogString(strKWs)); } else { d = new HashSet <string>(); d.Add(DebugUtil.LogString(strKWs)); ShaderVariantCollectionGenerator3.DataDictionary.Add(shader, d); } #if DEBUG_ON Debug.Log("file.Add(" + DebugUtil.LogString(strKWs) + ")"); #endif } else { string[] strKWs = new string[kws.Length]; for (int j = 0; j < kws.Length; j++) { #if UNITY_2019_3_OR_NEWER strKWs[j] = ShaderKeyword.GetKeywordName(shader, kws[j]); #else strKWs[j] = kws[j].GetKeywordName(); #endif } #if DEBUG_ON Debug.Log("svc.Add(" + shader + ", " + snippet.passType + ", " + DebugUtil.LogString(strKWs) + ")"); #endif if (ShaderVariantCollectionGenerator3.StopOnException) { svc.Add(new ShaderVariantCollection.ShaderVariant(shader, snippet.passType, strKWs)); } else { //不使用构造函数可以避免调用 ShaderVariantCollection.ShaderVariant.CheckShaderVariant //它将耗费大量时间来判断输入数据是否存在异常 ShaderVariantCollection.ShaderVariant sv = new ShaderVariantCollection.ShaderVariant(); sv.shader = shader; sv.passType = snippet.passType; sv.keywords = strKWs; svc.Add(sv); } } } //实际打包时不编译shader变体,仅收集信息,大幅优化执行时间 data.Clear(); }
void OnGUI() { GUILayout.Space(5); GUIStyle logoFont = new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleCenter, fontSize = 20 }; GUILayout.Label("ShaderVariantCollectionGenerator", logoFont); GUILayout.Space(10); GUILayout.Label("扫描材质路径(可以拖入文件夹自动获取)"); EditorGUILayout.BeginHorizontal(); { EditorGUI.BeginChangeCheck(); pathObj = EditorGUILayout.ObjectField(pathObj, typeof(UnityEngine.Object), false, GUILayout.Width(110)); if (EditorGUI.EndChangeCheck()) { m_materialsPath = AssetDatabase.GetAssetPath(pathObj); //判断是否为斜杠结尾,搜索的文件夹不能用斜杠结尾 if (m_materialsPath.EndsWith("/")) { m_materialsPath = m_materialsPath.Remove(m_materialsPath.Length - 2, 1); } pathObj = null; } m_materialsPath = EditorGUILayout.TextField(m_materialsPath); } EditorGUILayout.EndHorizontal(); GUILayout.Space(10); GUILayout.Label("生成变体文件路径"); m_svcPath = EditorGUILayout.TextField(m_svcPath); svcToShow = (ShaderVariantCollection)EditorGUILayout.ObjectField("ShaderVariantCollection", svcToShow, typeof(ShaderVariantCollection), false); GUILayout.Space(10); GUILayout.Label("剔除配置文件路径"); configPath = EditorGUILayout.TextField(configPath); excludeConfig = (ShaderKeywordConfig)EditorGUILayout.ObjectField("ExcludeKeywordConfig", excludeConfig, typeof(ShaderKeywordConfig), false); GUILayout.Space(10); GUILayout.Label("临时文件夹路径,不能用斜杠结尾"); m_tempPath = EditorGUILayout.TextField(m_tempPath); GUILayout.Space(10); GUILayout.Label("文本文件路径"); m_txtPath = EditorGUILayout.TextField(m_txtPath); GUILayout.Space(10); m_materialBuildTarget = (BuildTarget)EditorGUILayout.EnumPopup("MaterialBuildTarget", m_materialBuildTarget); GUILayout.Space(10); stopOnException = EditorGUILayout.ToggleLeft("异常时中断执行,严重增加运行时间", stopOnException); autoDeleteTempFolder = EditorGUILayout.ToggleLeft("自动清除临时文件夹", autoDeleteTempFolder); writeToFile = EditorGUILayout.ToggleLeft("结果写入文本文件,不生成变体", writeToFile); const int buttonHeight = 40; EditorGUILayout.BeginHorizontal(); { if (GUILayout.Button("自动获取 KeywordConfig", GUILayout.Height(buttonHeight))) { excludeConfig = (ShaderKeywordConfig)AssetDatabase.LoadAssetAtPath(configPath, typeof(ShaderKeywordConfig)); if (excludeConfig == null) { EditorUtility.DisplayDialog("SVCG", "文件不存在或无法加载", "哦"); } } if (GUILayout.Button("创建 KeywordConfig", GUILayout.Height(buttonHeight))) { if (File.Exists(configPath)) { if (!EditorUtility.DisplayDialog("SVCG", "文件已存在,是否覆盖?", "是", "否")) { return; } } excludeConfig = CreateInstance <ShaderKeywordConfig>(); AssetDatabase.CreateAsset(excludeConfig, configPath); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { if (GUILayout.Button("自动获取 SVC", GUILayout.Height(buttonHeight))) { svcToShow = (ShaderVariantCollection)AssetDatabase.LoadAssetAtPath(m_svcPath, typeof(ShaderVariantCollection)); if (svcToShow == null) { EditorUtility.DisplayDialog("SVCG", "文件不存在或无法加载", "哦"); } } if (GUILayout.Button("覆盖选择 SVC", GUILayout.Height(buttonHeight))) { if (svcToShow != null) { m_svcPath = AssetDatabase.GetAssetPath(svcToShow); } } if (GUILayout.Button("显示SVC信息", GUILayout.Height(buttonHeight))) { ClearOutput(); ShowSVCInfo(); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { if (GUILayout.Button("清除临时文件", GUILayout.Height(buttonHeight))) { DeleteTempFile(); } if (GUILayout.Button("清除临时文件夹", GUILayout.Height(buttonHeight))) { DeleteTempFolder(); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { Color defaultColor = GUI.backgroundColor; GUI.backgroundColor = Color.green; if (GUILayout.Button("收集变体", GUILayout.Height(buttonHeight))) { ClearOutput(); outputSB.AppendLine("收集中..."); DoCreate(m_materialBuildTarget); } GUI.backgroundColor = defaultColor; if (GUILayout.Button("从文本文件写入变体", GUILayout.Height(buttonHeight))) { ShaderVariantCollection svc = new ShaderVariantCollection(); svcToShow = svc; AssetDatabase.CreateAsset(svc, m_svcPath); ReadSVCDataAndAdd(svcToShow); } } EditorGUILayout.EndHorizontal(); //使用这种方式禁止交互 GUILayout.Label(outputSB.ToString(), EditorStyles.textArea, GUILayout.Height(120)); //_guiDebug(); }