Archived

This topic is now archived and is closed to further replies.

Jackthemeangiant

Lighting up terrain...

Recommended Posts

I am creating a terrain engine generated from a heightmap, and I just finished the code to calculate all the vertex normals. But I am fairly inexperienced with OpenGL Lighting, and when I enable a GL_LIGHT, and set up the diffuse and ambient properties, it just doesn't look right at all... I basically want the terrain, to look like terrain, with light coming from a particular spot(a sun). When I tried it, it was either all white, or the tops of my mountains were all white, or the light didn't reach one end of the terrain. I have read the chapter on Lighting in the Red book numerous times, but I am still stuck. Please help me =) Thanks Edited by - jackthemeangiant on November 10, 2001 3:10:04 PM

Share this post


Link to post
Share on other sites
the problem sounds very much like your supplying the incorrect normals.
theres a lot of info/demos/tuts on the net on how to calculate the correct normals
if u have the red book check out appendix E.

first find the normals to all the tris/quads + NOT the vertex normals once u have that info u can work out the vertex normals later

Share this post


Link to post
Share on other sites
For starters, just post the light initialization code.

Alex Broadwin
A-Tronic Software & Design
-----
"if you fail in life, you were destined to fail. If you suceed in life, call me."
"The answer is out there."
"Please help, I''m using Windows!"

Share this post


Link to post
Share on other sites
wow.... that sux.

Alex Broadwin
A-Tronic Software & Design
-----
"if you fail in life, you were destined to fail. If you suceed in life, call me."
"The answer is out there."
"Please help, I''m using Windows!"

Share this post


Link to post
Share on other sites
jack even though it still looks like the normals to me.
try making ambient light 0,0,0,0 + use a directional light not a positional one.
about the corrupt file from vc (i take it youre using win2000/XP)

right click on the harddisk select properties->hardware->properties->diskproperties and uncheck disk cache enabled.
u will need to do ths every time u reboot the machine.
ive been bitten a few times by crashes in win2000, when the current open c++ file has been turn into junk. grrrrr

Share this post


Link to post
Share on other sites
Hi Send me the code you use to calculate normals(full code that is the one calculating the trinangular normals & then the function calculating the vertex normals) also tell me what type of light you are using. then i can do something for you. see you then Bye.

Share this post


Link to post
Share on other sites
I will post my normal calculations in a bit, i have to finish re-writing them

Should i post them all?..becuase it is kinda long. I have to calcualte for 9 different types individualy (4 corners, 4 sides, everything else)

and to zedzeek, i am using win2k, but the disk cache checkbox is disabled for me

Edited by - jackthemeangiant on November 11, 2001 7:44:39 PM

Share this post


Link to post
Share on other sites
I have uploaded a copy of my program, drawing the terrain in wireframe, and drawing the normals in red:

http://jackthemeangiant.l33t.ca/invaders/Invaders.rar

Press the tilde key to bring down the console, then type
"/loadmap map" without the "'s

To me, they look correct, but anyways, here is my code for calculating normals:

First of all, here is my map structure:
      
//Map Data structure

typedef struct
{
float normal[3]; //vertex normal

float vertex[3]; //vertex array

} c_mapData;

//Map structure

typedef struct
{
int width; //Map width

int height; //Map height

c_mapData ***mapData; //Dynamic array of map data

} c_map;


then it is alocated here, and map data is loaded:
     
//Allocate memory for the map

map = new c_map;
map->mapData = new c_mapData **[width];

for (int i = 0; i < (int)width; i ++)
{
map->mapData[i] = new c_mapData *[height];
for (int t = 0; t < (int)height; t ++)
{
map->mapData[i][t] = new c_mapData;
}
}

map->width = width;
map->height = height;

int counter = 0;
for (int x = 0; x < map->width; x ++)
{
for (int y = 0; y < map->height; y ++)
{
map->mapData[y][x]->vertex[0] = y * stretchSize;
map->mapData[y][x]->vertex[1] = (float)((data[counter] / 255.0) * maxHeight);
map->mapData[y][x]->vertex[2] = (x * stretchSize)*(-1);

map->mapData[y][x]->normal[0] = y * stretchSize;
map->mapData[y][x]->normal[1] = (float)((data[counter] / 255.0) * maxHeight);
map->mapData[y][x]->normal[2] = (x * stretchSize)*(-1);

counter += bytesPerPixel;
}

}



now this is how I calculate the normals:
  

vector_t normal1,normal2,normal3,normal4,normal5,normal6,a,b;

