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<ShaderVariantsStripperConfig>(

                        AssetDatabase.GUIDToAssetPath(guid)))

                .ToArray();

            return sConfigs;

        }

        public static void ClearConfigs()

        {

            sConfigs = null;

        }

        public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> 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<string> keyList = new List<string>();

                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;

        /// <summary>

        /// 总耗时

        /// </summary>

        public static int TotalSeconds = 0;

   

        /// <summary>

        /// 执行构建流程

        /// </summary>

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

        public static BuildResult Run(List<IBuildTask> 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<TaskAttribute>();

                    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;

        }

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中的Shader是指在编译阶段根据当前渲染平台和材质属性的不同而生成的多个不同的着色器程序。Shader会根据平台的不同动态地作出适配,以实现在不同平台下的最佳性能和视觉效果。 在编写Shader时,我们可以使用多种预处理指令和量来定义Shader的。预处理指令比如#pragma multi_compile和#pragma shader_feature可以用来指示编译器在编译时根据条件来包含或排除某些代码块。通过这样的方式,我们可以根据不同情况选择不同的代码路径。 Shader的生成是基于Shader的特性和特定的材质属性。特性是用来定义一组可选功能的开关,可以在材质中进行开关的切换。材质属性是指材质上的一些自定义属性,比如颜色、纹理等。因此,Shader的生成是根据这些特性和属性的组合来确定的。 Shader的生成会带来一定的开销,因为每个都需要编译和存储。为了减少这种开销,Unity使用了渐的方式生成。即在编译过程中,Unity会根据之前生成的生成新的,以便在之后的编译过程中尽可能重用已经生成的,从而减少重复的工作。 对于Shader的管理,Unity提供了几种优化的方式。首先,我们可以使用ShaderVariantCollection来存储和管理常用的,从而减少编译时间和内存占用。其次,可以使用ShaderKeywords来动态地切换Shader的特性,以实现更精细的控制和优化。 总之,Unity的Shader功能可以根据不同平台和材质属性生成多个不同的着色器程序,以实现最佳的性能和视觉效果。合理的使用Shader管理和优化可以大大提升游戏的性能和兼容性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值