specualr lighting, why use half vectors?

Started by
6 comments, last by kRogue 17 years, 9 months ago
ok, typically one uses as specular lighting this formaula (openGL vertex lighting does this): spec=pow( clamp(0,1,dot(halfV,normal)), power) where halfV=normalize( normalized_toLightVector + normalized_toEyeVector ) note the 3 normalizes, but actually the following is more accurate (do a Google to see why): spec=pow( clamp(0,1,dot(normalize(toEyeVector),refectV),power) where reflectV = 2*dot(normalized_toLightVector),normal) * normal - normalized_toLightVector note that then we need only normalize toLightVector (which is needed anyways for difffuse lighting) and the vector to the eye.. so why on earth is the first method often used? also note that the dot prodcut to calculate reflectV is used in diffuse anyways as is normalizing the vetor to the light... so the cost of doing this specular is pow, one extra dot and one extra normalize where as the other it is pow, one extra dot and two extra normalizes.... so why one Earth is the first method done so often?? escpecially considering if you do this at the fragment shader level... [Edited by - kRogue on July 8, 2006 1:30:44 PM]
Close this Gamedev account, I have outgrown Gamedev.
Advertisement
nothing?
Quote:Original post by kRogue
where halfV=normalize( normalized_toLightVector + normalized_toEyeVector )

AFAIK, halfV is actually defined as
halfV = (normalized_toLightVector + normalized_toEyeVector)*0.5;

You eliminate one subtract and dot product from not having to calculate the reflection vector.

HTH
The half-vector is actually different to the light vector, and so yields a different dot product. this is the reason why the specular highlight appears in the corner as opposed to in the centre.
The second equation looks interesting. Do you get the same result as the first?

If I count the number of oprtations for the first, it gives
7

If I count the number of operations for the second, it gives
10

Quote:
AFAIK, halfV is actually defined as
halfV = (normalized_toLightVector + normalized_toEyeVector)*0.5;


Nope, that's just a approximation.
The correct way is
halfV=normalize( normalized_toLightVector + normalized_toEyeVector )

Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
Quote:
If I count the number of oprtations for the first, it gives
7


not just the opreatyoin vount matters, but what: normalize is kind of pricey (sqrt typically, 3 mults and 2 adds, but if the hardware has that normalize is just as cheap as others, then the first would be better)

Quote:
If I count the number of operations for the second, it gives
10


typically vector add mults are fast operations in hardware, ie c.xyz=t*a.xyz + b.xyz is very cheap.. me thinks maybe just one operation in NVASM (I could be wrong though)...

but back to the original question, why?? Moreover the legnth of the vectors can be computet in the vertex shader and then used in fragment shader (at a cost to accuracy, but not so bad) anyone have ATI hardware to compare the 2 approaches (cause on my nVidia the 2nd is faster)
Close this Gamedev account, I have outgrown Gamedev.
On SM 2.0, normalize is 3 instructions and I beleive each is 1 cycle, so it is somewhat expensive as you said. On SM 3.0, you have a real normalize instruction. I don't have a reference with me on cycle count.

MAD is a single instruction (special circuit).
Most instructions have a clamp version to, which doesn't add any cycles.

For SM 2.0
First case
If I count all ops as 1 cycle
except If I count clamp as 0 cycle
except If I count norm as 3 cycle
total = 3 * 3 + 3 = 10

Second case
If I count all ops as 1 cycle
except If I count clamp as 0 cycle
except If I count norm as 3 cycle
except there is a MAD, so - 1
total = 2 * 3 + 7 - 1 = 12

I must be doing something wrong if you say it is faster.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
lets take a look: the real difference is what dot is done in the specular: halfV against normal or reflect against eye: (note both methods have same overhead, eye vector) and the other costs per light are normalized_toLightVector and dot(normalized_toLightVector, normal) {for diffuse lighting}

to find halfV: one vector add and a normaize
to find reflect one vector add because the dot used in it is already needed for diffuse lighting. {note that the clamp is done seperately for the diffuse lighting!)

so per light,

1st method: MAD, normalize and a dot --> 5 instructions (SM2.0)
2nd method: dot and MAD --> 2 instructions (SM2.0 and even older)

so on SM2.0, it _looks_ like the 2nd method take 3 less instructions... basicly the 2nd method replaces a normalize and MAD with just a MAD... but the clamp for diffuse has to be done seperately, so 2nd method is really replace MAD and normalize with a clamp and MAD. (I am not looking at the total operation count though, so the question comes down to what is the extra 2 or 3 instructions worth per light, eh?) on the other hand if one just uses

halfV= 0.5*(normalized_toLightVector + normalized_toEyeVector)

then the costs for the first method is better by not needing to do that clamp....

[Edited by - kRogue on July 19, 2006 12:34:46 PM]
Close this Gamedev account, I have outgrown Gamedev.

This topic is closed to new replies.

Advertisement