PDA

View Full Version : Is this how lighting is supposed to look?



DrenDran
07-25-2011, 11:30 AM
I made a opengl program where you can move your view back and forth and side to side, and a cube with a light "in" it all three directions.
I filmed it as I used it:
http://www.youtube.com/watch?v=0KjwX3R-m7Y

Here is the code, which uses parts of tutorial 7 from nehe:


#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#if defined(__APPLE__) &amp;&amp; defined(__MACH__)
#include <OpenGL/gl.h> // Header File For The OpenGL32 Library
#include <OpenGL/glu.h> // Header File For The GLu32 Library
#else
#include <GL/gl.h> // Header File For The OpenGL32 Library
#include <GL/glu.h> // Header File For The GLu32 Library
#endif
#include "SDL.h"
#include <Math.h>

/* lighting on/off (1 = on, 0 = off) */
int light = 0;

GLfloat x=0;
GLfloat y=1;
GLfloat z=5.0f; // depth into the screen.

float xrot = 0;
float yrot = 0;

GLfloat lx=0;
GLfloat ly=0.5;
GLfloat lz=0;

/* white ambient light at half intensity (rgba) */
GLfloat LightAmbient[] = { 2,2,2, 1.0f };

/* super bright, full intensity diffuse light. */
GLfloat LightDiffuse[] = { 2,2,2, 1.0f };

GLuint filter = 0; /* Which Filter To Use (nearest/linear/mipmapped) */
GLuint texture[3]; /* Storage for 3 textures. */

SDL_Surface *LoadBMP(char *filename)
{
Uint8 *rowhi, *rowlo;
Uint8 *tmpbuf, tmpch;
SDL_Surface *image;
int i, j;

image = SDL_LoadBMP(filename);
if ( image == NULL ) {
fprintf(stderr, "Unable to load %s: %s\n", filename, SDL_GetError());
return(NULL);
}

/* GL surfaces are upsidedown and RGB, not BGR :-) */
tmpbuf = (Uint8 *)malloc(image->pitch);
if ( tmpbuf == NULL ) {
fprintf(stderr, "Out of memory\n");
return(NULL);
}
rowhi = (Uint8 *)image->pixels;
rowlo = rowhi + (image->h * image->pitch) - image->pitch;
for ( i=0; i<image->h/2; ++i ) {
for ( j=0; j<image->w; ++j ) {
tmpch = rowhi[j*3];
rowhi[j*3] = rowhi[j*3+2];
rowhi[j*3+2] = tmpch;
tmpch = rowlo[j*3];
rowlo[j*3] = rowlo[j*3+2];
rowlo[j*3+2] = tmpch;
}
memcpy(tmpbuf, rowhi, image->pitch);
memcpy(rowhi, rowlo, image->pitch);
memcpy(rowlo, tmpbuf, image->pitch);
rowhi += image->pitch;
rowlo -= image->pitch;
}
free(tmpbuf);
return(image);
}

// Load Bitmaps And Convert To Textures
GLvoid LoadGLTextures(GLvoid)
{
// Load Texture
SDL_Surface *image1;

image1 = LoadBMP("Media/crate.bmp");
if (!image1) {
SDL_Quit();
exit(1);
}

// Create Textures
glGenTextures(3, &amp;texture[0]);

// texture 1 (poor quality scaling)
glBindTexture(GL_TEXTURE_2D, texture[0]); // 2d texture (x and y size)

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_NEAREST); // cheap scaling when image bigger than texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_NEAREST); // cheap scaling when image smalled than texture

// 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
// border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->w, image1->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);

// texture 2 (linear scaling)
glBindTexture(GL_TEXTURE_2D, texture[1]); // 2d texture (x and y size)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR); // scale linearly when image bigger than texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR); // scale linearly when image smalled than texture
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->w, image1->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);

// texture 3 (mipmapped scaling)
glBindTexture(GL_TEXTURE_2D, texture[2]); // 2d texture (x and y size)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR); // scale linearly when image bigger than texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR_MIPMAP_NEAREST); // scale linearly + mipmap when image smalled than texture
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->w, image1->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);

// 2d texture, 3 colors, width, height, RGB in that order, byte data, and the data.
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image1->w, image1->h, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);
};

/* A general OpenGL initialization function. Sets all of the initial parameters. */
GLvoid InitGL(GLsizei Width, GLsizei Height) // We call this right after our OpenGL window is created.
{
glViewport(0, 0, Width, Height);
LoadGLTextures(); // load the textures.
glEnable(GL_TEXTURE_2D); // Enable texture mapping.

glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS); // The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading

glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // Reset The Projection Matrix

gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window

glMatrixMode(GL_MODELVIEW);
glEnable ( GL_COLOR_MATERIAL );
glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
}

