Recently while programming specular bump-mapping on a Geforec3/4 the highlights would look horrible due to low precision banding issues. I was rendering mostly smooth surfaces (ie steel/wood) with occasional bumpy parts. (ie wood grain/ bolts/ rivets etc)
I could solve the banding problems with a dependant texture lookup but the performance hit was too great. I was thinking of just using per-vertex specular but then the bumpy areas looked bad. So this is what I did:
-Calculate per-vertex specular
(In pixel program)
-Calculate per-pixel specular
-Dot3 the bump normal with (0,0,1) (ie straight up) and if the result is > 0.75 lerp between the per-vertex and per-pixel by the scaled amount. The end result is the per-vertex specular color is used on the smooth parts, the per-pixel specular is used on the bumpy parts.
The Dot3 against (0,0,1) essentially just takes the z (or b) component of the bump map lookup. This value is biased then x2 (to get -1…1 range) then has 0.75 subtracted and is multiplied by 4 and saturated.(so 0.75…1.0 range gets mapped to 0.0…1.0 range) This value is then used to lerp.
So in code (sorry for the DX likeness):
add_x4_sat scale_value, bumptex_bx2.b, -0.75
lerp specular_value, scale_value, vertex_specular_value, per_pixel_specular_value
I was able to co-issue both instructions so I got this for free.(multiplying by specular color was in a seperate instruction) The end result actually looks quite good and seems to take away a bit of the “plastic” look bump-specular can look like. (In fact I now use this as the high end card code path)