1

I am currently looking for information on how to get the final flat color value of a given face within a lit 3d scene. I have a Material class that contains the following 4 colors:

ambient, specular, diffuse & emissive

My Color class has methods for simple blend effects such as add, multiply etc

From a list of lights, camera position, material, face normal & face position. I would like to calculate the final color of a face to be filled using a software render pipeline using the standard 4 color material model.

Edric
  • 24,639
  • 13
  • 81
  • 91
Gary Paluk
  • 1,038
  • 1
  • 14
  • 28

2 Answers2

3

I assume you want the standard Phong or Blinn-Phong lighting model, which the fixed-function GL uses, too.

The emissive term is the color the material emits by itself (for example when modeling a light). So it just adds to the final color.

color = emissive;

The ambient term simulates the indirect lighting computation due to infinitely reflected light, so it doesn't depend on the position of the light and is approximately everywhere. So the material's ambient is just multiplied by the light's color and adds to the final color.

color += ambient * lightColor;

The diffuse term simulates a standard Lambertian reflector, that reflects light equally in all directions. It depends on the angle between the direction to the light and the surface normal, with smaller angles resulting in more light.

lightDir = normalize(lightPos-facePos);
color += dot(lightDir, normal) * diffuse * lightColor;

The specular term finally simulates specular surfaces, that reflect more light into a singular direction (the perfect reflection direction). So it depends on the direction you are looking onto the face in. Additionally the reflectivity depends on another parameter that describes the roughness of the surface (or actually its shininess which is also the name GL uses, with higher values making sharper highlights and thus being more "shiny").

viewDir = normalize(cameraPos-facePos);
halfVec = normalize(lightDir+viewDir);
color += pow(dot(normal, halfVec), shininess) * specular * lightColor;

Of course the ambient, diffuse and specular term have to be computed for every light.

For more complex lights other than simple point lights without distance attenuation, you have to consider other things, but this simple model should get you started.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
  • Thank you. If the Color had to be applied in a kind of 'component-wise' situation would it look like: color.red += pow(dot(normal, halfVec), shininess.red) * specular.red * lightColor.red; color.blue += pow(dot(normal, halfVec), shininess.blue) * specular.blue * lightColor.blue; color.green += pow(dot(normal, halfVec), shininess.green) * specular.green* lightColor.green; – Gary Paluk Aug 14 '11 at 15:42
  • @Gary Essentially yes, but the shininess is just a scalar value, only the colors have 3/4 components. – Christian Rau Aug 14 '11 at 15:45
  • Hey Christian, can I just check; with the pow function you describe, is the first parameter the 'power' parameter and the second, the 'base'? – Gary Paluk Aug 15 '11 at 07:08
  • @Gary No, the dot product (quasi the angle/cos between the directions) is the base and the shininess the exponent. So that the value (highlight) drops faster to the sides of the perfect angle (0) when the shininess is greater, producing a sharper highlight. – Christian Rau Aug 15 '11 at 11:47
  • Hey Christian, I'm having difficulties with the light looking either unnatural or generally terrible. I've tried to implement this as you outline, I've uplaoded the code to: https://gist.github.com/1148516 and an example of the result I'm getting to: http://www.swfcabin.com/open/1313471851 - I wondered if their is anything obvious that is wrong. I'm pretty sure my color system is ok. – Gary Paluk Aug 16 '11 at 06:09
  • @Gary First, you multiply the ambient by the lightColor (which is correct), but it seems you overwrite the ambient with this product. So the ambient of the nth light is the product of all light colors and the material color, which is wrong (but it won't do any harm to your example). The real problem is, that the dot products can be negative. What you should do is replace `dot(normal,lightDir)` by `max(dot(normal,lightDir), 0)` (I didn't include this in the answer for the sake of simplicity). Likewise the specular computation only has to be done if this clamped dot product is != 0. – Christian Rau Aug 16 '11 at 12:52
  • 1
    @AzadSalahli Well, a standard 3D vector normalization, what else could it mean? – Christian Rau Dec 22 '12 at 21:53
  • Oh, I got it. Thank you! Sorry for a rather dumb question, but I couldn't help it, since I just started learning about 3D graphichs :) – Azad Salahli Dec 22 '12 at 21:59
1

The colors are just added together:

ambient + diffuse + emissive + specular

Ambient is the basecolor. Diffuse is the material's color multiplied with the lighting intensity. Emissive is just added to create the illusion of some global illumination. The last one is the specularcolor which is muliplied by the result of the specular lighting calculation.

So it becomes:

ambientcolor + diffusecolor * diffuselighting + emissivecolor + specularcolor * specularlighting

In my experience this is not always the lightingmodel you want. Specifying different hues for these colors results in unnatural lighting-behavior, but that is how the models of the fixed function pipeline of OpenGl and DirectX work.

Tobias Schlegel
  • 3,970
  • 18
  • 22