void drawcube(float x,float y,float z,float a,float b,float c)
{
// Front Face (note that the texture's corners have to match the quad's corners)
glNormal3f(x+(a/2),y+(b/2),z); // front face points out of the screen on z.
glTexCoord2f(0.0f, 0.0f); glVertex3f(x,y, z+c); // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f(x+a,y, z+c); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f(x+a,y+b, z+c); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(x,y+b, z+c); // Top Left Of The Texture and Quad

// Back Face
glNormal3f(x+(a/2),y+(b/2),z+c); // back face points into the screen on z.
glTexCoord2f(1.0f, 0.0f); glVertex3f(x,y,z); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f(x,y+b,z); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(x+a,y+b,z); // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(x+a,y,z); // Bottom Left Of The Texture and Quad

// Top Face
glNormal3f(x+(a/2),y+b,z+(c/2)); // top face points up on y.
glTexCoord2f(0.0f, 1.0f); glVertex3f(x,y+b,z); // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(x,y+b, z+c); // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f(x+a,y+b, z+c); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f(x+a,y+b,z); // Top Right Of The Texture and Quad

// Bottom Face
glNormal3f(x+(a/2),y,z+(c/2)); // bottom face points down on y.
glTexCoord2f(1.0f, 1.0f); glVertex3f(x,y,z); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(x+a,y,z); // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(x+a,y, z+c); // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f(x,y, z+c); // Bottom Right Of The Texture and Quad

// Right face
glNormal3f(x+a,y+(b/2),z+(c/2)); // right face points right on x.
glTexCoord2f(1.0f, 0.0f); glVertex3f(x+a,y,z); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f(x+a,y+b,z); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(x+a,y+b, z+c); // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(x+a,y, z+c); // Bottom Left Of The Texture and Quad

// Left Face
glNormal3f(x,y+(b/2),z+(c/2)); // left face points left on x.
glTexCoord2f(0.0f, 0.0f); glVertex3f(x,y,z); // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f(x,y, z+c); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f(x,y+b, z+c); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(x,y+b,z); // Top Left Of The Texture and Quad
}

/* The main drawing function. */
void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View

glTranslatef(-x,-y,-z); // move z units out from the screen.

/* position of light (x, y, z, (position of light)) */
GLfloat LightPosition[] = { lx, ly, lz, 1.0f };

// set up light number 1.
//glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // add lighting. (ambient)
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // add lighting. (diffuse).
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // set light position.
glEnable(GL_LIGHT1); // turn light 1 on.

glBindTexture(GL_TEXTURE_2D, texture[filter]); // choose the texture to use.

glBegin(GL_QUADS); // begin drawing a cube
drawcube(0,0,0,2,2,2);
drawcube(3,0,0,2,2,2);
drawcube(lx,ly,lz,0.5,0.5,0.5);
glEnd();

glBindTexture(GL_TEXTURE_2D, NULL);
glBegin(GL_QUADS);
glColor3f(0,1,0);
drawcube(-100,0,-100,200,0.01,200);
glColor3f(0,0,1);
drawcube(-1000,1000,-1000,2000,0.01,2000);
glEnd(); // done with the polygon.
glColor3d(1,1,1);

// swap buffers to display, since we're double buffered.
SDL_GL_SwapBuffers();
}

int main(int argc, char **argv)
{
int done;
Uint8 *keys;

/* Initialize SDL for video output */
if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
exit(1);
}

/* Create a 640x480 OpenGL screen */
if ( SDL_SetVideoMode(1280, 960, 0, SDL_OPENGL) == NULL ) {
fprintf(stderr, "Unable to create OpenGL screen: %s\n", SDL_GetError());
SDL_Quit();
exit(2);
}

/* Set the title bar in environments that support it */
SDL_WM_SetCaption("Jeff Molofee's GL Code Tutorial ... NeHe '99", NULL);

/* Loop, drawing and checking events */
InitGL(1280,960);
done = 0;
while ( ! done ) {
DrawGLScene();

/* This could go in a separate function */
{ SDL_Event event;
while ( SDL_PollEvent(&amp;event) ) {
if ( event.type == SDL_QUIT ) {
done = 1;
}
if ( event.type == SDL_KEYDOWN ) {
switch(event.key.keysym.sym) {
case SDLK_ESCAPE:
done = 1;
break;
case SDLK_l:
printf("Light was: %d\n", light);
light = light ? 0 : 1; // switch the current value of light, between 0 and 1.
printf("Light is now: %d\n", light);
if (!light) {
glDisable(GL_LIGHTING);
} else {
glEnable(GL_LIGHTING);
}
break;
case SDLK_f:
printf("Filter was: %d\n", filter);
filter += 1;
if (filter>2)
filter = 0;
printf("Filter is now: %d\n", filter);
break;
}
}
}
}

/* Check current key state for special commands */
keys = SDL_GetKeyState(NULL);
if ( keys[SDLK_UP] == SDL_PRESSED )
{
z-=0.1;
}
if ( keys[SDLK_DOWN] == SDL_PRESSED )
{
z+=0.1;
}
if ( keys[SDLK_LEFT] == SDL_PRESSED )
{
x-=0.1;
}
if ( keys[SDLK_RIGHT] == SDL_PRESSED )
{
x+=0.1;
}
if ( keys[SDLK_w] == SDL_PRESSED ) {
lz-=0.03;
}
if ( keys[SDLK_s] == SDL_PRESSED ) {
lz+=0.03;
}
if ( keys[SDLK_a] == SDL_PRESSED ) {
lx-=0.03;
}
if ( keys[SDLK_d] == SDL_PRESSED ) {
lx+=0.03;
}
if( keys[SDLK_PAGEDOWN] == SDL_PRESSED)
{
ly-=0.03;
}
if( keys[SDLK_PAGEUP] == SDL_PRESSED)
{
ly+=0.03;
}
}
SDL_Quit();
return 1;
}


