Tuesday, December 20, 2011

Unity3D EditorWindow Formatting Tip

During the past several months I've done a bit of work extending the Unity3D editor to create custom editor functionality for my upcoming game.  Unity makes it ridiculously easy to implement custom functionality in the editor, however their documentation can leave something to be desired.  One of the hidden nuggets I found is EditorGUIUtility.LookLikeControls() , which exposes custom formatting for certain EditorGUILayout elements.




Here's an example of using EditorGUILayout.EnumPopup() and EditorGUILayout.LabelField() to show some enum and string values.  As you can see the description label on the left is cut off, which makes this GUI very unusable.  EditorGUIUtility.LookLikeControls() lets you change the default pixel size of one or both of the content display fields for these methods, so you can make your GUI's much more readable.



Here's the same menu using EditorGUIUtility.LookLikeControls(250), which expands the first content zone to 250 pixels, and provides a nice amount of space to clearly mark the inputs for the menu.  And as you can see at the bottom, calling EditorGUIUtility.LookLikeControls() with no params will restore the GUI system to the default layout for these elements.

Saturday, September 24, 2011

Handling Texture Tiling and Offset in a Unity3d Vertex and Fragment Shader using TRANSFORM_TEX macro

When doing some test work, I found my Cg shader wasn't handling texture offset and tiling properly, resulting in distortion such as below:

The Unity shader on the left properly handles a 3x tiling factor for the texture, while my shader on the right doesn't properly handle the same 3x tiling factor



My shader setup was pretty simple, here's a snippet of the important parts:

#include "UnityCG.cginc"

sampler2D _MainTex;
float4 _Color;

v2f vert ( appdata_base v )
{
    v2f o; 

    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

    // Texture offset - BAD
    o.uv = v.texcoord;
    return o;
}

half4 frag (v2f i) : COLOR
{    
    return tex2D(_MainTex, i.uv) * _Color;
}

I bolded the problematic part, which is the Texture UV handling in the 'vert' program.  Simply grabbing the v.texcoord will work when there is not tiling or offsets in the texture, but breaks once those elements are introduced

After snooping around, I found the solution is to use the TRANSFORM_TEX macro in the UnityCG.cginc to make sure the texture's offset and tiling are properly applied.  A small caveat to this is you must, "declare float4 properties for each texture before the vertex program, with _ST appended" (Quoted from Unity3d shader docs).

Here's a snippet of my shader with the new changes:

#include "UnityCG.cginc"

sampler2D _MainTex;
float4 _Color;
uniform float4 _MainTex_ST; // Needed for TRANSFORM_TEX(v.texcoord, _MainTex)

v2f vert ( appdata_base v )
{
    v2f o; 

    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

    // Texture offset - GOOD
    o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    return o;
}

half4 frag (v2f i) : COLOR
{    
    return tex2D(_MainTex, i.uv) * _Color;
}

With this happy little change, our shader now properly handles the tiling and offsets of the texture.
 

For those curious, I gleaned this information from the Unity3D Vertex and Fragment Programs and the ancient Unity 2.x Shader Conversion Guide.  The info pulled from the Shader conversion guide regards the _MainTex_ST property needed for TRANSFORM_TEX to work. 

UPDATE - Dec 1, 2013 - The Unity 2.x Shader Conversion Guide seems to have disappeared from the internet.  This information is all still relevant for Unity 4.x release versions