Files
JJBB/Assets/Editor/Scripts/ShaderVariantTool.cs

304 lines
12 KiB
C#
Raw Normal View History

2024-08-23 15:49:34 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Games.GlobeDefine;
using UnityEditor;
using UnityEngine;
public static class ShaderVariantTool
{
// public const string variantCollectionPath = "Assets/Project/Shader/ShaderVariants.shadervariants";
// public const string shadowDepthKeyword = "SHADOWS_DEPTH";
// public const string fogKeyword = "FOG_LINEAR";
// public const string lightmapKeyword = "LIGHTMAP_ON";
// public const string directionalKeyword = "DIRECTIONAL";
//
// private const string _fogCompileWord = "fog";
// private const string _forwardBaseCompileWord = "fwdbase";
public static readonly string[] excludeKeywords =
{
"UNITY_HDR_ON",
"DIRLIGHTMAP_COMBINED",
"DIRLIGHTMAP_SEPARATE"
};
// public static void BuildVariantForShaders(IList<string> assetPaths)
// {
// var data = new List<ShaderVariantsSetting>();
// for (var i = 0; i < assetPaths.Count; i++)
// {
// var path = assetPaths[i];
// var shader = AssetDatabase.LoadAssetAtPath<Shader>(path);
// var shaderSettings = CreateVariants(path, shader);
// data.Add(shaderSettings);
// }
//
// var collection = new ShaderVariantCollection();
// for (var i = 0; i < data.Count; i++)
// {
// var varients = data[i].ParseToVarients();
// for (var j = 0; j < varients.Length; j++)
// collection.Add(varients[j]);
// }
//
// AssetDatabase.CreateAsset(collection, variantCollectionPath);
// AssetDatabase.SaveAssets();
// AssetDatabase.Refresh();
// Debug.LogWarning("Build Shader Variant Collection for " + assetPaths.Count);
// }
// public static ShaderVariantsSetting CreateVariants(string assetPath, Shader shader)
// {
// var filePath = Application.dataPath.Open(assetPath.Substring("Assets".Length));
// var keywordList = new List<string>();
// var useForwardBase = false;
// var useShadow = false;
// var lines = File.ReadAllLines(filePath);
// var regex = new Regex("(?<=#pragma multi_compile).+");
// var shadowRegex = new Regex("\"LightMode\"\\s*=\\s*\"ShadowCaster\"");
// foreach (var line in lines)
// {
// var match = regex.Match(line);
// if (match.Success)
// {
// var result = match.Value.Trim('_', ' ');
// // Unity内置Keyword
// if (match.Value.StartsWith("_"))
// {
// switch (result)
// {
// case _fogCompileWord:
// if (!keywordList.Contains(fogKeyword))
// keywordList.Add(fogKeyword);
// break;
// case _forwardBaseCompileWord:
// useForwardBase = true;
// break;
// }
// }
// else if (match.Value.Contains("__"))
// {
// if (!result.Contains(" ") && !excludeKeywords.Contain(result) && !keywordList.Contains(result))
// keywordList.Add(result);
// }
// else
// {
// Debug.LogWarning("无法处理 " + line.TrimStart());
// }
// }
// else
// {
// match = shadowRegex.Match(line);
// if (match.Success)
// useShadow = true;
// }
// }
//
// // 注useForwardBase的物体都是景物仅仅需要烘培阴影
// if (useForwardBase)
// useShadow = false;
// var fixedKeywords = useForwardBase ? new[] {lightmapKeyword, directionalKeyword} : new string[0];
// var toggleKeywords = keywordList.ToArray();
// return new ShaderVariantsSetting(shader.name, useForwardBase ? PassType.ForwardBase : PassType.Normal,
// fixedKeywords, toggleKeywords, useShadow);
// }
// public class ShaderVariantsSetting
// {
// public readonly string[] fixedKeywords;
// public readonly PassType passType;
// public readonly string shaderName;
// public readonly bool shadow;
// public readonly string[] toggleKeywords;
//
// public ShaderVariantsSetting(string name, PassType pass, string[] fixedMacro, string[] toggleMacro,
// bool useShadow = false)
// {
// shaderName = name;
// passType = pass;
// fixedKeywords = fixedMacro;
// toggleKeywords = toggleMacro;
// shadow = useShadow;
// }
//
// public ShaderVariantCollection.ShaderVariant[] ParseToVarients()
// {
// var shader = Shader.Find(shaderName);
// if (shader == null)
// throw new ArgumentException("无法获得Shader " + shaderName);
// var end = 1 << toggleKeywords.Length;
// var variants = new ShaderVariantCollection.ShaderVariant[end + (shadow ? 1 : 0)];
// for (var i = 0; i < end; i++)
// {
// var index = 0;
// var count = EditorCommonUtility.GetMaskCount(i);
// var keywords = new string[count + fixedKeywords.Length];
// for (var j = 0; j < toggleKeywords.Length; j++)
// {
// var num = j.ToFlag();
// if (i.ContainFlag(num))
// {
// keywords[index] = toggleKeywords[j];
// index++;
// }
// }
//
// for (var j = 0; j < fixedKeywords.Length; j++)
// keywords[count + j] = fixedKeywords[j];
// variants[i] = new ShaderVariantCollection.ShaderVariant
// {
// shader = shader,
// passType = passType,
// keywords = keywords
// };
// }
//
// if (shadow)
// variants[end] = new ShaderVariantCollection.ShaderVariant
// {
// shader = shader,
// passType = PassType.ShadowCaster,
// keywords = new[] {shadowDepthKeyword}
// };
//
// return variants;
// }
// }
#region DummyMaterial
public static void CreateAllDummyMaterials(List<string> assetPaths, string bundlePath)
{
var recordPath = GlobeVar.testConfigPath.Open("DummyMatRecord.txt");
var create = true;
assetPaths.Sort();
var builder = new StringBuilder();
foreach (var assetPath in assetPaths)
builder.AppendLine(assetPath);
var newHash = ClassifyBundles.GetStringHash(builder.ToString());
if (File.Exists(recordPath))
{
var oldHash = File.ReadAllText(recordPath);
if (oldHash.Equals(newHash, StringComparison.Ordinal))
create = false;
}
if (create)
{
var data = new List<DummyMaterialBuilder>();
var dummyFilePath = EditorCommonUtility.AssetToFilePath(ClassifyBundles.dummyMaterialPath);
if (Directory.Exists(dummyFilePath))
Directory.Delete(dummyFilePath, true);
Directory.CreateDirectory(dummyFilePath);
AssetDatabase.Refresh();
for (var i = 0; i < assetPaths.Count; i++)
{
var path = assetPaths[i];
var shader = AssetDatabase.LoadAssetAtPath<Shader>(path);
var shaderSettings = CreateDummyMaterials(path, shader);
data.Add(shaderSettings);
}
for (var i = 0; i < data.Count; i++)
{
var variants = data[i];
variants.SaveToVariants(bundlePath);
}
File.WriteAllText(recordPath, newHash);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.LogWarning("Build Shader Variant Collection for " + assetPaths.Count);
}
else
Debug.LogWarning("Skip Shader Variant as Hash matched!");
}
public static DummyMaterialBuilder CreateDummyMaterials(string assetPath, Shader shader)
{
var filePath = Application.dataPath.Open(assetPath.Substring("Assets".Length));
var keywordList = new List<string>();
var lines = File.ReadAllLines(filePath);
var regex = new Regex("(?<=#pragma multi_compile).+");
foreach (var line in lines)
{
var match = regex.Match(line);
if (match.Success)
{
var result = match.Value.Trim('_', ' ');
// Unity内置Keyword
if (match.Value.StartsWith("_"))
{
}
else if (match.Value.Contains("__"))
{
if (!result.Contains(" ") && !excludeKeywords.Contain(result) && !keywordList.Contains(result))
keywordList.Add(result);
}
else
{
Debug.LogWarning("无法处理 " + line.TrimStart());
}
}
}
// 注useForwardBase的物体都是景物仅仅需要烘培阴影
return new DummyMaterialBuilder(shader, keywordList.ToArray());
}
public class DummyMaterialBuilder
{
public readonly Shader shader;
public readonly string[] toggleKeywords;
public DummyMaterialBuilder(Shader name, string[] toggleMacro)
{
shader = name;
toggleKeywords = toggleMacro;
}
public void SaveToVariants(string bundleName)
{
if (!shader)
throw new ArgumentException("无法获得Shader!");
var end = 1 << toggleKeywords.Length;
var variants = new Material[end];
for (var i = 0; i < end; i++)
{
var index = 0;
var count = EditorCommonUtility.GetMaskCount(i);
var keywords = new string[count];
for (var j = 0; j < toggleKeywords.Length; j++)
{
var num = j.ToFlag();
if (i.ContainFlag(num))
{
keywords[index] = toggleKeywords[j];
index++;
}
}
variants[i] = new Material(shader);
for (var j = 0; j < keywords.Length; j++)
variants[i].EnableKeyword(keywords[j]);
variants[i].name = shader.name + "_" + i;
}
for (var i = 0; i < variants.Length; i++)
{
var assetPath =
ClassifyBundles.dummyMaterialPath.Open(ClassifyBundles.GetStringHash(variants[i].name) + AssetConst.materialExtension);
AssetDatabase.CreateAsset(variants[i], assetPath);
var importer = AssetImporter.GetAtPath(assetPath);
importer.assetBundleName = bundleName;
importer.assetBundleVariant = LoadAssetBundle.bundleFileExtension;
}
}
}
#endregion
}