304 lines
12 KiB
C#
304 lines
12 KiB
C#
|
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
|
|||
|
}
|