Shader Input Structure

The basic form of a surface shader is:

struct Input {
    float4 color : COLOR;
};
void surf (Input IN, inout SurfaceOutput o) {
    o.Albedo = float4(1.0, 1.0, 0.0, 1.0);
}

It's not completely obvious, because unlike the appdata_full structure, there's no immediate reference to look up the structure.

However, the unity documentation has this to say on the topic:

The input structure Input generally has any texture coordinates needed by the shader. Texture coordinates must be named “uv” followed by texture name (or start it with “uv2” to use second texture coordinate set).

Additional values that can be put into Input structure:

float3 viewDir - will contain view direction, for computing Parallax effects, rim lighting etc.

float4 with COLOR semantic - will contain interpolated per-vertex color.

float4 screenPos - will contain screen space position for reflection or screenspace effects.

float3 worldPos - will contain world space position.

float3 worldRefl - will contain world reflection vector if surface shader does not write to o.Normal. See Reflect-Diffuse shader for example.

float3 worldNormal - will contain world normal vector if surface shader does not write to o.Normal.

You can also take uv coordinates for a texture using uv_NAME.

To use these properties, add them to the input structure:

struct Input {
  float2 uv_MainTex;
  float3 worldNormal;
  float3 viewDir;
};

Passing data from the vertex program

Provide a second argument to the vertex function for this to work.

Shader "Example/Custom Vertex Data" {
  Properties {
    _MainTex ("Texture", 2D) = "white" {}
  }
  SubShader {
    Tags { "RenderType" = "Opaque" }
    CGPROGRAM
    #pragma surface surf Lambert vertex:vert
    struct Input {
      float2 uv_MainTex;
      float3 customColor;
    };
    void vert (inout appdata_full v, out Input o) {
      UNITY_INITIALIZE_OUTPUT(Input,o);
      o.customColor = abs(v.normal);
    }
    sampler2D _MainTex;
    void surf (Input IN, inout SurfaceOutput o) {
      o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      o.Albedo *= IN.customColor;
    }
    ENDCG
  } 
  Fallback "Diffuse"
}

Notice the use of UNITY_INITIALIZE_OUTPUT to initialize the output structure in the vertex program.

As noted above, certain Input structure names (Eg. uv_NAME) are reserved and may not be used in this way.