Perpixel specular thoughts


I was thinking about how to implement specular ligthing on a perpixel basis in my engine but I have found a serious problem.

Here is how my geometry is rendered without specular:

  1. Draw geometry with ambient lighting
  2. Loop through all light sources
    2.1. Draw shadow volumes
    2.2. Add diffuse result
    2.3. Add attenuation result
  3. Multiply result from (1) and (2) with texture map

This is working really good. But what if I want to add specular now? The problem is that I can’t just insert specular into (2) because the specular result needs to be added to the result of (1),(2) and (3); it needs to be applied after the decal pass (3)
So I would have to loop throgh all lights angain in a fourth step; the problem here are the shadow volumes; to get correct results, I would have to draw all the shadow volumes in my step (4) again.

  1. Loop through all lights
    4.1. Draw shadow volumes
    4.2. Add specular result

Drawing all shadow volumes twice would of course cost damn much performance since they eat so much fillrate.

Am I missing something here? Does someone know a better solution?

Thanks in advance

[This message has been edited by LaBasX2 (edited 02-09-2002).]

I’m wondering if the way I am calculating the diffuse result is correct; I’m looping through all lights and add the results of the diffuse bump mapping together. When all this is done, I multiply the framebuffer with the polygon’s base (decal) texture, similar to lightmapping. Is this the correct way or, or is the following way better?

  1. Draw polys with ambient color
  2. Loop through all lights; for every light add bump mapping result multiplied with the base texture to the framebuffer

Is this correct or is there a better way? Please help me.


hm… the diffuse therm works like this:

sum(light[i] dot normal) * diffusecolor (==decalmap)

or in simple math:

(d0 + d1 + d2 … )*dc
with d0 to dn = clamped(light[n] dot normal)
and dc = decalmap diffusecolor

simple math rules now say that you can kill the brakets () with this simple therm:

d0dc + d1dc + d2*dc…

so it doesn’t mather that much… (not at all except for precision issues…)

Thanks for your reply, davepermen.

I’m not sure that both equations produce the same result.

Isn’t sum(light[i] dot normal) automatically clamped since the buffers can only handle values between 0 and 1 (respectively 0 and 255)? So it is in the range 0 to 1 when being multiplied with the decal texture. That means that the polygon will never become brighter than the diffuse color.

But the second equation can make the polygon brighter than it’s decal texture, since the decal texture can be added several times.

I’m not quite sure what is the correct way for lighting…


this one:

d0dc + d1dc + d2*dc
if 2 lights shine on your half-white (grey with RGB(127,127,127)) plane, it gets white (if both lights are white).

does make sence to get results bigger then the dc-texture…


Thanks again!

You’re right, that makes sense. But I still have another case where I am not sure:

my decal texture has the color (128, 255, 0) that’s some sort of bright green
now 2 white lights are shining onto that surface; the final color would thus be (128, 255, 0) * 2 = (255, 255, 0) (yellow)

Is that still correct? I don’t know much about light theory so I can’t tell you but I have never seen an object in the real world that is suddenly changing its color from green to yellow when it is lighted by another (white) lamp. Hmm, I guess I must be missing something here; somehow that’s all confusing


correct results you’ll never get on hardware that clamps the color to the range of 0 and 1… never…

but it’ll take some time till our colors are all floatingpoint-values…