OpenGL lighting small objects? - opengl

I'm having a problem with lighting when dealing with really small particles. I'm doing particle-based fluid simulation and am right now rendering the fluid as really tiny polygonized spheres (by really tiny I'm saying about 0.03 units radius for the spheres). The lighting in my scene isn't lighting them how I want and I can't get it to look right. I'm looking for something similar to the soft lighting on the particles in this image...
However my particles look like this...
See how my particles have bright white sections whereas the green particles are just lit up softly and don't have large white hotspots. I know the reason is either the settings for my light or simply the fact that the particles are so small that the light takes up a larger space (is that possible??). My settings for lighting are as follows...
GLfloat mat_ambient[] = {0.5, 0.5, 0.5, 1.0};
GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat mat_shininess[] = {10.0};
GLfloat light_position[] = {0.0, 0.1, p_z, 1.0};
GLfloat model_ambient[] = {0.5, 0.5, 0.5, 1.0};
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, model_ambient);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);

Thanks for all the suggestions everyone but unfortunately nothing worked. I sat down with my graphics professor and we determined that this problem was in fact related to the size of the particles and the fact that OpenGL treats directional lights as being infinitely far away from any vertex. The proper way to fix it was modifying the constant attenuation of the light source like this...
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 10.0);
Now my particles look like this...
which is exactly the lighting I was after!

The size of the particles isn't an issue - you're over-saturating your colours.
For each RGB component, you should have ambient + diffuse + specular <= 1.0
For a scene like this I'd expect ambient to be no more than 0.1 or so, diffuse of 0.6 or so, and specular making up the rest.

It looks like you need to turn down the specular component of your material, turn down the ambient a bit, and add some diffuse shading (GL_DIFFUSE). Consider also positioning the light behind the the viewport/camera.

Related

OpenGL doesn't consider distance of GL_DIFFUSE positional light

I want to put a positional light in my scene. I expect distant objects to take less light, but opengl just care about angle between surface normal and light. Am I doing something wrong or do I have to add another function?
GLfloat lightIntensity=1.0;
GLfloat main_position[] = {0.0, 0.0, 1.0, 1.0};
GLfloat light_ambient[] = {0.2, 0.2, 0.2, 0.0};
GLfloat light_diffuse[] = {lightIntensity, lightIntensity, lightIntensity, 1.0};
GLfloat light_specular[] = {0.0, 0.0, 0.0, 0.0};
/* Enable a single OpenGL light. */
glLightfv(GL_LIGHT0, GL_POSITION, main_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
When I run the code, 2 object with same surface normal have same lighting even though they have different distance from the light source
For a distance dependent light you've to set the attenuation parameters GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION respectively GL_QUADRATIC_ATTENUATION. See glLight. By default the light is constant independent on the distance.
The light attenuation is specified in OpenGL 2.0 Specification - 2.14.1 Lighting, page 62.
The light attenuation factor is defiend as:
att = 1 / (kc + kl * d + kq * d * d)
d ... distance from the light source to the fragment
kc ... constant attenuation
kl ... linear attenuation
kq ... quadratic attenuation
The default value for the constant attenuation is 1, for the linear and quadratic attenuation it is 0. This leads to a distance independent factor of 1.
e.g. In the following a attenuation is set, where the attenuation factor is <= 1.0/255.0 at a distance of max_dist:
float max_dist = ...;
float threshold = 1.0f/255.0f;
float kc = 0.0f;
float kq = 0.0f;
float kl = (1.0f/threshold - kc - kq*max_dist*max_dist) / max_dist;
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, kc);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, kl);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, kq);
For quadratic attenuation the same can be achieved by
float kc = 0.0f;
float kl = 0.0f;
float kq = (1.0f/threshold - kc - kl*max_dist) / (max_dist*max_dist);

How to stop positional light moving with camera

