Custom ShaderGUI for Unity that extends the standard material inspector.
It solves core limitations of Unity’s built-in system:
MaterialProperryDrawerattributes cannot take extra parameters.- You cannot apply multiple custom attributes to the same property
- You cannot combine some built-in attributes with custom
MaterialPropertyDrawer.
Parse shader text comments to attributes and values, then use ShaderGUI to draw it
- Tooltips, HelpBoxes, and multiple attributes are written in shader comments.
- No need for multiple
MaterialPropertyDrawerhacks. - Easy to add custom processors for any specialized UI control.
- Makes Unity’s material inspector far more flexible and maintainable.
- Write HTML-formatted tooltips using simple
//comments. - Show HelpBox messages using
[HelpBox]tag inside comments. - Support for multiple attributes on the same property.
- Extend the system with custom processors for any kind of control.
- Works with built-in attributes (
[Toggle],[HDR],[Enum],[Header]) at the same time.
Any comment starting with // becomes a tooltip for the next property.
// Main particle texture (RGBA)
_MainTex("Main Texture", 2D) = "white" {}➡ Hover over the property in the inspector to see the tooltip.
Use [HelpBox] inside a comment to show a message box above the property.
// [HelpBox]Gradient is applied to luminance
_Gradient("Gradient", 2D) = "white" {}Mix them in one line.
Text before [HelpBox] → tooltip, text after → HelpBox.
// Gradient texture [HelpBox]Only active when UseGradient is enabled
_Gradient("Gradient", 2D) = "white" {}Special tags can be written inside comments to control rendering:
// [Vector2] UV Scroll Speed (x = U, y = V)
_Scroll("Scroll Speed", Vector) = (0,0,0,0)
// [LogarithmicRange] Distortion intensity
_Strength("Distortion Strength", Range(0,1)) = 0.2| Tag | Description |
|---|---|
[Vector2] |
Hide ZW components of a Vector. Show only X/Y float fields. |
[Vector2:X,Y] |
Same as above, but with custom labels for each field. |
[MiniTexture] |
Draws a compact texture field (mini thumbnail). |
[EnableIf:Property] |
Disable the property only if another float/int property is less than 0.5. |
[HelpBox] |
Shows a help message above the property. |
All custom logic is handled by Property Processors.
Each processor extends the abstract base class:
public abstract class PropertyProcessor
{
public abstract void Draw(MaterialEditor editor, MaterialProperty prop, PropertyInfo info, GUIContent content);
}- Create a new class extending
PropertyProcessor. - inplement
CanDrawto filter your attribute byfieldType. if you write aDecoratorreturnfalse - In
ParseCommentuse Regex to find your attribute, and fillinfo.cuatomDatawith parsed values - Implement the
Drawmethod.
private class StepSliderProcessor : PropertyProcessor
{
private static Regex regex = new Regex(@"\[StepSlider\(\s*([-+]?\d*\.?\d+)\s*\)\]");
public override int ProcessingOrder => 10;
public override bool CanProcess(MaterialProperty prop, PropertyInfo info, List<string> unityAttributes)
{
return (prop.type == MaterialProperty.PropType.Float || prop.type == MaterialProperty.PropType.Range) && info.customData.ContainsKey("stepSize");
}
public override void Draw(MaterialEditor editor, MaterialProperty prop, PropertyInfo info, GUIContent content)
{
if (info.customData.TryGetValue("stepSize", out var val))
{
float step = (float)val;
EditorGUI.BeginChangeCheck();
float newVal = EditorGUILayout.Slider(content, prop.floatValue, prop.rangeLimits.x, prop.rangeLimits.y);
newVal = Mathf.Round(newVal / step) * step;
if (EditorGUI.EndChangeCheck())
prop.floatValue = newVal;
}
else
{
Debug.LogError("TryGetValue(stepSize) failed");
}
}
public override string ParseComment(string comment, ref PropertyInfo info, ref string helpBox)
{
var match = regex.Match(comment);
if (match.Success)
{
if (float.TryParse(match.Groups[1].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out float step))
{
info.customData["stepSize"] = step;
comment = regex.Replace(comment, "");
}
else
{
Debug.LogError("stepSize failed parse");
}
}
return comment;
}
}Shader usage:
// [StepSlider(0.25)]
_Smoothness("Smoothness", Range(0,1)) = 0.5