반응형
- 프로젝트에서 사용하는 특정 쉐이더의 키워드 및 Variants 숫자를 리스트로 정렬해주는 툴
- 사용되는 키워드 분량, 필요 없는 키워드를 판별하는 용도로 사용
- 글로벌로 제어되는 multi_compile 키워드는 카운팅되지 않음. (예 : _MAIN_LIGHT_SHWDOWS)
- 정확히 Material에 저장된 Keyword만 카운트됨.
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
// Ref - https://github.com/needle-tools/shader-variant-explorer
public class ShaderVariantChecker : EditorWindow
{
private static MethodInfo GetVariantCount, GetShaderGlobalKeywords, GetShaderLocalKeywords;
private Shader _shader;
private ulong _variantCount = 0;
private ulong _usedVariantCount = 0;
private int _keywordCount = 0;
private int _materialCount = 0;
private Dictionary<string, int> _materialKeywords = new Dictionary<string, int>();
private bool _isChecked = false;
private Vector2 scrollPosition;
[MenuItem("CustomTool/ShaderVariantChecker")]
private static void ShowWindow()
{
GetWindow<ShaderVariantChecker>().Show();
}
public void OnGUI()
{
_shader = EditorGUILayout.ObjectField("Shader", _shader, typeof(Shader), true) as Shader;
if(GUILayout.Button("Check"))
{
if (!_shader) return;
Process(_shader);
}
if (!_isChecked) return;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Variant Count : " + _variantCount);
EditorGUILayout.LabelField("Used Variant Count : " + _usedVariantCount);
EditorGUILayout.LabelField("Keyword Count : " + _keywordCount);
EditorGUILayout.EndHorizontal();
EditorGUILayout.LabelField("Used Material Count : " + _materialCount);
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
Color defaultColor = GUI.color;
foreach (KeyValuePair<string, int> keyword in _materialKeywords)
{
EditorGUILayout.BeginHorizontal();
bool isValid = keyword.Value > 0;
if (isValid) GUI.color = Color.red;
EditorGUILayout.TextField(keyword.Key);
EditorGUILayout.TextField(keyword.Value.ToString(), GUILayout.Width(30));
GUI.color = defaultColor;
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndScrollView();
}
private void Process(Shader shader)
{
if (!shader) return;
GetShaderDetails(shader, out var variantCount, out var usedVariantCount, out string[] localKeywords, out string[] globalKeywords);
_materialKeywords.Clear();
for (int i = 0; i < localKeywords.Length; i++)
{
_materialKeywords.Add(localKeywords[i], 0);
}
for (int i = 0; i < globalKeywords.Length; i++)
{
if (_materialKeywords.ContainsKey(globalKeywords[i])) continue;
_materialKeywords.Add(globalKeywords[i], 0);
}
_variantCount = variantCount;
_usedVariantCount = usedVariantCount;
_keywordCount = _materialKeywords.Count;
// Debug.Log("variantCount : " + variantCount + ", usedVariantCount : " + usedVariantCount + ", keywordCount : " + keywordTotalCount);
List<Material> materials = FindMaterialsUsingShader(shader);
_materialCount = materials.Count;
for (int i=0; i< materials.Count; i++)
{
Material mat = materials[i];
if (!mat) continue;
string[] keywords = mat.shaderKeywords;
if(keywords == null || keywords.Length ==0) continue;
for(int j=0; j< keywords.Length; j++)
{
if (!_materialKeywords.ContainsKey(keywords[j])) continue;
_materialKeywords[keywords[j]]++;
}
}
_isChecked = true;
}
void GetShaderDetails(Shader requestedShader, out ulong shaderVariantCount, out ulong usedShaderVariantCount, out string[] localKeywords, out string[] globalKeywords)
{
if (GetVariantCount == null) GetVariantCount = typeof(ShaderUtil).GetMethod("GetVariantCount", (BindingFlags)(-1));
if (GetShaderGlobalKeywords == null) GetShaderGlobalKeywords = typeof(ShaderUtil).GetMethod("GetShaderGlobalKeywords", (BindingFlags)(-1));
if (GetShaderLocalKeywords == null) GetShaderLocalKeywords = typeof(ShaderUtil).GetMethod("GetShaderLocalKeywords", (BindingFlags)(-1));
if (GetVariantCount == null || GetShaderGlobalKeywords == null || GetShaderLocalKeywords == null)
{
shaderVariantCount = 0;
usedShaderVariantCount = 0;
localKeywords = null;
globalKeywords = null;
return;
}
shaderVariantCount = (ulong)GetVariantCount.Invoke(null, new object[] { requestedShader, false });
usedShaderVariantCount = (ulong)GetVariantCount.Invoke(null, new object[] { requestedShader, true });
localKeywords = (string[])GetShaderLocalKeywords.Invoke(null, new object[] { requestedShader });
globalKeywords = (string[])GetShaderGlobalKeywords.Invoke(null, new object[] { requestedShader });
// var name = $"{requestedShader.name}: ({shaderVariantCount} variants, {localKeywords.Length} local, {globalKeywords.Length} global)";
}
public static List<Material> FindMaterialsUsingShader(Shader shader)
{
List<Material> materialsUsingShader = new List<Material>();
string[] materialAssetGUIDs = AssetDatabase.FindAssets("t:Material");
foreach (var guid in materialAssetGUIDs)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
Material material = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
if (material != null && material.shader != null)
{
if (material.shader.name == shader.name)
{
materialsUsingShader.Add(material);
}
}
}
return materialsUsingShader;
}
}
반응형
'Unity > Programming' 카테고리의 다른 글
Unity Package Manager My Assets(구매 에셋) 목록 CSV 추출 (0) | 2024.10.14 |
---|---|
유니티 URP RendererFeature 활성화 제어 스크립트 (1) | 2024.01.16 |
Script 에셋 경로 참조하기 (0) | 2023.04.04 |
Unity URP HLSL 쉐이더 템플릿 생성 스크립트 (0) | 2023.03.07 |
[Unity Editor] Particle System에서 싱글 Emission 자동 세팅 (1) | 2020.06.28 |
WRITTEN BY
- CatDarkGame
Technical Artist dhwlgn12@gmail.com
,