Reputation: 293
I have a class I have written to draw a plane and a put a texture on it. I have also made a class for lighting. It appears that my light will affect solid objects, but it doesn't change the lighting on my plane. My plane always appears to have the same lighting no matter what. Any idea why it isn't working?
This is what it looks like when I run the project (the cone shows where the light is coming from): https://i.sstatic.net/g1xOo.png
This is my code:
class Light
{
public:
//light constructor
void Draw();
private:
GLenum m_LightSource;
float m_Ambient[4];//ambient is light all around
float m_Specular[4];//gleem that hits an object
float m_Diffuse[4];//lights oart of an object
float m_SpotlightWidth;
float m_Position[4];
float m_Attenuation;
float m_MaterialSpecular[4];
float m_MaterialShine[1];
};
void Light::Draw()
{
glPushMatrix();
glTranslatef(m_Position[0], m_Position[1], m_Position[2]); // Move the spotlight.
// Light properties.
glLightfv(m_LightSource, GL_AMBIENT, m_Ambient);
glLightfv(m_LightSource, GL_DIFFUSE, m_Diffuse);
glLightfv(m_LightSource, GL_SPECULAR, m_Specular);
glEnable(m_LightSource);// Enable particular light source.
// Material properties shared by all the spheres.
glMaterialfv(GL_FRONT, GL_SPECULAR, m_MaterialSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, m_MaterialShine);
if(m_DrawCone)
{
// Draw the spotlight cone in wireframe after disabling lighting
glPushMatrix();
glDisable(GL_LIGHTING);
glRotatef(-90.0, 1.0, 0.0, 0.0);
glColor3f(1.0, 1.0, 1.0);
glutWireCone(3.0 * tan( m_SpotlightWidth/180.0 * PI ), 3.0, 20, 20);
glEnable(GL_LIGHTING);
glPopMatrix();
}
float lightPos[] = { 0.0, 3.0, 0.0, 1.0 }; // Spotlight position.
float spotDirection[] = {0.0, -1.0, 0.0}; // Spotlight direction.
// Spotlight properties including position.
glLightfv(m_LightSource, GL_POSITION, lightPos);
glLightf(m_LightSource, GL_SPOT_CUTOFF, m_SpotlightWidth);
glLightfv(m_LightSource, GL_SPOT_DIRECTION, spotDirection);
glLightf(m_LightSource, GL_SPOT_EXPONENT, m_Attenuation);
glPopMatrix();
}
class Plane
{
public:
Plane();
Plane(float x, float y, float z, float width, float height, float depth, string textureName);
void Draw();
private:
float m_CenterX, m_CenterY, m_CenterZ, m_Width, m_Height, m_Depth;
unsigned int m_Texture[1];
unsigned char m_Colour[3];
string m_TextureName;
};
void Plane::Draw()
{
if(m_HasTexture)
{
// Turn on OpenGL texturing.
glEnable(GL_TEXTURE_2D);
// Activate a texture.
glBindTexture(GL_TEXTURE_2D, m_Texture[0]);
// Map the texture onto a square polygon.
glBegin(GL_POLYGON);
glTexCoord2f(0.0, 1.0); glVertex3f(m_CenterX - m_Width, m_CenterY - m_Height, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(m_CenterX + m_Width, m_CenterY - m_Height, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(m_CenterX + m_Width, m_CenterY + m_Height, 0.0);
glTexCoord2f(0.0, 0.0); glVertex3f(m_CenterX - m_Width, m_CenterY + m_Height, 0.0);
glEnd();
// Turn off OpenGL texturing.
glDisable(GL_TEXTURE_2D);
}
void Plane::LoadTexture(string textureName)
{
// Create texture index array.
glGenTextures(1, m_Texture);
// Local storage for bmp image data.
PNGFile *image[1];
// Load the texture.
image[0] = GetPNGData(textureName);
// Bind image to texture index[0].
glBindTexture(GL_TEXTURE_2D, m_Texture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//used to make the image look blocky
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image[0]->sizeX, image[0]->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, image[0]->pixels.data() );
delete image[0];
}
void drawScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//glulookat
// Turn on OpenGL lighting.
glEnable(GL_LIGHTING);
//Light.Draw();
// Draw 10 x 10 array of multi-colored spheres.
int i,j;
for (i = 0; i < 9; i++)
for (j = 0; j < 9; j++)
{
glPushMatrix();
glTranslatef(-4.0+i, 0.0, -4.0+j);
// Ambient and diffuse colors of the spheres specified to alternate.
if ((i+j)%3 == 0) glColor4f(1.0, 0.0, 0.0, 1.0);
else if ((i+j)%3 == 1) glColor4f(0.0, 1.0, 0.0, 1.0);
else glColor4f(0.0, 0.0, 1.0, 1.0);
glutSolidSphere (0.5, 20.0, 16.0);
glPopMatrix();
}
plane.Draw();
glutSwapBuffers();
}
void setup(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
plane = Plane(0,0,-10,5,5,0, "launch.png");
glShadeModel (GL_SMOOTH);
// stops GL_QUAD from showing faces by priority
glEnable(GL_DEPTH_TEST);
// Specify how texture values combine with current surface color values.
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glEnable(GL_BLEND); // Enable blending.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Enable color material mode:
// The ambient and diffuse color of the front faces will track the color set by glColor().
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
}
Upvotes: 1
Views: 6875
Reputation: 54642
There are at least two problems that prevent you from getting good lighting. The first one should be easy to solve. The second one goes deeper.
The following call determines how the result of the lighting calculation is combined with the color read from the texture:
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
As the name indicates, GL_REPLACE
means that the color resulting from lighting is replaced by the texture color. So by definition, you will get no lighting if you use this setting with texturing enabled.
The most common setting to combine the color from lighting with the color read from the texture is GL_MODULATE
:
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
This means that the two colors (from lighting and from texture) are multiplied.
The legacy fixed function pipeline in OpenGL uses per-vertex lighting. This means that the lighting equations are only evaluated once per vertex, and the result is the interpolated across the entire polygon.
Per-vertex lighting works poorly for very large primitives, like in the case where you draw the entire plane as a single, large polygon. Particularly specular highlights are normally lost this way, and even the diffuse term suffers if the primitives are two large.
To fix this, there are two main options:
While moving to the programmable pipeline is a bigger step for you right now if you have not dealt with it before, I would still consider it. The fixed pipeline is not even available anymore in modern versions of OpenGL (Core Profile, as well as ES 2.x and later), so you will want to learn about shader programming sooner or later anyway.
Upvotes: 5