Z instrukcji dot korzystamy przy liczeniu oświetlenia w shaderze. Przykładowo:
color = texture * dot(N, L);
Nie wszyscy jednak są świadomi, że dot można użyć w zupełnie innych celach. Najpierw zobaczmy czym ta instrukcja jest (za Cg Reference Manual):
float dot(float4 a, float4 b)
{
return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
}
Do czego jeszcze użyć iloczynu skalarnego (bo tak się właśnie nazywa ta operacja)? Np. do konwersji kolorów:
float4 pixel(float4 c : COLOR) : COLOR
{
float bw = c.r * 0.59 + c.g * 0.3 + c.b * 0.11;
return float4(bw, bw, bw, 1);
}
Wersja z prostym filtrem RGB -> BW potrzebuje siedmu instrukcji Pixel Shader 2.0:
def c0, 0.30000000, 0.58999997, 0.11000000, 1.00000000 dcl v0.xyz mul r0.x, v0.y, c0 mad r0.x, v0, c0.y, r0 mov r0.w, c0 mad r0.xyz, v0.z, c0.z, r0.x mov oC0, r0
Wersja z dot:
float4 pixel2(float4 c : COLOR) : COLOR
{
float bw = dot(c.rgb, float3(0.59, 0.3, 0.11));
return float4(bw, bw, bw, 1);
}
def c0, 0.58999997, 0.30000000, 0.11000000, 1.00000000 dcl v0.xyz mov r0.w, c0 dp3 r0.xyz, v0, c0 mov oC0, r0
I co? Dwie instrukcje mniej! Niby niewiele, ale dla filtru nałożonego na obraz HD to ponad 4 mln taktów shadera mniej (bez AA). Dlatego warto pamiętać o takiej drobnej optymalizacji, zwłaszcza, że kompilator Cg (notabene bardzo inteligentny) nie był w stanie uprościć pierwszego shadera do drugiego nawet dla stałego wektora (0.59, 0.3, 0.11).