まだちょっとしっかりと理解できていませんが、こちらの記事(Light calculations inside Unity's CG shader)を参考にさせて頂きました。
"LightMode"="Vertex"
を使う
Tagsに"LightMode"="Vertex"
を指定することで、複数ライトがある場合に、それぞれのライトの位置や色にアクセスできるようになります。
ライトの位置と色を取得する
ライトの位置と色はunity_LightPosition[n]
とunity_LightColor[n]
でアクセスできます。
複数ある場合は配列になっているので適宜添字を使ってアクセスします。
注意点
ひとつだけ注意点があります。
通常、ライトの位置は_WorldSpaceLightPos0
で取得するかと思いますが、上記の場合はワールド空間上ではなく、どうやらビュー座標空間としての位置となります。なので計算する際は注意が必要です。
(位置をそのまま色として出力してみると、視点移動するだけで色が変わるのが分かります)
位置を計算する
ビュー座標系なので計算しやすいように座標変換します。
Directional lightとそれ以外で若干、計算が異ります。
if(unity_LightPosition[0].w == 0.0) { // `w`が0の場合はDirectional light.
float3 lightPos = normalize(mul(unity_LightPosition[0], UNITY_MATRIX_IT_MV).xyz);
}
else { // それ以外はSpot lightかPoint light.
float3 lightPos = normalize(mul(unity_LightPosition[0], UNITY_MATRIX_IT_MV).xyz - vertex.xyz);
}
Directional lightの場合は「どの方向から来ているか」の値が入っています。
なので光の方向が仮に0, -1, 0
(地面が垂直に照らされている)の場合は、変数には0, 1, 0
という値が入ります。
ライトの位置に関係なく、ライトの方向(パラメータ的にはrotation)で決まります。
一方、それ以外のライトに関しては変数名通り位置が入っています。
座標変換でローカル座標空間に変換した上で、自身の頂点位置との差分を取って方向を計算します。
スポットライトなどの情報を得る
スポットライトやポイントライトは、その位置だけでなく、範囲や角度などライティングに必要なデータがあります。
そうしたデータについてはこちらの記事(Cg Programming/Unity/Light Attenuation)が参考になります。
_LightTextureB0
や_LightMatrix0
などを使って必要な情報を得るようです。