I am finally starting to work with lighting in OpenGL, but I can't seem to get the lights to work properly. I am originally going off XoaX's tutorial #4, but I am trying to implement mine into objects. In my code I have a "Light" that extends a basic class called "Object" so I do not have to re-implement moving, pointing commands, etc. There is a sub class in "Light" called "LightSettings" where the settings and some actions are done with Specular, Diffuse and ambient light for that particular light. And since OpenGL cannot create an infinite supply of lights, I created a manager called "LightStudio" to help handle who has what light handle as well as the global light commands.
Moving right along, I am drawing a tessellated sheet (50 by 50 squares) that constrained to 4 different coordinates as a solid 0x0000FF blue. This sheet curves to hopefully get the full effect of lighting. In my program, I set up some default and standard lighting settings as so:
These commands are only called once (at the init of OpenGL):
Code:
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
glFrontFace(GL_CCW);
My code for drawing the tessellated "plane" is below:
Code:
void Plane3D::drawTessellated(int tessCountX, int tessCountY)
{
Point3D *pts,left,right;
int pos,x,y;
if (tessCountX<0 || tessCountY<0){return;}
pts = new Point3D[(tessCountX+1)*(tessCountY+1)];
if (!pts)
{
errLog.print("Could not malloc. [Plane3D::drawTessellated(int,int)]");
assert(!"Could not malloc. [Plane3D::drawTessellated(int,int)]");
}
pos = 0;
for (y=0;y<=tessCountY;y++)
{
avg(a,d,y/(float)tessCountY,left);
avg(b,c,y/(float)tessCountY,right);
for (x=0;x<=tessCountX;x++)
{
avg(left,right,x/(float)tessCountX,pts[pos]);
pos++;
}
}
glBegin(GL_QUADS);
for (y=0;y<tessCountY;y++)
{
for (x=0;x<tessCountX;x++)
{
GameLib::calculateNormalTrangle(pts[x +( y *(tessCountX+1))],
pts[x +((y+1)*(tessCountX+1))],
pts[x+1+((y+1)*(tessCountX+1))]);
pts[x +( y *(tessCountX+1))].useAsVertex();
pts[x +((y+1)*(tessCountX+1))].useAsVertex();
pts[x+1+((y+1)*(tessCountX+1))].useAsVertex();
pts[x+1+( y *(tessCountX+1))].useAsVertex();
}
}
glEnd();
delete []pts;
}
For those that need to see how I set up my normals:
Code:
void GameLib::calculateNormalTrangle(Point3D &va,Point3D &vb,Point3D &vc)
{
Direction3D normal;
Point3D a,b,normalPt;
a=va;
a-=vb;
b=vb;
b-=vc;
normalPt.setX((a.getY() * b.getZ()) - (a.getZ() * b.getY()));
normalPt.setY((a.getZ() * b.getX()) - (a.getX() * b.getZ()));
normalPt.setZ((a.getX() * b.getY()) - (a.getY() * b.getX()));
// normalize
normal.setFromLength(normalPt.getX(), normalPt.getY(), normalPt.getZ());
glNormal3f(normal.getI(),normal.getJ(),normal.getK());
}
Direction3D& Direction3D::setFromLength(double dx,double dy,double dz)
{
double total;
total=dx+dy+dz;
i=dx/total;
j=dy/total;
k=dz/total;
return *this;
}
And finally my Lights:
Light.h
Code:
#pragma once
#include "Object.h"
#include "Point3D.h"
class Light : public Object
{
private:
int lightNum;//-1 if no light
GLenum getLightEnum();
bool requestControl();
public:
static GLenum getLightEnum(int num);
class LightSettings
{
private:
bool use;
float intensity,r,g,b;
public:
LightSettings();
~LightSettings();
float getRed();
float getGreen();
float getBlue();
float getIntensity();
LightSettings& setIntensity(float intensity);
LightSettings& setColor(int hexColor);
LightSettings& setColor(float r, float g, float b);
LightSettings& disable();
LightSettings& enable();
void drawMe(GLenum lightEnum);//only call from Light()
}ambient,diffuse,specular;
Light();
~Light();
bool hasLightControl();
void draw();
};
class LightStudio
{
private:
Light *inUse[8];//array of pointers
int ambientLight;
public:
LightStudio();
~LightStudio();
int requestLightControl(Light *light);//should only be called from Light
bool releaseLightControl(Light *light);//should only be called from Light
LightStudio& setAmbientLight(int hexColor);
int getAmbientLight();
};
extern LightStudio lightStudio;
Light.cpp
Code:
#include "Light.h"
/*some more includes here*/
#define DEFAULT_INTENSITY_AMBIENT 0.2f
#define DEFAULT_INTENSITY_DIFFUSE 1.0f - DEFAULT_INTENSITY_AMBIENT
#define DEFAULT_INTENSITY_SPECULAR 1.0f
LightStudio lightStudio;
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//// L I G H T :: L I G H T S E T T I N G S ////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
Light::LightSettings::LightSettings()
{
disable();
intensity=0;
r=g=b=1.0;
}
Light::LightSettings::~LightSettings(){}
float Light::LightSettings::getRed(){return r;}
float Light::LightSettings::getGreen(){return g;}
float Light::LightSettings::getBlue(){return b;}
float Light::LightSettings::getIntensity(){return intensity;}
Light::LightSettings& Light::LightSettings::setIntensity(float intensity)
{
this->intensity=intensity;
return *this;
}
Light::LightSettings& Light::LightSettings::setColor(int hexColor)
{
r = (float)(hexColor & 0xFF0000)/(float)0xFF0000;
g = (float)(hexColor & 0x00FF00)/(float)0x00FF00;
b = (float)(hexColor & 0x0000FF)/(float)0x0000FF;
return *this;
}
Light::LightSettings& Light::LightSettings::setColor(float r, float g, float b)
{
this->r=r;
this->g=g;
this->b=b;
return *this;
}
Light::LightSettings& Light::LightSettings::disable()
{
use = false;
return *this;
}
Light::LightSettings& Light::LightSettings::enable()
{
use = true;
return *this;
}
void Light::LightSettings::drawMe(GLenum lightEnum)
{
// Set lighting intensity and color
GLfloat color[4];
color[0] = color[1] = color[2] = intensity;
color[3] = 1.0f;
glLightfv(lightEnum, GL_AMBIENT, color);
// Set material properties
GLfloat cc[4];
cc[0]=r;
cc[1]=g;
cc[2]=b;
cc[3]=1.0f;
glMaterialfv(GL_FRONT, GL_AMBIENT, cc);
}
/////////////////////////////////////
/////////////////////////////////////
//// L I G H T ////
/////////////////////////////////////
/////////////////////////////////////
Light::Light()
{
requestControl();
ambient.setIntensity(DEFAULT_INTENSITY_AMBIENT);
diffuse.setIntensity(DEFAULT_INTENSITY_DIFFUSE);
specular.setIntensity(DEFAULT_INTENSITY_SPECULAR);
}
Light::~Light()
{
lightStudio.releaseLightControl(this);
}
bool Light::requestControl()
{
lightNum = lightStudio.requestLightControl(this);
return lightNum==-1?false:true;
}
void Light::draw()
{
if (hasLightControl())
{
if (gameController.isLightingEnabled())
{
// Set the light position
GLfloat pos[4];
GLenum lightEnum;
lightEnum = getLightEnum();
//GLfloat dir[4];
pos[0] = (float)position.getX();
pos[1] = (float)position.getY();
pos[2] = (float)position.getZ();
pos[3] = 1.0f;
glLightfv(lightEnum, GL_POSITION, pos);
/*dir[0] = (float)direction.getI();
dir[1] = (float)direction.getJ();
dir[2] = (float)direction.getK();
glLightfv(getLightEnum(), GL_SPOT_DIRECTION, dir);*/
ambient.drawMe(lightEnum);
diffuse.drawMe(lightEnum);
specular.drawMe(lightEnum);
}
}
else
{
requestControl();
}
}
bool Light::hasLightControl()
{
return lightNum==-1?false:true;
}
GLenum Light::getLightEnum()
{
switch (lightNum)
{
case 0:
return GL_LIGHT0;
case 1:
return GL_LIGHT1;
case 2:
return GL_LIGHT2;
case 3:
return GL_LIGHT3;
case 4:
return GL_LIGHT4;
case 5:
return GL_LIGHT5;
case 6:
return GL_LIGHT6;
case 7:
return GL_LIGHT7;
default:
errLog.print("trying to use a non existant light in Light::getLightEnum");
assert(!"trying to use a non existant light in Light::getLightEnum");
return 0;
}
}
GLenum Light::getLightEnum(int num)
{
switch (num)
{
case 0:
return GL_LIGHT0;
case 1:
return GL_LIGHT1;
case 2:
return GL_LIGHT2;
case 3:
return GL_LIGHT3;
case 4:
return GL_LIGHT4;
case 5:
return GL_LIGHT5;
case 6:
return GL_LIGHT6;
case 7:
return GL_LIGHT7;
default:
errLog.print("trying to use a non existant light in Light::getLightEnum(int)");
assert(!"trying to use a non existant light in Light::getLightEnum(int)");
return 0;
}
}
/////////////////////////////////////////////////
/////////////////////////////////////////////////
//// L I G H T S T U D I O ////
/////////////////////////////////////////////////
/////////////////////////////////////////////////
LightStudio::LightStudio()
{
for (int i=0;i<8;i++)
{inUse[i] = 0;}
}
LightStudio::~LightStudio(){}
int LightStudio::requestLightControl(Light *light)
{
for (int i=0;i<8;i++)
{
if (inUse[i]==0)
{
inUse[i]=light;
glEnable(Light::getLightEnum(i));
mainLog(Str()<<"Enabling LIGHT"<<i<<" control to a new light");
return i;
}
}
return -1;//full
}
bool LightStudio::releaseLightControl(Light *light)
{
for (int i=0;i<8;i++)
{
if (inUse[i]==light)
{
inUse[i]=0;
mainLog(Str()<<"Disabling LIGHT"<<i<<" for an object");
glDisable(Light::getLightEnum(i));
return true;
}
}
return false;
}
LightStudio& LightStudio::setAmbientLight(int hexColor)
{
ambientLight = hexColor;
float cc[4];
cc[0]=(hexColor&0xFF0000)/(float)0xFF0000;
cc[1]=(hexColor&0x00FF00)/(float)0x00FF00;
cc[2]=(hexColor&0x0000FF)/(float)0x0000FF;
cc[3]=1.0f;
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, cc);
return *this;
}
int LightStudio::getAmbientLight()
{
return ambientLight;
}
Happy fun time with lights isn't so
The plane shows up as pure white! I'm sorry for such a book of a post, but I don't think leaving anything out would prove to be useful as a reader. In fact some more code might be required, but this should be decent enough for now. I appreciate the help, I don't want to get to a point where I just add stuff in to see if it might work. If requested, I will provide the git repo.
Thanks again