a[0] = map->mapData[x][y]->vertex[0] - map->mapData[x - 1][y - 1]->vertex[0];
a[1] = map->mapData[x][y]->vertex[1] - map->mapData[x - 1][y - 1]->vertex[1];
a[2] = map->mapData[x][y]->vertex[2] - map->mapData[x - 1][y - 1]->vertex[2];

b[0] = map->mapData[x][y - 1]->vertex[0] - map->mapData[x - 1][y - 1]->vertex[0];
b[1] = map->mapData[x][y - 1]->vertex[1] - map->mapData[x - 1][y - 1]->vertex[1];
b[2] = map->mapData[x][y - 1]->vertex[2] - map->mapData[x - 1][y - 1]->vertex[2];

Cross(normal1,b,a);

a[0] = map->mapData[x][y]->vertex[0] - map->mapData[x][y - 1]->vertex[0];
a[1] = map->mapData[x][y]->vertex[1] - map->mapData[x][y - 1]->vertex[1];
a[2] = map->mapData[x][y]->vertex[2] - map->mapData[x][y - 1]->vertex[2];

b[0] = map->mapData[x + 1][y]->vertex[0] - map->mapData[x][y - 1]->vertex[0];
b[1] = map->mapData[x + 1][y]->vertex[1] - map->mapData[x][y - 1]->vertex[1];
b[2] = map->mapData[x + 1][y]->vertex[2] - map->mapData[x][y - 1]->vertex[2];

Cross(normal2,b,a);

a[0] = map->mapData[x][y]->vertex[0] - map->mapData[x + 1][y]->vertex[0];
a[1] = map->mapData[x][y]->vertex[1] - map->mapData[x + 1][y]->vertex[1];
a[2] = map->mapData[x][y]->vertex[2] - map->mapData[x + 1][y]->vertex[2];

b[0] = map->mapData[x + 1][y + 1]->vertex[0] - map->mapData[x + 1][y]->vertex[0];
b[1] = map->mapData[x + 1][y + 1]->vertex[1] - map->mapData[x + 1][y]->vertex[1];
b[2] = map->mapData[x + 1][y + 1]->vertex[2] - map->mapData[x + 1][y]->vertex[2];

Cross(normal3,b,a);

a[0] = map->mapData[x][y]->vertex[0] - map->mapData[x + 1][y + 1]->vertex[0];
a[1] = map->mapData[x][y]->vertex[1] - map->mapData[x + 1][y + 1]->vertex[1];
a[2] = map->mapData[x][y]->vertex[2] - map->mapData[x + 1][y + 1]->vertex[2];

b[0] = map->mapData[x][y + 1]->vertex[0] - map->mapData[x + 1][y + 1]->vertex[0];
b[1] = map->mapData[x][y + 1]->vertex[1] - map->mapData[x + 1][y + 1]->vertex[1];
b[2] = map->mapData[x][y + 1]->vertex[2] - map->mapData[x + 1][y + 1]->vertex[2];

Cross(normal4,b,a);

a[0] = map->mapData[x][y]->vertex[0] - map->mapData[x][y + 1]->vertex[0];
a[1] = map->mapData[x][y]->vertex[1] - map->mapData[x][y + 1]->vertex[1];
a[2] = map->mapData[x][y]->vertex[2] - map->mapData[x][y + 1]->vertex[2];

b[0] = map->mapData[x - 1][y]->vertex[0] - map->mapData[x][y + 1]->vertex[0];
b[1] = map->mapData[x - 1][y]->vertex[1] - map->mapData[x][y + 1]->vertex[1];
b[2] = map->mapData[x - 1][y]->vertex[2] - map->mapData[x][y + 1]->vertex[2];

Cross(normal5,b,a);

a[0] = map->mapData[x][y]->vertex[0] - map->mapData[x - 1][y]->vertex[0];
a[1] = map->mapData[x][y]->vertex[1] - map->mapData[x - 1][y]->vertex[1];
a[2] = map->mapData[x][y]->vertex[2] - map->mapData[x - 1][y]->vertex[2];

b[0] = map->mapData[x - 1][y - 1]->vertex[0] - map->mapData[x - 1][y]->vertex[0];
b[1] = map->mapData[x - 1][y - 1]->vertex[1] - map->mapData[x - 1][y]->vertex[1];
b[2] = map->mapData[x - 1][y - 1]->vertex[2] - map->mapData[x - 1][y]->vertex[2];

Cross(normal6,b,a);

