unity3d:YooAsset shader变体收集代码解析
开始收集
YooAsset.Editor.ShaderVariantCollector.Run
创建临时场景
// 创建临时测试场景 CreateTempScene(); _steps = ESteps.Prepare; EditorApplication.update += EditorUpdate;
准备阶段
反射调用ShaderUtil.ClearCurrentShaderVariantCollection清空当前项目搜集到的变体,我们需要重新搜集一次;
EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "ClearCurrentShaderVariantCollection");
如何反射调用
/// <summary> /// 调用私有的静态方法 /// </summary> /// <param name="type">类的类型</param> /// <param name="method">类里要调用的方法名</param> /// <param name="parameters">调用方法传入的参数</param> public static object InvokeNonPublicStaticMethod(System.Type type, string method, params object[] parameters) { var methodInfo = type.GetMethod(method, BindingFlags.NonPublic | BindingFlags.Static); if (methodInfo == null) { UnityEngine.Debug.LogError($"{type.FullName} not found method : {method}"); return null; } return methodInfo.Invoke(null, parameters); }
收集全部材质球
YooAsset.Editor.ShaderVariantCollector.GetAllMaterials
所有收集器的依赖asset
// 获取所有打包的资源 CollectResult collectResult = AssetBundleCollectorSettingData.Setting.GetPackageAssets(EBuildMode.DryRunBuild, _packageName); foreach (var assetInfo in collectResult.CollectAssets) { string[] depends = AssetDatabase.GetDependencies(assetInfo.AssetPath, true); foreach (var dependAsset in depends) { if (allAssets.Contains(dependAsset) == false) allAssets.Add(dependAsset); }
收集所有依赖asset的材质球
List<string> allMaterial = new List<string>(1000); foreach (var assetPath in allAssets) { System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath); if (assetType == typeof(UnityEngine.Material)) { allMaterial.Add(assetPath); }
收集变体,摄像机照射所有材质球一遍
变体收集,每次只处理最大1000个材质球,超过的,等下一批再处理
YooAsset.Editor.ShaderVariantCollectorSetting.ProcessCapacity = 1000
每次处理一批时,总材质球列表_allMaterials去掉0-count,然后处理当前的range
int count = Mathf.Min(_processMaxNum, _allMaterials.Count); List<string> range = _allMaterials.GetRange(0, count); _allMaterials.RemoveRange(0, count);
在场景中创建一堆sphere几何体,并排列整齐,然后把渲染相机对齐它们,并保证它们都可以看见;
分批次把这些材质资源赋予这些sphere几何体,渲染100ms;
完成处理
变体收集到路径YooAsset.Editor.ShaderVariantCollectorSetting.SavePath = “Assets/MyShaderVariants.shadervariants”
反射调用ShaderUtil.SaveCurrentShaderVariantCollection保存到一个整体变体集合资源中去
EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "SaveCurrentShaderVariantCollection", savePath);
输出文件
MyShaderVariants.shadervariants会打包进入unityshaders.bundle包里
输出json,可以查看keyword做相应的剔除
AssetPath": "Resources/unity_builtin_extra", "ShaderName": "Standard", "ShaderVariantElements": [ { "PassType": 4, "Keywords": [ "DIRECTIONAL", "LIGHTPROBE_SH", "SHADOWS_SCREEN", "SHADOWS_SPLIT_SPHERES" ] }, { "PassType": 4, "Keywords": [ "DIRECTIONAL", "LIGHTPROBE_SH", "SHADOWS_SCREEN", "SHADOWS_SPLIT_SPHERES", "_EMISSION" ] },
打包时去掉keyword代码示例
public class StripInstancingOnKeyword : IPreprocessShaders { public int callbackOrder { //多个回调处理的处理顺序 get { return 0; } } //在执行打包assetbundle会处理 public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> inputData) { Debug.Log(string.Format("shader:{0}", shader.name)); //反向遍历,有利于删除 for (int i = inputData.Count - 1; i >= 0; i--) { ShaderCompilerData input = inputData[i]; //Global And Local Keyword if (input.shaderKeywordSet.IsEnabled(new ShaderKeyword("DIRECTIONAL")) || input.shaderKeywordSet.IsEnabled(new ShaderKeyword(shader, "DIRECTIONAL"))) { Debug.Log(string.Format("剔除shader:{0},变体{1}", shader.name, "DIRECTIONAL")); inputData.RemoveAt(i); } } } }
posted on 2023-07-17 01:15 luoyikun 阅读(436) 评论(0) 编辑 收藏 举报 来源
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!