# Dot3 Specular

How do I exponentiate the specular dot3 term to n, knowing that I have my decal modulated with diffuse term as follows:
final_color = decal * dot3_diffuse +
dot3_specular^n
where n is shininess factor.
I want to use pure OpenGL 1.3 commands (dot3, combine mode, blending, …)

Thanks.

x^n = xxx*…*x where there are n times an x…
to power up, you have to multily like stupid…

tipp:
x^16:
x = xx; //^2
x = x
x; //^4
x = xx; //^8
x = x
x; //^16

how to get this into the standart ones… well i think you need 2 passes…

With register combiners you can do it in less passes, but it’s hardware-specific.

If your specular color is monochromatic, you can compute separately the diffuse component in the RGB buffer and the specular in the Alpha buffer, and then add the two buffers ; eg :
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); // deactivate Alpha writing
glDisable(GL_BLEND);
draw_decal(); // draw the decal in RGB buffer
glEnable(GL_BLEND);
glBlendFunc(GL_DST_COLOR, GL_ZERO);
draw_diffuse(); // multiply decal by diffuse in RGB buffer
glDisable(GL_BLEND);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); // activate Alpha writing and deactivate RGB writing
draw_specular(); // draw the specular “intensity” in the Alpha buffer
glEnable(GL_BLEND);
glBlendFunc(GL_DST_ALPHA, GL_ZERO);
for (int i=1; i<shininess(); i++) draw_specular(); // multiply specular^i by specular in Alpha buffer
glBlendFunc(GL_DST_ALPHA, GL_ONE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); // activate RGB writing for final operation
glColor3fv(specular_color());
draw_geometry(); // draw geometry without texture

the shininess() function may return a positive integer, and the specular_color() function may return a GLfloat containing RGB values of the specular color.

(note that some optimizations can be done with ARB_multitexture and NV_blend_square extensions that are widely supported)

nonetheless there are two major limitations :
1- you have to allocate an Alpha buffer, and you have to reserve it for the dot3 effect,
2- you may not be able to use translucent textures unless you call glBlendFunc differently.

But what about if I have multiple lights in a scene and want to take into account their specular contribution?

Originally posted by wis mak:
[b]How do I exponentiate the specular dot3 term to n, knowing that I have my decal modulated with diffuse term as follows:
final_color = decal * dot3_diffuse +
dot3_specular^n
where n is shininess factor.
I want to use pure OpenGL 1.3 commands (dot3, combine mode, blending, …)

Thanks.[/b]

to approximate (N.H)^16 for specular lighting, you can use:

((N.H)^2 - 0.75)*4

If you look at a graph of the above function over the domain [0.0, 1.0] it looks pretty close to f(x)=x^16

[This message has been edited by chrisATI (edited 07-10-2002).]

chris : such an optimization is very handy for per-fragment low-level extensions such as register combiners (and certainly with fragment shaders too).
I’ve already seen such approximation in Mark Kilgard’s “Practical and Robust Bump-mapping for Today’s GPUs” with the formula : (0.4 * ((H.N) - 0.75))^2

wis mak : the piece of code that I wrote merely does :
{
draw decal in RGB buffer => so that RGB buffer contains ‘decal’
multiply RGB buffer by diffuse => so that RGB buffer contains ‘decaldiffuse’
draw specular in Alpha buffer => so that Alpha buffer contains ‘specular intensity’
modulate Alpha buffer with specular color and add it to RGB buffer => so that RGB buffer contains 'decal
diiffuse+specular intensityspecular color’
}
because 'specular intensity
specular color’ represents the total specular contribution, the final RGB buffer contains ‘decal*diffuse+specular’

to do it with multiple lights, add specular contributions of each light separately by clearing the alpha buffer when you need a new specular contribution.
First, add the diffuse contributions of each light. Render this contribution in RGB buffer.
Then modulate the total diffuse contribution with decal. Render this into RGB buffer.
Then, for each light :
{
draw the specular intensity in Alpha buffer.
modulate this Alpha buffer with specular color and add it to RGB buffer
}

The would look like that (still, without optimizations) :
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); // deactivate Alpha writing
glDisable(GL_BLEND);
glColor3f(0,0,0); // black color to clear the buffer
draw_geometry(); // draw geometry without texture. it clears the RGB buffer
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
for (i=0; i<number_of_lights(); i++) // in this loop, all diffuse contributions will be rendered
{
draw_diffuse(i); // add decal contribution of light i, in RGB buffer
// At this point, RGB buffer contains : (diffuse_0 + … + diffuse_i) where i is the index of the current light in the loop
}
// At this point, RGB buffer contains : (diffuse_0 + diffuse_1 + … + diffuse_n) where n is the number of lights
glBlendFunc(GL_DST_COLOR, GL_ZERO);
draw_decal(); // modulate the total diffuse contribution with the decal, in RGB buffer
// At this point, RGB buffer contains : (diffuse_0 + diffuse_1 + … + diffuse_n)*decal
for (i=0; i<number_of_lights(); i++) // in this loop, all specular contributions will be rendered
{
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); // activate Alpha writing and deactivate RGB writing
glDisable(GL_BLEND);
glColor4f(0,0,0,1); // full alpha to clear the buffer
draw_geometry(); // draw geometry without texture. it clears the Alpha buffer
glEnable(GL_BLEND);
glBlendFunc(GL_DST_ALPHA, GL_ZERO);
for (int j=0; j<shininess(); j++) draw_specular(i); // render specular_intensity^n for light i, in Alpha buffer
glBlendFunc(GL_DST_ALPHA, GL_ONE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); // activate RGB writing to add specular contribution of light i
glColor3fv(specular_color()); // note that this specular color may be dependant to the light (eg one light may have a white specular color but a second light may have a yellow specular color)
draw_geometry(); // draw geometry without texture. it adds specular contribution of light i, in RGB buffer
// At this point, RGB buffer contains : (diffuse_0 + diffuse_1 + … + diffuse_n)*decal + (specular_0 + … + specular_i)
}
// At this point, RGB buffer contains : (diffuse_0 + diffuse_1 + … + diffuse_n)*decal + (specular_0 + specular_1 + … + specular_n)