//average the poly's normals

map->mapData[x][y]->normal[0] = ((normal1[0] + normal2[0] + normal3[0] + normal4[0] + normal5[0] + normal6[0]) / 6);
map->mapData[x][y]->normal[1] = ((normal1[1] + normal2[1] + normal3[1] + normal4[1] + normal5[1] + normal6[1]) / 6);
map->mapData[x][y]->normal[2] = ((normal1[2] + normal2[2] + normal3[2] + normal4[2] + normal5[2] + normal6[2]) / 6);

//convert to 1 unit length

Normalize(map->mapData[x][y]->normal);

//move normal to proper position by adding the value of the vertex to it

map->mapData[x][y]->normal[0] += map->mapData[x][y]->vertex[0];
map->mapData[x][y]->normal[1] += map->mapData[x][y]->vertex[1];
map->mapData[x][y]->normal[2] += map->mapData[x][y]->vertex[2];


Cross and Normalize are defined as:

//finds the cross product of two vectors

void Cross(vector_t &norm,vector_t vec1,vector_t vec2)
{
norm[0] = vec1[1]*vec2[2]-vec2[1]*vec1[2];
norm[1] = vec1[2]*vec2[0]-vec2[2]*vec1[0];
norm[2] = vec1[0]*vec2[1]-vec2[0]*vec1[1];
}

void Normalize(vector_t &norm)
{
int magnitude;

//find magnitude to normilze

magnitude = sqrt((norm[0] * norm[0]) + (norm[1] * norm[1]) + (norm[2] * norm[2]));

if (magnitude == 0)
magnitude = 1;

//divide by the magnitude to set the normal's length to 1 unit

norm[0] /= magnitude;
norm[1] /= magnitude;
norm[2] /= magnitude;
}




Edited by - jackthemeangiant on November 11, 2001 8:15:18 PM

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Alright,
zedzeek, I tried what you said to try making ambient light 0,0,0,0 + use a directional light not a positional one. and this is what is looks like

http://jackthemeangiant.l33t.ca/valley%20of%20normals.jpg

the problem is that the light isn''t reaching all of the map.

I don''t know if I am expecting the wrong thing from gl_lighting. I bascily want a very nice looking terrain engine, like the one that used to be on glVelocity''s site Xterminate i think it was called (btw what happend to that site).

Share this post


Link to post
Share on other sites
From the appearence of the normals in the newly posted screen shots it seems as if they are all not of the same magnitude(that is unit magnitude) so try this

1)Don''t normalize the normals your self.
2)Use glEnable(GL_NORMALIZE) (before drawing the terrain) to let openGL normalize the normals itself then disable it after drawing the terrain using glDisable(GL_NORMALIZE).

Try this may be this works.Good Luck :-)

manni

Share this post


Link to post
Share on other sites
Alright, now I think I am getting somewhere =)

this is using GL_NORMALIZE

http://jackthemeangiant.l33t.ca/w00t.jpg

Does this picture look more correct?

if it is, then what is wrong with my normalizing code?

    
void Normalize(vector_t &norm)
{
int magnitude;
//find magnitude to normilze

magnitude = sqrt((norm[0] * norm[0]) + (norm[1] * norm[1]) + (norm[2] * norm[2]));

if (magnitude == 0)
magnitude = 1;

//divide by the magnitude to set the normal's length to 1 unit

norm[0] /= magnitude;
norm[1] /= magnitude;
norm[2] /= magnitude;
}



Edited by - jackthemeangiant on November 11, 2001 12:30:30 AM

Share this post


Link to post
Share on other sites
try using the same light source you are using in the first screen shot you posted. One more thing before setting the light position the Model View Matrix must be Identity so that your original light position is not get disturbed. Tope it will work Good luck

manni

Share this post


Link to post
Share on other sites
Well, from the normalization code that you posted, I''d guess that your normals will most likely never have the correct length of one unit, because you are using an integer for the magnitude. An integer does not have the precision that you need for normalizing the vectors. You should use a float or a double instead. Aside from that, the code looks right, although you could probably get rid of the test for a magnitude of 0 since the only vector that would give you such a magnitude would be the 0 vector (0,0,0).

j.w.

Share this post


Link to post
Share on other sites
Go to this site

http://www.opengl.org/developers/code/features/KilgardTechniques/oglpitfall/oglpitfall.html

Here you can get info if you are going to use glScalef(sx,sy,sz);

Let me know if it helps you. bye




manni

Share this post


Link to post
Share on other sites