Many thanks to Jessy for helping with this question.
Vertex colours can be animated using a shader by introducing two properties. One for each simulated light source. The red colour component of a vertex colour can be used to illuminate one light source whilst the blue for another. It is easily possible to have 4 simulated light sources (R, G, B, A).
I have called these properties Emission A and Emission B and a value of 0 indicates that the vertex colour component should not contribute to lighting whereas 1 indicates full contribution.
These properties can be easily animated using the animation editor in Unity. Alternatively it is also possible to script the animation if need be.
I want to use these values to simulate two light sources smoothly dimming, but I suspect that there are many other applications of this technique.
I am aiming for iOS platforms and so have created two alternative implementations to compare performance. I do not at this time know which of the two variants performs more efficiently.
EDIT: The first approach seems to perform more efficiently than the second. The first approach does not include vertex lighting. I will add that to the answer if I can figure it out.
Cg Vertex and Fragment shader as follows:
Shader "Custom/Animated Vertex Emission" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_EmissionA ("Emission A", Range(0, 1)) = 1
_EmissionB ("Emission B", Range(0, 1)) = 0
}
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
float4 color : COLOR;
};
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
fixed4 color : COLOR;
};
sampler2D _MainTex;
float _EmissionA;
float _EmissionB;
float4 _MainTex_ST;
v2f vert(appdata v) {
v2f o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
float c = min(1, _EmissionA * v.color.r + _EmissionB * v.color.b);
o.color = float4(c, c, c, 1);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
half4 frag(v2f i) : COLOR {
half4 outColor = tex2D(_MainTex, i.uv);
return outColor * i.color;
}
ENDCG
}
}
Fallback "Custom/Unlit"
}
Unity Surface Shader:
Shader "Custom/Animated Vertex Emission" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_EmissionA ("Emission A", Range(0, 1)) = 1
_EmissionB ("Emission B", Range(0, 1)) = 0
}
SubShader {
Tags { "RenderType"="Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float3 color : COLOR;
};
sampler2D _MainTex;
float _EmissionA;
float _EmissionB;
void surf(Input IN, inout SurfaceOutput o) {
float3 temp = tex2D(_MainTex, IN.uv_MainTex).rgb;
float c = min(1, _EmissionA * IN.color.r + _EmissionB * IN.color.b);
o.Albedo = half3(c * temp.r, c * temp.g, c * temp.b);
}
ENDCG
}
Fallback "Custom/Unlit"
}