When the light goes to the left of the cubes, no sides light up, and when it goes to the right, all sides seem to light up. Why is this? How can I fix my lighting?
edit: oh, and the ground doesn't light up at all

mhagain
07-25-2011, 12:27 PM
When the light goes to the left of the cubes, no sides light up, and when it goes to the right, all sides seem to light up. Why is this? How can I fix my lighting?
edit: oh, and the ground doesn't light up at all

I haven't studied your code in detail but the symptoms you describe indicate that your normals are all pointing in the same direction. Why not set some breakpoints, run in the debugger, and find out?

DrenDran
07-25-2011, 12:31 PM
Just look at the drawcube function.
As you can see, each normal would be different.

robmx
07-25-2011, 01:51 PM
The only thing I see is that the normals are not normalized. Try normalizing them and see what happen.

DrenDran
07-25-2011, 01:52 PM
The only thing I see is that the normals are not normalized. Try normalizing them and see what happen.
What's that even mean?

robmx
07-25-2011, 02:01 PM
The only thing I see is that the normals are not normalized. Try normalizing them and see what happen.
What's that even mean?

making sure that the vector's magnitude is 1.

http://en.wikipedia.org/wiki/Euclidean_vector#Length

Edit:
Also check that the normals are what you are expecting. Usually normals for a cube are:
Front => ( 0, 0, 1)
Back => ( 0, 0, -1)
Top => ( 0, 1, 0)
Bottom => ( 0, -1, 0)
Right => ( 1, 0, 0)
Left => (-1, 0, 0)
(Unless the cube has a different direction)

DrenDran
07-25-2011, 02:19 PM
The only thing I see is that the normals are not normalized. Try normalizing them and see what happen.
What's that even mean?

making sure that the vector's magnitude is 1.

http://en.wikipedia.org/wiki/Euclidean_vector#Length
So you mean like, making sure they're whole numbers?
edit: adding glEnable(GL_NORMALIZE); didn't do much.

Here is what light looks like with normalizing enabled, new ground terrain, and other additions:
http://img29.imageshack.us/img29/7815/lightwut.png
What is odd is that all tiles from the view point (the light is at the view point) to the center are lit in a path.

Dark Photon
07-25-2011, 05:03 PM
What is odd is that all tiles from the view point (the light is at the view point) to the center are lit in a path.
What's your vertex density? To see, enable wireframe:


glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

Alternatively, you can see the lighting better if you disable texturing and just look at the "lit color" result.

Keep in mind that with standard OpenGL, lighting is only evaluated at the vertices and interpolated across the polygons. If you want a higher frequency, you either use more vertices (wastes vertex transforms) or you can write your own shaders and compute lighting per-pixel rather than per-vertex.

DrenDran
07-25-2011, 05:49 PM
What is odd is that all tiles from the view point (the light is at the view point) to the center are lit in a path.
What's your vertex density? To see, enable wireframe:


glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

Alternatively, you can see the lighting better if you disable texturing and just look at the "lit color" result.

Keep in mind that with standard OpenGL, lighting is only evaluated at the vertices and interpolated across the polygons. If you want a higher frequency, you either use more vertices (wastes vertex transforms) or you can write your own shaders and compute lighting per-pixel rather than per-vertex.

What doesn't make sense, is that stuff is light at the center, when the light is very far away from it. Here is a screen shot with that wire frame mode:
http://img98.imageshack.us/img98/6817/wiress.png

Aeluned
07-26-2011, 01:42 PM
It does make sense. You have a very sparse mesh representing your terrain.

Since the intensity of the light reflected off of your terrain is directly correlated to the angle of incidence between the vertex normal and the vector defined by vertexPos-LightPos, your lighting will begin looking drastically worse as the light approaches the terrain. As Dark Photon suggested, try increasing the tessellation of your terrain and notice how the quality of the lighting holds up even when the light source is hovering just above your terrain. Or better yet, write a fragment shader to do your lighting.

Your boxes are suffering from the same problem.

I admittedly didn't read through your source code, this is just going off of that video clip you posted. It looks to me like that's what's happening.