Why*_*ork 1 c++ opengl lighting
我写了一堂课来绘制一个平面并在上面放置一个纹理。我还开设了灯光课程。看起来我的光会影响固体物体,但它不会改变我的平面上的照明。无论如何,我的飞机似乎总是具有相同的照明。知道为什么它不起作用吗?
这就是我运行项目时的样子(圆锥体显示光线来自哪里): https: //i.stack.imgur.com/g1xOo.png
这是我的代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
至少有两个问题会妨碍您获得良好的照明。第一个应该很容易解决。第二个更深入。
以下调用确定如何将光照计算的结果与从纹理读取的颜色相结合:
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Run Code Online (Sandbox Code Playgroud)
顾名思义,GL_REPLACE意味着照明产生的颜色被纹理颜色替换。因此根据定义,如果您在启用纹理的情况下使用此设置,您将不会获得任何照明。
将照明颜色与从纹理读取的颜色相结合的最常见设置是GL_MODULATE:
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
Run Code Online (Sandbox Code Playgroud)
这意味着两种颜色(来自照明和纹理)相乘。
OpenGL 中的传统固定功能管道使用逐顶点光照。这意味着每个顶点仅计算一次照明方程,结果是在整个多边形上进行插值。
对于非常大的基元,逐顶点光照效果不佳,例如将整个平面绘制为单个大多边形的情况。特别是镜面高光通常会以这种方式丢失,如果图元很大,甚至漫反射项也会受到影响。
要解决此问题,有两个主要选项:
虽然如果您以前没有处理过的话,现在转向可编程管道对您来说是一个更大的步骤,但我仍然会考虑它。固定管道在现代版本的 OpenGL(Core Profile,以及 ES 2.x 及更高版本)中甚至不再可用,因此无论如何您迟早都会想要学习着色器编程。
| 归档时间: |
|
| 查看次数: |
6578 次 |
| 最近记录: |