When I rotate and/or move the camera in my openGL project, it is almost as if there is a spotlight moving with it, however I have set up my gl light to be positional and given it a static position.
void Lighting::Display()
{
glPushMatrix();
glTranslatef(0.f, yoffset, 0.f); // move to start
glTranslatef(0.f, ceilHeight * scale[0], 0.f);
DrawLight();
glDisable(GL_LIGHTING);
glPushAttrib(GL_ALL_ATTRIB_BITS);
// Match colour of sphere to diffuse colour of light
glColor4fv(specular);
glTranslatef(0.f, -10.0f * scale[1], 0.f);
glutSolidSphere(5.0f * scale[0], 25, 25);
glPopAttrib();
glPopMatrix();
// Re-enable lighting after light source has been drawn
glEnable(GL_LIGHTING);
// Set properties GL_LIGHT0
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
//glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0001f);
GLfloat pos[4] = { 0.f, 950.f, 0.f, 1.f };
glLightfv(GL_LIGHT0, GL_POSITION, pos);
// enable GL_LIGHT0 with these defined properties
glEnable(GL_LIGHT0);
}
I expected to have a single source of light hanging in the centre of the scene, with light being emitted equally in all directions from its position
however a trail of light seems to be emitted as a spotlight instead.
Here is an image showcasing the issue:
As you can see there is an odd line of light being emitted.
When the light position is set by glLightfv(GL_LIGHT0, GL_POSITION, pos), then pos is multiplied by the current model view matrix.
The intensity of the ambient light (Ia), diffuse light (Id) and specular light (Is), of the Blinn–Phong reflection model is calculated as follows:
N ... norlmal vector
L ... light vector (from the vertex position to the light)
V ... view vector (from the vertex position to the eye)
sh ... shininess
H = normalize(V + L)
NdotH = max(dot(N, H), 0.0)
Ia = 1
Id = max(dot(N, L), 0.0)
Is = pow(NdotH, sh)
So the ambient light (GL_AMBIENT) is independent of any direction.
The diffuse light (GL_DIFFUSE) depends on the normal vector of the surface (N) and the direction of the incident light (L). It stays constant on the lit surface, independent on the point of view.
The specular light (GL_SPECULAR) depends on the surfaces normal vector (N), the light direction (L). and the viewing direction (V). This causes that the specular highlights change, when you move in the scene, because the viewing direction to the lit surfaces changes.
Further note that the light calculations in the deprecated OpenGL fixed function light model are done per vertex (Gouraud Shading). The calculated light is interpolated on the area, between the the corners of the primitives. A modern implementation would be to do the light calculation per fragment (Phong shading).
Gouraud Shading cause the spotted look of the specular highlights at the ceiling and may increase an unexpected look. Tessellating the areas in smaller peaces may improve that, but the best solution would be to switch to modern OpenGL write a Shader and implement a per fragment light model for your needs.
Your pop your matrix right before setting the lighting position. As a result your position of your light is always what you set it too. You are then multiplying everything else by your View Matrix I assume. The View matrix essentially transforms the world into the view of the camera. Essentially a camera doesn't move, the world moves around the camera. Since the light is not multiplied by this view matrix ALSO you get a light that appears to maintain a constant position relative to the camera.

Rotating a light around a stationary object in openGL/glsl

So, I'm trying to rotate a light around a stationary object in the center of my scene. I'm well aware that I will need to use the rotation matrix in order to make this transformation occur. However, I'm unsure of how to do it in code. I'm new to linear algebra, so any help with explanations along the way would help a lot.
Basically, I'm working with these two right now and I'm not sure of how to make the light circulate the object.
mat4 rotation = mat4(
vec4( cos(aTimer), 0.0, sin(aTimer), 0.0),
vec4( 0, 1.0, 0.0, 0.0),
vec4(-sin(aTimer), 0.0, cos(aTimer), 0.0),
vec4( 0.0, 0.0, 0.0, 1.0)
);
and this is how my light is set up :
float lightPosition[4] = {5.0, 5.0, 1.0, 0};
glLightfv(GL_LIGHT0, GL_POSITION, lightPositon);
The aTimer in this code is a constantly incrementing float.
Even though you want the light to rotate around your object, you must not use a rotation matrix for this purpose but a translation one.
The matrix you're handling is the model matrix. It defines the orientation, the position and the scale of your object.
The matrix you have here is a rotation matrix, so the orientation of the light will change, but not the position, which is what you want.
So there is two problems to fix here :
1.Define your matrix properly. Since you want a translation (circular), I think this is the matrix you need :
mat4 rotation = mat4(
vec4( 1.0, 0.0, 0.0, 0.0),
vec4( 0.0, 1.0, 0.0, 0.0),
vec4( 0.0, 0.0, 1.0, 0.0),
vec4( cos(aTimer), sin(aTimer), 0.0, 1.0)
);
2.Define a good position vertex for your light. Since it's a single vertex and it's the job of the model matrix (above) to move the light, the light vector 4D should be :
float lightPosition[4] = {0.0f, 0.0f, 0.0f, 1.0f};
//In C, 0.0 is a double, you may have warnings at compilation for loss of precision, so use the suffix "f"
The forth component must be one since it's thanks to it that translations are possible.
You may find additional information here
Model matrix in 3D graphics / OpenGL
However they are using column vectors. Judging from your rotation matrix I do belive you use row vectors, so the translation components are in the last row, not the last column of the model matrix.

