Instantly share code, notes, and snippets.
Last active
January 20, 2025 23:37
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save Myrkie/2b3664a05293d1bb0e118f05a3357cd2 to your computer and use it in GitHub Desktop.
Shows hidden shaders in material shader selection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
using UnityEditor; | |
using UnityEditor.IMGUI.Controls; | |
using UnityEngine; | |
using HarmonyLib; | |
[InitializeOnLoad] | |
public class ShowHiddenShaders : Editor | |
{ | |
private static readonly Harmony _harmonyInstance = new("com.Myrkur.MaterialEditor.ShowHiddenShaders"); | |
private static Dictionary<int, Shader> s_HiddenShadersById = new(); | |
private static int s_NextCustomId = -1; | |
static ShowHiddenShaders() | |
{ | |
try | |
{ | |
var materialEditorType = | |
typeof(Editor).Assembly.GetType("UnityEditor.MaterialEditor+ShaderSelectionDropdown"); | |
var shaderDropdownType = | |
materialEditorType.GetNestedType("ShaderDropdownDataSource", BindingFlags.NonPublic); | |
var fetchDataMethod = shaderDropdownType.GetMethod( | |
"FetchData", BindingFlags.NonPublic | BindingFlags.Instance); | |
if (fetchDataMethod == null) | |
{ | |
Debug.LogError("Could not find FetchData method."); | |
return; | |
} | |
var fetchPostfix = new HarmonyMethod(typeof(ShowHiddenShaders).GetMethod(nameof(FetchDataPostfix), | |
BindingFlags.NonPublic | BindingFlags.Static)); | |
_harmonyInstance.Patch(fetchDataMethod, postfix: fetchPostfix); | |
var itemSelectedMethod = materialEditorType.GetMethod("ItemSelected", | |
BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(AdvancedDropdownItem) }, null); | |
var itemSelectedPrefix = new HarmonyMethod( | |
typeof(ShowHiddenShaders).GetMethod(nameof(ShaderDropdownItemSelectedPrefix), | |
BindingFlags.NonPublic | BindingFlags.Static)); | |
_harmonyInstance.Patch(itemSelectedMethod, prefix: itemSelectedPrefix); | |
} | |
catch (Exception ex) | |
{ | |
Debug.LogError(ex); | |
} | |
} | |
private static void FetchDataPostfix(ref AdvancedDropdownItem __result, object __instance) | |
{ | |
if (__result == null) | |
{ | |
return; | |
} | |
var hiddenRoot = new AdvancedDropdownItem("Hidden Shaders"); | |
__result.AddChild(hiddenRoot); | |
s_HiddenShadersById.Clear(); | |
s_NextCustomId = -1; | |
ShaderInfo[] allShaderInfos; | |
try | |
{ | |
allShaderInfos = ShaderUtil.GetAllShaderInfo(); | |
if (allShaderInfos == null || allShaderInfos.Length == 0) | |
{ | |
return; | |
} | |
} | |
catch (Exception) | |
{ | |
return; | |
} | |
var hiddenShadersByCategory = new Dictionary<string, List<AdvancedDropdownItem>>(); | |
foreach (var info in allShaderInfos) | |
{ | |
if (info.name.StartsWith("Hidden/")) | |
{ | |
string shaderName = info.name.Substring("Hidden/".Length); | |
string[] parts = info.name.Split('/'); | |
if (parts.Length >= 2) | |
{ | |
string category = parts[1]; | |
if (!hiddenShadersByCategory.ContainsKey(category)) | |
{ | |
hiddenShadersByCategory[category] = new List<AdvancedDropdownItem>(); | |
} | |
var customId = s_NextCustomId--; | |
s_HiddenShadersById[customId] = Shader.Find(info.name); | |
hiddenShadersByCategory[category].Add(new AdvancedDropdownItem(shaderName) { id = customId }); | |
} | |
} | |
} | |
foreach (var category in hiddenShadersByCategory) | |
{ | |
if (category.Value.Count > 1) | |
{ | |
var subcategory = new AdvancedDropdownItem(category.Key); | |
hiddenRoot.AddChild(subcategory); | |
foreach (var shaderItem in category.Value) | |
{ | |
subcategory.AddChild(shaderItem); | |
} | |
} | |
else | |
{ | |
foreach (var shaderItem in category.Value) | |
{ | |
hiddenRoot.AddChild(shaderItem); | |
} | |
} | |
} | |
} | |
private static bool ShaderDropdownItemSelectedPrefix(AdvancedDropdownItem item, object __instance) | |
{ | |
if (!s_HiddenShadersById.TryGetValue(item.id, out Shader chosenHiddenShader)) | |
{ | |
return true; | |
} | |
AssignSelectedShader(chosenHiddenShader); | |
return false; | |
} | |
private static void AssignSelectedShader(Shader hiddenShader) | |
{ | |
var selectedMaterials = Selection.objects.OfType<Material>().ToArray(); | |
if (selectedMaterials.Length == 0) | |
{ | |
var selectedGOs = Selection.gameObjects; | |
var collected = new List<Material>(); | |
foreach (var go in selectedGOs) | |
{ | |
var renderer = go.GetComponent<Renderer>(); | |
if (renderer != null) | |
{ | |
collected.AddRange(renderer.sharedMaterials.Where(m => m != null)); | |
} | |
} | |
selectedMaterials = collected.ToArray(); | |
} | |
if (selectedMaterials.Length == 0) | |
{ | |
Debug.LogWarning("No selected Materials or Renderers to assign the hidden shader."); | |
return; | |
} | |
foreach (var material in selectedMaterials) | |
{ | |
if (material != null && material.shader != hiddenShader) | |
{ | |
Undo.RecordObject(material, "Change Shader"); | |
material.shader = hiddenShader; | |
EditorUtility.SetDirty(material); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Unity_6ki8h7sgYq.mp4