# Trying to understand light on Opengl, how to simulate a realistic sun light?

I don't know if I'm doing something wrong or missing anything but I want to simulate sun light, like in a sunny day.

When the object is facing the directional light, it's well lit and there's no problems there. If I go around the object and look at it's back, it's dark. It's not too much dark because I'm using GL_AMBIENT but it's still too dark for a sunny day. If I increase the value, it will never look better because the side of the object facing the light will be too bright.

And there's another annoying issue with the ambient light, when looking at the back of the object, I can't see any shape, only a plain color. Hard to explain, here's some pictures:

Object Front: http://i.stack.imgur.com/YW53X.png
Object Back: http://i.stack.imgur.com/Qufha.png

As you can easily see, the front side looks nice, you can see the shape of that red thing. On the back side, it's plain, you can't see the same shape.

Now, I know that I'm looking at the back of an object and I'm looking in the direction of the light and it should be darker than the front side. But it shouldn't look so plain like this. That's not what we see when going against the sun light looking at some object, we see that the objects form some shape.

How can I have the same (or similar) effect on OpenGL?

My light is currently defined like this:

float posLight0[4] = {-1.0f, 1.0f, 1.0f, 0.0f};
float ambLight0[4] = {0.5f, 0.5f, 0.5f, 0.5f};

glLightfv(GL_LIGHT0, GL_POSITION, posLight0);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambLight0);

• I suggest that you consider using shaders, if possible. The OpenGL fixed-function pipeline uses a fairly simple lighting model, whereas shaders give you full control over the maths. – Incredulous Monk Apr 6 '11 at 2:09

With the ambient light your objects appear too bright because the diffuse light is added to the ambient light, and the diffuse light defaults to 1.0. This adds up to 1.5, and everything above 1.0 is clamped. Set the diffuse light to 0.5:

float difLight0[4] = {0.5f, 0.5f, 0.5f, 1.0f};
glLightfv(GL_LIGHT0, GL_DIFFUSE, difLight0);


The second problem is harder to solve. You can try adding some fine details to the surface such as texture or bump map. In OpenGL the ambient light is constant, but in real world that is never the case. To simulate the real world, some form of global illumination solution is needed. Ambient occlusion helps a lot here, but is harder to implement than just setting OpenGL states. You could bake the ambient occlusion to the vertices of your model in your 3D modeling software or use SSAO, but I'm not going to the details.

What you can easily do is add another dimmer light source from some other direction (e.g. opposite direction). This will not be realistic, but at least it will give some shape for the back sides of your objects as well.

Also consider adding specular highlights to your application. It will make objects shiny.

float specLight0[4] = {0.5f, 0.5f, 0.5f, 1.0f};
glLightfv(GL_LIGHT0, GL_SPECULAR, specLight0);
glMaterialfv(GL_FRONT, GL_SHININESS, 10.0f); // Shininess between 0 and 128


You can also specify light and material colors separately, especially if the defaults are not suitable for you.

• So there's no simple and direct way to do what I want in OpengGL... Too bad. Maybe I'll try adding another light source, but how exactly do I specify the light intensity? – Ricardo Amaral Apr 5 '11 at 10:43
• The GL_SPECULAR and GL_SHININESS don't seem to produce any effect though... I did change glMaterialfv to glMateriali because it was not compiling. And also tried a larger value like 128. It looks the same to me... Maybe the problem is on my loaded model (obj/mtl), will have to take a look. – Ricardo Amaral Apr 5 '11 at 11:30
• @Nazgulled Just checked that the light0 specular defaults to 1.0, but the material specular defaults to 0.0. So change glLightfv(GL_LIGHT0, GL_SPECULAR, specLight0); to glMaterialfv(GL_FRONT, GL_SPECULAR, specLight0); It's also good to set glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); or the specular might be calculated incorrectly when the camera is rotating. – msell Apr 6 '11 at 9:15
• @Nazgulled For the secondary light, set the ambient and specular to zero and some small value like 0.2 for the diffuse. You can also set the ambient of all lights to zero and use global ambient with GL_LIGHT_MODEL_AMBIENT instead. – msell Apr 6 '11 at 9:18

OpenGL's ambient light is a single color, but ambient light in the real world is usually brighter from above and darker from below. You can approximate this in OpenGL by setting the ambient light to very dark blue, and adding a dark blue directional light pointing downward. That, plus a bright white directional light coming from wherever the sun is, can approximate outdoors light pretty well.

What you really should do is write a shader that calculates light per pixel, but getting there from where you are is going to take a little time.

The answer you have got here is pretty good. Just one addition. Once you will want to have it nicer, try implement atmospheric scattering