Unity 2.x Shader Conversion Guide
Reference Manual > ShaderLab Reference > Unity 2.x Shader Conversion Guide

Unity 2.x Shader Conversion Guide

Unity 2.x has many new features and changes to its rendering system, and ShaderLab did update accordingly. Most of the shaders that were used in Unity 1.x do work without any changes in Unity 2.x, but some of ShaderLab constructs need to be changed when you upgrade your project from Unity 1.x to 2.x. Most of the changes apply to advanced pixel lighting shaders only, and if you have trouble updating them - just ask for our help!

This document describes all the changes in detail, with instructions on how shaders should be updated.

New shader compilation directives

Unity 1.x used comment-like directives to compile Cg shaders, for example:

// vertex vert
// fragment frag
// autolight 7

would say that vertex program is named vert, fragment program is named frag and the shader supports all Unity's lights (assuming it's a pixel lit shader). The downside of such directives is that they are very fragile - if you'd accidentally wrote a comment somewhere like // vertex program here, Unity would think it's a Cg compilation directive!

Unity 2.0 introduces a new compilation scheme based on #pragma statements, which is much more robust. If no new-style directives are found in the shader, then Unity will try processing the old comment-like directives. So your shader will be compiled correctly, and Unity will print warnings to the console indicating how old-style directives should be replaced with new ones.

The above example converted to new directives would look like:

#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_builtin

SetTexture and register bindings aren't needed anymore with fragment programs

In Unity 1.x when using fragment programs, the texture samplers had to be explicitly bound to registers like this:

uniform sampler2D _BumpMap : register(s0); // bind to 1st register

and after the fragment program dummy SetTexture commands had to be written in this register order.

In Unity 2.0 this is not needed anymore; Unity will automatically allocate the samplers and figure out the textures that are used. So remove the register binding from samplers:

uniform sampler2D _BumpMap; // no more register worries!

and remove those dummy SetTexture commands after the fragment program.

There's one caveat though: because now sampler registers will be allocated automatically, vertex program code that used TRANSFORM_UV macro to apply texture tiling/offset may not work anymore (because it might be using wrong index in the new shader). In Unity 2.x the proper (and more optimal) way of applying texture tiling/offset is this:

// declare float4 properties for each texture before the vertex program,
// with _ST appended:
uniform float4 _MainTex_ST; // for _MainTex

and inside vertex program, use new TRANSFORM_TEX macro, that takes input texture coordinate (usually from vertex) and texture name:

TRANSFORM_TEX(v.texcoord, _MainTex)

Commands and constructs removed from ShaderLab

SeperateSpecular commandReplace it with SeparateSpecular, we just removed the typo-version.
TexCount commandThis was used in some old shaders, it has no purpose now.
Shorthand comparison functions in AlphaTest and ZTestShaderLab did support shorthand versions, like ZTest <=, replace with a normal version like ZTest LEqual
Program properties not in Properties blockSupport for those has been removed. They were only used by Water shaders, so all you have to do is update standard assets

Cg 1.5 caveats

In Unity 2.0 we upgraded to NVIDIA's Cg 1.5 shader compiler. Most existing shaders should continue to work, with one caveat: Cg 1.5 treats projective texture reads differently. If before you did a tex2Dproj with a four-element texture coordinate, you have to use a three-element texture coordinate now (otherwise Cg will turn it into a shadowmap lookup). That means code like this:

tex2Dproj( _MainTex, uv ); // where uv is float4

needs to be turned into:

tex2Dproj( _MainTex, uv.xyw ); // or just make uv to be a float3

Pixel-lit shader changes

The way pixel-lit shaders are constructed has changed significantly in Unity 2.0, partly to simplify the process and partly to support new features like realtime shadows. Here's a guide on how to convert a pixel-lit shader (in case you have one):

1. Convert to new compilation directives, like outlined above:

2. Convert vertex-to-fragment structure.
Before you had to write two structures (often named v2f and v2f2), one with V2F_LIGHT_COORDS macro inside and the other without. In Unity 2.x you only have to write a single structure, and remove bindings to individual TEXCOORDs as well. So old code like this:

struct v2f {
    V2F_POS_FOG;
    float3  uvK       : TEXCOORD0;
    float2  uv2       : TEXCOORD1;
    float3  viewDirT  : TEXCOORD2;
    float3  lightDirT : TEXCOORD3;
    V2F_LIGHT_COORDS(TEXCOORD4);
}; 
struct v2f2 { 
    V2F_POS_FOG;
    float3  uvK       : TEXCOORD0;
    float2  uv2       : TEXCOORD1;
    float3  viewDirT  : TEXCOORD2;
    float3  lightDirT : TEXCOORD3;
};

should become this:

struct v2f {
    V2F_POS_FOG;
    LIGHTING_COORDS
    float3  uvK;
    float2  uv2;
    float3  viewDirT;
    float3  lightDirT;
}; 

The changes are:

3. Pass lighting information in the vertex program
Usually at the end of the vertex program a PASS_LIGHT_COORDS macro was used. In Unity 2.x, replace it with TRANSFER_VERTEX_TO_FRAGMENT macro. So code like:

PASS_LIGHT_COORDS(1); // or some other number, indicating the texture stage for attenuation textures

becomes:

TRANSFER_VERTEX_TO_FRAGMENT(o); // 'o' being the output structure name

4. Remove register bindings from samplers like outlines above.
Whenever there's code like:

uniform sampler2D _BumpMap : register(s0);

turn it into

uniform sampler2D _BumpMap;

5. Change signature of the fragment program
There are no two separate structures for passing information from vertex program to fragment program, so change code like this:

float4 frag (v2f2 i, LIGHTDECL(TEXUNIT2)) : COLOR

simply into this:

float4 frag (v2f i) : COLOR

6. Use new macro for light attenuation
In the fragment program, replace all LIGHTATT occurences with LIGHT_ATTENUATION(i), in this case i being the input structure name.

7. Remove SetTexture commands after fragment program
SetTexture commands are not necessary anymore when fragment programs are used. Just remove them!