Summary

Unity provides a convenient way to link custom documentation to Monobehaviours and ScriptableObjects by adding the [HelpURL] attribute to your class. When an instance of this class is selected in the Inspector users can click the help icon to open the given link in the attribute in a browser. It would be nice if we could use the same attribute also to add custom documentation to shaders and materials. Unfortunately this does not work out of the box. In this article we look at a way how to use MaterialPropertyDrawers to add the [HelpURL] attribute to shaders.

Motivation

I’m a Tech Artist here at InnoGames. One of my jobs is writing shaders that our artists can use to create beautiful materials for their models. These shaders can become quite complex and require documentation. The documentation must be accessible – ideally directly from the point where they are used: The Inspector in the Unity Editor.

Custom Attributes in Shaders

Unity already has some built-in attributes you can use in in properties section shaders of shaders such as [Toggle] or [Enum]. These would be used to limit the input or format the value of the property.

There are also attributes that don’t affect the property itself called property decorators. These attributes can be used to render headers and spaces like [Header] and [Space].

You can also create your own attributes by writing a MaterialPropertyDrawer class. To create a custom docorator the class name needs to end with “Decorator”. So let’s create a simple [HelpURL] attribute decorator:

HelpURLDrawer.cs
public class HelpURLDecorator : MaterialPropertyDrawer
{
   public override void OnGUI(Rect position, MaterialProperty prop, string label, MaterialEditor editor)
   {
      var content = new GUIContent(EditorGUIUtility.IconContent("_Help")) {tooltip = "Show Shader Documentation"};
 
      if (GUI.Button(position, content, new GUIStyle("IconButton")))
      {
        // Open URL in browser
      }
   }
}

Let’s write a simple Shader to test the attribute:

HelpURLTest.shader
Shader "HelpURLTest"
{
    Properties
    {
        [HelpURL]
        _MainTex ("Texture", 2D) = "white" {}
    }
 
    SubShader
   {
      Pass
      {
      }
   }
}

When we create a material from this shader and select it we can see that the property drawer has rendered a help icon inside the material. So far so good. But how can we specify the URL?

Specifying the URL

It turns out that this is tricky. We get some information about the property a MaterialProperty parameter of OnGUI. We can get all the values users get add to a property like a colorfloatvectorrange or texture. Because this is all types of properties that are supported. But to specify a URL we would need a string.

We will chose a hacky path here and expect the URL in the first line of the shader code. Then we can just read the shader code from file and parse the first line. The shader would look like this:

HelpURLTest.shader
// https://your.custom.shader.documentation.url
 
Shader "HelpURLTest"
{
    Properties
    {
        [HelpURL]
 
        _MainTex ("Texture", 2D) = "white" {}
    }
 
    SubShader
   {
      Pass
      {
      }
   }
}

And this would be the full code of the property drawer:

HelpURLDrawer.cs
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
 
public class HelpURLDecorator : MaterialPropertyDrawer
{
   public override void OnGUI(Rect position, MaterialProperty prop, string label, MaterialEditor editor)
   {
      var content = new GUIContent(EditorGUIUtility.IconContent("_Help")) {tooltip = "Show Shader Documentation"};
 
      if (GUI.Button(position, content, new GUIStyle("IconButton")))
      {
         var material = editor.target as Material;
         var shader = material.shader;
         string assetPath = AssetDatabase.GetAssetPath(shader);
         if (string.IsNullOrEmpty(assetPath))
         {
            return;
         }
 
         string line = File.ReadLines(assetPath).First();
         if (!line.StartsWith("//"))
         {
            return;
         }
 
         line = line.TrimStart('/', ' ');
 
         Help.BrowseURL(line);
      }
   }
 
   public override float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor)
   {
      return 20;
   }
}

Conclusion

The [HelpURL] attribute is a convenient way to provide custom documentation to your classes and with a little hack you can use the attribute to document your shaders, too.

By Andreas Hackel

Technical Artist @ InnoGames