• unity变体收集工具


    项目目录:D:\GIT\YooAsset\Temp

    收集代码:

    using System.Collections;

    using System.Collections.Generic;

    using UnityEditor;

    #if UNITY_EDITOR

    using UnityEditor.Build;

    using UnityEditor.Rendering;

    #if UNITY_2019_4_OR_NEWER

    using UnityEditor.Build.Pipeline.Utilities;

    #endif

    #endif

    using UnityEngine;

    using System.Linq;

    using System.Text;

    using ShaderVariant = UnityEngine.ShaderVariantCollection.ShaderVariant;

    // 增量打包时已经打包的Shader不会触发该回调,只有新打包的Shader才会。不管是Addressable打包或者是其他的打包方式都类似。

    // 如果需要通过IPreprocessShaders来进行Shader变体剔除,那么还是建议重新全量打包一次,或者打包时设置ForceRebuild。

    // 实现 IPreprocessShaders 接口的类有VersionedCallbackAttribute 属性, 修改version更新sbp的hash,跳过打包缓存。

    namespace Soco.ShaderVariantsStripper

    {

    #if UNITY_EDITOR

    #if UNITY_2019_4_OR_NEWER

        [VersionedCallback(1.47f)]

    #endif

        public class ShaderVariantsStripperCode : IPreprocessShaders

        {

            public static StringBuilder sbCache = new StringBuilder();

            public static StringBuilder sb = new StringBuilder();

            public int callbackOrder { get { return 0; } }

            private static string[] sAllPath = { "Assets", "Packages" };

            private static ShaderVariantsStripperConfig[] sConfigs;

            private List<(ConditionPair conditionPair, ShaderVariantsStripperConfig config)> mConditionList = new List<(ConditionPair condition, ShaderVariantsStripperConfig config)>();

            public static ShaderVariantsStripperConfig[] LoadConfigs()

            {

                string[] guids = AssetDatabase.FindAssets("t:ShaderVariantsStripperConfig", sAllPath);

                sConfigs = (from guid in guids

                        select AssetDatabase.LoadAssetAtPath(

                            AssetDatabase.GUIDToAssetPath(guid)))

                    .ToArray();

                return sConfigs;

            }

            public static void ClearConfigs()

            {

                sConfigs = null;

            }

            public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList data)

            {

                sbCache.AppendLine(shader.name);

                sbCache.AppendLine(data.Count.ToString());

                sbCache.AppendLine(snippet.passType.ToString());

               

                // print to file

                sb.AppendLine("");

                sb.AppendLine($"name:{shader.name}, passType:{snippet.passType}, shaderType:{snippet.shaderType}");

                foreach(var v in data) {

                    List keyList = new List();

                    string keys = "";

                    foreach(var key in v.shaderKeywordSet.GetShaderKeywords()) {

                        keys += key.name + ",";

                        keyList.Add(key.name);

                    }

                    sb.AppendLine($"     变体 Shader:{shader.name} keys:{keys} ");

                    var str_ = "";

                    foreach(var str in keyList) {

                        str_ += str + " ";

                    }

                    sbCache.AppendLine(str_);

                }

                sbCache.AppendLine("");



     

                if (sConfigs == null) {

                    LoadConfigs();

                }

                ShaderCompilerData workaround = data[0];

                int stripCount = 0;

                for (int i = data.Count - 1; i >= 0 ; --i) {

                    mConditionList.Clear();

                    StripVariant(shader, snippet, data[i], sConfigs, mConditionList);

                    foreach (var conditionPair_fromConfig in mConditionList) {

                        if (conditionPair_fromConfig.conditionPair.strip)

                        {

                            data.RemoveAt(i);

                            stripCount++;

                            break;

                        }

                    }

                }

                // Debug.Log($"Shader:{shader.name} Pass:{snippet.passType}-PassName:{snippet.passName} 剔除个数:{stripCount}");

                if (data.Count == 0)

                {

                    // Debug.Log($"Shader:{shader.name} Pass:{snippet.passType} 因剔除全部保留变体一个");

                    data.Add(workaround);

                } else {

                    foreach(var v in data)

                    {

                        string keys = "";

                        foreach(var key in v.shaderKeywordSet.GetShaderKeywords())

                        {

                            keys += key.name + ",";

                        }

                        // Debug.Log($"     变体 Shader:{shader.name} keys:{keys} ");

                    }

                }

            }

           

            //对外开放接口,用于检查keyword是否需要被剔除

            private static List<(ConditionPair conditionPair, ShaderVariantsStripperConfig config)> sConditionList = new List<(ConditionPair condition, ShaderVariantsStripperConfig config)>();

            public static bool IsVariantStrip(Shader shader, ShaderSnippetData snippet, ShaderCompilerData data, ShaderVariantsStripperConfig[] configs)

            {

                sConditionList.Clear();

                StripVariant(shader, snippet, data, sConfigs, sConditionList);

                return sConditionList.Any(conditionPair_fromConfig =>

                    conditionPair_fromConfig.conditionPair.strip);

            }

           

            public static void StripVariant(Shader shader, ShaderSnippetData snippet, ShaderCompilerData data,

                ShaderVariantsStripperConfig[] configs,

                List<(ConditionPair conditionPair, ShaderVariantsStripperConfig config)> conditionList)

            {

                StripVariant(shader, ShaderVariantsData.GetShaderVariantsData(snippet, data), configs, conditionList);

            }

           

            public static void StripVariant(Shader shader, ShaderVariantsData variantData, ShaderVariantsStripperConfig[] configs, List<(ConditionPair conditionPair, ShaderVariantsStripperConfig config)> conditionList)

            {

                int FindConditionEqual(ConditionPair pair, out int index)

                {

                    for (int condList_i = 0; condList_i < conditionList.Count; ++condList_i)

                    {

                        if (pair.condition.EqualTo(conditionList[condList_i].conditionPair.condition, variantData))

                        {

                            index = condList_i;

                            return condList_i;

                        }

                    }

                    index = -1;

                    return -1;

                }

                   

                foreach (ShaderVariantsStripperConfig config in configs)

                {

                    if (!config.mEnable)

                        continue;

                   

                    bool applyGlobalConfig = true;

                    // 如果这个配置文件中能找到当前shader,则应用配置文件中“应用global config选项”

                    if (config.mShaderConditions.TryGetValue(shader, out ShaderVariantsItem item))

                        applyGlobalConfig = item.applyGlobalConfig;

                    // 如果Shader View中没有Shader,则Global Setting应用于全体Shader

                    else if (config.mShaderConditions.Count == 0)

                        applyGlobalConfig = true;

                    else

                        applyGlobalConfig = false;

                       

                    //Global condition

                    if (applyGlobalConfig)

                    {

                        foreach (ConditionPair pair in config.mGlobalConditions)

                        {

                            if (pair.condition != null && pair.condition.Completion(shader, variantData))

                            {

                                //如果有相同的条件,

                                if (FindConditionEqual(pair, out int findIndex) != -1)

                                {

                                    //且优先级更高

                                    if(pair.priority > conditionList[findIndex].conditionPair.priority)

                                        conditionList[findIndex] = (pair, config);

                                    //优先级更低则直接丢弃

                                }

                                else//否则加入列表

                                    conditionList.Add((pair, config));

                            }

                        }

                    }

                    //Shader local condition

                    if (item != null)

                    {

                        foreach (ConditionPair pair in item.conditionPairs)

                        {

                            if (pair.condition.Completion(shader, variantData))

                            {

                                if (FindConditionEqual(pair, out int findIndex) != -1)

                                {

                                    if (pair.priority > conditionList[findIndex].conditionPair.priority)

                                        conditionList[findIndex] = (pair, config);

                                }

                                else

                                    conditionList.Add((pair, config));

                            }

                        }

                    }

                }

            }

        }

    #endif

    }


     

    保存代码:生成一个svc 和一个txt

    using System;

    using System.Collections;

    using System.Collections.Generic;

    using System.Reflection;

    using System.Diagnostics;

    using UnityEngine;

    using ShaderVariant = UnityEngine.ShaderVariantCollection.ShaderVariant;

    using Rendering = UnityEngine.Rendering;

    using System.IO;

    namespace YooAsset.Editor

    {

        public class BuildRunner

        {

            private static Stopwatch _buildWatch;

            ///

            /// 总耗时

            ///

            public static int TotalSeconds = 0;

       

            ///

            /// 执行构建流程

            ///

            /// 如果成功返回TRUE,否则返回FALSE

            public static BuildResult Run(List pipeline, BuildContext context)

            {

                if (pipeline == null)

                    throw new ArgumentNullException("pipeline");

                if (context == null)

                    throw new ArgumentNullException("context");

                BuildResult buildResult = new BuildResult();

                buildResult.Success = true;

                TotalSeconds = 0;

                for (int i = 0; i < pipeline.Count; i++)

                {

                    IBuildTask task = pipeline[i];

                    try

                    {

                        _buildWatch = Stopwatch.StartNew();

                        var taskAttribute = task.GetType().GetCustomAttribute();

                        if (taskAttribute != null)

                            BuildLogger.Log($"---------------------------------------->{taskAttribute.TaskDesc}<---------------------------------------");

                        task.Run(context);

                        _buildWatch.Stop();

                        // 统计耗时

                        int seconds = GetBuildSeconds();

                        TotalSeconds += seconds;

                        if (taskAttribute != null)

                            BuildLogger.Log($"{taskAttribute.TaskDesc}耗时:{seconds}秒");

                    }

                    catch (Exception e)

                    {

                        EditorTools.ClearProgressBar();

                        buildResult.FailedTask = task.GetType().Name;

                        buildResult.ErrorInfo = e.ToString();

                        buildResult.Success = false;

                        break;

                    }

                }

                // 返回运行结果

                BuildLogger.Log($"构建过程总计耗时:{TotalSeconds}秒");

                Print();

                return buildResult;

            }

            private static void Print()

            {

                System.Text.StringBuilder sb = Soco.ShaderVariantsStripper.ShaderVariantsStripperCode.sb;  

                SVC.FileHelper.WriteToFile(sb, "Temp/OnProcessShader.txt");

               

                System.Text.StringBuilder sbCache = Soco.ShaderVariantsStripper.ShaderVariantsStripperCode.sbCache;  

                SVC.FileHelper.WriteToFile(sbCache, "Temp/sbCache.txt", false);

                ShaderVariantCollection svc = new ShaderVariantCollection();

                using (System.IO.StringReader reader = new System.IO.StringReader(sbCache.ToString()))

                {

                    string line;

                    while ((line = reader.ReadLine()) != null)

                    {

                        UnityEngine.Debug.Log(line);

                        string shaderName = line.Trim();

                        Shader mshader = Shader.Find(shaderName);

                        if(mshader == null)

                        {

                            UnityEngine.Debug.LogError("没有找到shader: " + shaderName);

                        } else {

                        }

                        line = reader.ReadLine();

                        int count = int.Parse(line.Trim());

                        line = reader.ReadLine();

                        string mpassType = line.Trim();  

                        Rendering.PassType mpass = (Rendering.PassType) Enum.Parse(typeof(Rendering.PassType), mpassType);

                        for(int i = 0, iMax = count; i < iMax; i++)

                        {

                            line = reader.ReadLine();

                            string keysLine = line.Trim();

                            string[] keyNames = keysLine.Split(' ');

                            ShaderVariant _sv = new ShaderVariant(mshader, mpass, keyNames);

                            svc.Add(_sv);

                        }

                           

                        line = reader.ReadLine(); // 跳过分割行

                    }

                        var tempPath = "Assets/TestSVC/Tool2/UnityBuildResultSVC.shadervariants";

                    if ( File.Exists( tempPath ) ) {

                        UnityEditor.AssetDatabase.DeleteAsset( tempPath );

                    }  

                    UnityEngine.Debug.LogError("--------- Save" + svc);

                    UnityEditor.AssetDatabase.CreateAsset(svc, tempPath);

                    UnityEditor.AssetDatabase.SaveAssets();

                    UnityEditor.AssetDatabase.Refresh();

                }

            }

            private static int GetBuildSeconds()

            {

                float seconds = _buildWatch.ElapsedMilliseconds / 1000f;

                return (int)seconds;

            }

        }

    }

  • 相关阅读:
    深度学习基础之《TensorFlow框架(15)—神经网络》
    pycharm进阶使用学习
    线性表01- 数组与简易接口设计
    在抖音中使用语聚AI,实现自动回复用户视频评论、私信问答
    概率论的学习和整理--番外9:关于贝特朗悖论的学习
    AI作画:十分钟快速搭建自己的text-to-image diffusion models
    关于C++解决内存泄漏问题的心得
    Java AtomicInteger 学习以及理解
    FMT自抗扰控制算法(ADRC)现已开源
    greenhills compiler 2021.1.4 for x86 Linux
  • 原文地址:https://blog.csdn.net/gepengmiss/article/details/133911815