Decorating Unity Shader Headers.
I was always passionate about making everything beautiful and well-structured. It’s not just about the game graphics, but also the tools and overall development environment.
I believe that working with nice-looking tools subconsciously instills a good sense of visual taste in everyone working with you, which ultimately translates into visually appealing game designs.
To achieve that, we need to use MaterialPropertyDrawer
(unity doc).
The simplest structure looks like this:
public class CustomHeaderDecorator : MaterialPropertyDrawer
{
private string text;
public CustomHeaderDecorator(string text)
{
this.text = text;
}
public override void OnGUI(
Rect pos, MaterialProperty prop, string label, MaterialEditor editor)
{
...
}
public override float GetPropertyHeight(
MaterialProperty prop, string label, MaterialEditor editor)
{
return 0;
}
}
Basically, that's all you need to do.
I chose a FrameBox
UI style for my header and tinted it into a bluish color.
Also, I've added an indent to increase readability even more, as well as some text parsing code that will allow the use of new lines.
After this is done, you can then use the following syntax to achieve the result shown in the image.
[CustomHeader(Globals)]
_Color("Color", Color) = (1,1,1,1)
_MainTex("Albedo (RGB)", 2D) = "white" {}
_MainTex2("Texture 2 (RGB)", 2D) = "black" {}
_NormalMap("Normal Map", 2D) = "bump" {}
[Space]
_Scale ("Scale", Range(1.0, 100.0)) = 50.0
_Offset ("Offset", Vector) = (0, 0, 0, 0)
[CustomHeader(PBR Shading)]
[Toggle(PBR_SHADING)] _PBRShading("PBR Shading", Float) = 0
_Metallic("Metallic", Range(0, 1)) = 0.0
_Smoothness("Smoothness", Range(0, 1)) = 0
Full C# code follows. Use it in any way you'd like to.
CustomHeaderDecorator.cs
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
namespace LazyBearTechnology
{
///
/// Decoration drawer for a shader property.
///
/// Usage:
///
/// [CustomHeader(Waves)] _WaveSize("Wave Size", Float) = 0
///
///
public class CustomHeaderDecorator : MaterialPropertyDrawer
{
private string text;
private const int HEIGHT = 25;
private const int SPACE_BEFORE = 4;
private const int SPACE_AFTER = 5;
private static bool indented = false;
public CustomHeaderDecorator(string text)
{
text = text.Replace(" _n ", "\n");
text = text.Replace("_n ", "\n");
text = text.Replace("_n", "\n");
text = text.Replace("__", "-");
this.text = text;
}
public override void OnGUI(Rect position, MaterialProperty prop, string label, MaterialEditor editor)
{
if (indented) EditorGUI.indentLevel--;
Color c = GUI.color;
GUI.color = new Color(0.75f, 0.9f, 1);
GUIStyle headerStyle = new GUIStyle(GUI.skin.GetStyle("FrameBox"))
{
fontStyle = FontStyle.Bold
};
position.y += SPACE_BEFORE;
position = EditorGUI.IndentedRect(position);
position.height -= 8;
GUI.Label(position, text, headerStyle);
position.y += SPACE_AFTER;
EditorGUI.indentLevel++;
indented = true;
GUI.color = c;
}
public override float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor)
{
return HEIGHT + SPACE_AFTER + SPACE_BEFORE;
}
}
}
#endif