Expose float2/vector2 property from shader to Unity material inspector

14.9k Views Asked by At

In a Unity shaderlab shader you can expose shader properties to the material inspector in the editor. This can be done by placing the properties you want to expose in the Properties section like so

Properties
{
    _SomeFloat("A Float", float) = 5
}

Unity defines a list of properties in the documentation here.

However this does not include any form of float2 or vector2, just single Float or Vector which consists of xyzw.

I tried setting the property type to float2 And Vector2

_SomeFloat("A Float", float2) = (5,5)
_SomeFloat2("A Float2", Vector2) = (5,5)

which both return the error Parse error: syntax error, unexpected TVAL_ID at line 7

or trying to cut down the Vector in half by setting only half the members

_SomeFloat("A Float", Vector) = (5,5)

which return the error Parse error: syntax error, unexpected ')', expecting ','

I could just use the Vector type and only use its xy, but that makes for unclear UI as there are now two unused elements in the inspector, and could not find a Property Attribute or Drawer (Such as HideInInspector) that allows you to hide the zw values from the inspector.

So is there a way to expose a float2 using a property type? Or maybe an alternative where you can place two float properties next to each other in the editor like Tiling/Offset drawer is in the standard 2D property type (Maybe something similar to [EditorGUILayout.BeginHorizontal][2])?

2

There are 2 best solutions below

2
On BEST ANSWER

From quick search I've found there's MaterialPropertyDrawer that can be extended to add custom tags in shader inspectors (ref: https://docs.unity3d.com/ScriptReference/MaterialPropertyDrawer.html).

Thus, you could use Vector property in shader, create custom attribute, let's say, [ShowAsVector2] and make MaterialPropertyDrawer for it, which would only show two input fields, and assign their value to vector's x and y values. This would result in shader property written as:

[ShowAsVector2] _Position2D("Position", Vector) = (0, 0, 0, 0)

0
On

This is an extension to @tsvedas's answer.

using UnityEngine;
using UnityEditor;


/// <summary>
/// Draws a vector2 field for vector properties.
/// Usage: [ShowAsVector2] _Vector2("Vector 2", Vector) = (0,0,0,0)
/// </summary>
public class ShowAsVector2Drawer : MaterialPropertyDrawer
{
    public override void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor)
    {
        if( prop.type == MaterialProperty.PropType.Vector )
        {
            EditorGUIUtility.labelWidth = 0f;
            EditorGUIUtility.fieldWidth = 0f;

            if (!EditorGUIUtility.wideMode)
            {
                EditorGUIUtility.wideMode = true;
                EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - 212;
            }

            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = prop.hasMixedValue;
            Vector4 vec = EditorGUI.Vector2Field(position, label, prop.vectorValue);
            if (EditorGUI.EndChangeCheck()) {
                prop.vectorValue = vec;
            }
        }
        else
            editor.DefaultShaderProperty( prop, label.text );

    }
}

Simply put this script in an Editor folder, and you should be able to only see the x and y coordinates.