How use option Kd Ks Ka [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
how use/draw "Kd Ka Ks"?
I am interested in how to use these options.
Ks[3]
Kd[3]
Ka[3]
glcolor3f(..., ..., ...);
Thanks.
These are coefficients of reflection. Ka is for ambient component, Kd is for diffuse component, and Ks is for specular component.
The Ks, Kd, and Ka are arrays of 3 elements (you can also have a 4th value, the alpha component). The elements represent the RGB colors. You can tweak these values if you want to modify how light reflects off of your surface (increase Ks for more specular lighting and making your surface more shiny, Kd for more diffuse reflection, and Ka for more ambient light, which will make everything brighter).
For example, you can modify materials using glMaterialfv:
GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 };
GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat shinyness[] = { 5.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, shinyness);
S, D, and A should stand for specular, diffuse, and ambient lighting. Without surrounding code though I'm not too sure what the vectors represent. I would guess though that that is the color of the specular, ambient, and diffuse lights to be applied to the surface. There are many shading models you can check out to implement lighting, have a look at Phong: http://www.arcsynthesis.org/gltut/Illumination/Tut11%20Phong%20Model.html, http://en.wikipedia.org/wiki/Phong_shading

Bad shading result when applying material

I've got an openGL 3d scene with two simple objects (glutSolidCube and glutSolidTeapot). When I set up the lights with GL_COLOR_MATERIAL enabled, I get the following result:
Which is good. Then when I set up my own material like this:
//diffuse light color variables
GLfloat dlr = 0.4;
GLfloat dlg = 0.6;
GLfloat dlb = 0.9;
//ambient light color variables
GLfloat alr = 0.7;
GLfloat alg = 0.7;
GLfloat alb = 0.7;
//ambient light color variables
GLfloat slr = 0.4;
GLfloat slg = 0.4;
GLfloat slb = 0.4;
GLfloat DiffuseLight[] = {dlr, dlg, dlb}; //set DiffuseLight[] to the specified values
GLfloat AmbientLight[] = {alr, alg, alb}; //set AmbientLight[] to the specified values
GLfloat SpecularLight[] = {slr, slg, slb}; //set AmbientLight[] to the specified values
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float *)&AmbientLight);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float *)&DiffuseLight);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float *)&SpecularLight);
I get this very different result, in which you can see it's not being shaded properly, it's like FLAT shading although I defined it as SMOOTH (Gouraud).
Where can the problem be? Is it on the material definition?
You forgot to set specular shininess.
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 12.0f);
Set it to 10...25 and it'll look much better/shinier. It won't look as good as per-pixel lighting, though. Default value for shininess is zero which will look exactly like what you see - i.e. ugly.
I get this very different result, in which you can see it's not being shaded properly, it's like FLAT shading although I defined it as SMOOTH (Gouraud).
Well, you got smooth shading. However the OpenGL fixed function pipeline evaluates illumination values only at the vertices, then performs barycentric interpolation over the face. The result you got is exactly what to expect.
What you want is per pixel/fragment illumination. Only way to get this is by using a shader (well, it's also possible by tinkering with the so called "texture combiner environment", but getting that one to work properly is a lot of hard work. Implementing a Phong illumination shader is a matter of minutes).
By changing your lighting and material settings you're just putting emphasis on the shortcommings of the Gouraud shading model.