PDA

View Full Version : lighting the sun creating the problem

Dhruvil vyas
11-27-2011, 09:06 PM
I am a newbie to opengl and this is my first post.I am trying to develop space simulator. I am trying to use sun as the light source My problem is that the lighting dosent work as expected. Maybe i am using the wrong calculation for the normals. I am using a single "createsphere" function to create a sphere, and then use different coordinates and sizes to display them. The problem is that all the sphere on the screen show almost the same effect. i.e the light rotates along with them. I am not sure where the problem is ...i am posting my code ...

void CreateSphere (double R, double X, double Y, double Z) {
int n,m;
double a;
double b;
n = 0;
m = 0;
//NORMALS* p = new NORMALS;

for( b = 0; b <= 90 - space; b+=space){

for( a = 0; a <= 360 - space; a+=space)
{
VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b) / 180 * PI) - X;
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b) / 180 * PI) + Y;
VERTEX[n].Z = R * cos((b) / 180 * PI) - Z;
VERTEX[n].V = (2 * b) / 360;
VERTEX[n].U = (a) / 360;

n++;
VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b + space) / 180 * PI) - X;
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b + space) / 180 * PI) + Y;
VERTEX[n].Z = R * cos((b + space) / 180 * PI) - Z;
VERTEX[n].V = (2 * (b + space)) / 360;
VERTEX[n].U = (a) / 360;

n++;
VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b) / 180 * PI) - X;
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b) / 180 * PI) + Y;
VERTEX[n].Z = R * cos((b) / 180 * PI) - Z;
VERTEX[n].V = (2 * b) / 360;
VERTEX[n].U = (a + space) / 360;

n++;

VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b + space) /180 * PI) - X;
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b + space) /180 * PI) + Y;
VERTEX[n].Z = R * cos((b + space) / 180 * PI) - Z;
VERTEX[n].V = (2 * (b + space)) / 360;
VERTEX[n].U = (a + space) / 360;

n++;
}

}
}

the display sphere function is given below

void DisplaySphere (double R, GLuint texture)
{

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

int b,m = 0;
glScalef (0.0125 * R, 0.0125 * R, 0.0125 * R);
glBindTexture (GL_TEXTURE_2D, texture);
glBegin (GL_TRIANGLE_STRIP);

for ( b = 0; b <VertexCount; b++)
{

glTexCoord2f (VERTEX[B].U, VERTEX[B].V);
glNormal3f(-VERTEX[B].X, -VERTEX[B].Y, -VERTEX[B].Z);
glVertex3f (VERTEX[B].Y, VERTEX[B].X, -VERTEX[B].Z);
}

m = 0;

for ( b = 0; b <VertexCount; b++)
{

glTexCoord2f (VERTEX[B].U, -VERTEX[B].V);
glNormal3f(-VERTEX[B].X, -VERTEX[B].Y, -VERTEX[B].Z);
glVertex3f (VERTEX[B].Y, VERTEX[B].X, VERTEX[B].Z);
}

glEnd();
glRotatef(angle,0,0,1);

}

the lighting code is given here

glPushMatrix();
gluLookAt (0.0, 10.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); //defines a viewing transformation.
//GLdouble eyex, eyey,eyez, centerx,centery, centerz, upx, upy, upz..// have kept upz=1 so,
//to go left-right in the screen change x cood
//to go up(+z) and down(-z) to change z coord
//to go inside(-y) - outside(+y) the screen change y coord.

// Now translate to the sun
glTranslatef(0.0, -7.0, 3.0);

/* For LIGHT0 */
GLfloat lightZeroPosition[] = {0.0f, 0.0f, 0.0f, 1.0f};
/*GLfloat lightvec[] = {0.5f, 0.2f, 0.0f, 1.0f};*/
GLfloat lightZeroColor[] = {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat amb[] = {1, 1, 1, 1};
GLfloat spec[] = {0.3, 0.3, 0.3, 1};

glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
glLightfv(GL_LIGHT0, GL_SPECULAR, spec);
//glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, lightvec );
//glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 20);

glEnable(GL_LIGHT0);
glRotatef(angle,0,0,1);
DisplaySphere(5,textures);// function to display the sun

am attaching some images also

BionicBytes
11-28-2011, 03:14 AM
There are a few things wrong with your code.
Firstly the normal generation:

glNormal3f(-VERTEX[B].X, -VERTEX[B].Y, -VERTEX[B].Z);
glVertex3f (VERTEX[B].Y, VERTEX[B].X, -VERTEX[B].Z);

Normals are not generated like that. One way of calculating the normals is to create a PLANE from three of the adjacent verticies. By definition, the normal is perpendicular to the plane. Repeat this process for each vertex, calculating the normal from the vertex + two adjacent.
Personally, for 'planets' I'd just use gluSolidSphere...it's created properly with normals and texture coordinates, etc.

Then the odd texture parameter you have...

void DisplaySphere (double R, GLuint texture)
{

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

...you are calling glTexParameteri but there's no texture bound (or at least it's not obvious from the code you have posted).

Lastly, the positioning of the directional light - which you have placed in the origin (0,0,0) with lightZeroPosition. Is that what you intended?

gluLookAt (0.0, 10.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
// Now translate to the sun
glTranslatef(0.0, -7.0, 3.0);

/* For LIGHT0 */
GLfloat lightZeroPosition[] = {0.0f, 0.0f, 0.0f, 1.0f};
GLfloat lightZeroColor[] = {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat amb[] = {1, 1, 1, 1};
GLfloat spec[] = {0.3, 0.3, 0.3, 1};

glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);

You have done one thing right, that's postion the light immediately after settingup the OpenGl ModelView matrix (GluLookAt). This will take the lightZeroPosition and multiplying it with the current modelview matrix - which has been set as:

gluLookAt (0.0, 10.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0) multiplied by an internal matrix to represent glTranslatef(0.0, -7.0, 3.0);
Thus, the sun is NOT positioned at 0,0,0 (because of your glTranslatef command).
Additionally, the glLight0 is a directional light. How is it going to light objects not directly infront/behind the 'sun' object at the origin? I.E. What about objects which are at 90 degrees to the origin. They won't be lit properly beciase the light is travelling in a single uniform direction from the origin. Ideally, you need a Point light instead.

tksuoran
11-28-2011, 03:48 AM
For a sphere shape, vertex normals can be computed directly, no need to compute face normals. You can simply normalize vertex positions to get normals. Or you could compute normals instead of vertex positions into array, and do glVertex3f(R * NORMAL[B].X, R * NORMAL[B].Y, R * NORMAL[B].Z). That would replace glScale in DisplaySphere. But if you keep glScale you should enable GL_NORMALIZE, otherwise lighting will be done with scaled normals.

The code appears to do some coordinate system reorientation, and normals get treated differently from vertex positions. I would probably remove this mismatch, as it also affects the lighting.

Directional lights are valid for solar system, as the light source is distant and thus effectively directional. However you would need to update light direction for each body you render.  You would also lose attenuation, but it is not sure if you even need or want it here.

Sometimes it is more intuitive to use identity modelview transform while setting light position/direction in world coordinates.