Opengl:我如何影响纹理平面上的光照?

时间:2014-12-30 20:55:39

标签: c++ opengl lighting

我有一个我写过的课来画一个平面并在上面放一个纹理。我也做了一个照明课。看来我的光线会影响固体物体,但它不会改变我飞机上的光线。无论如何,我的飞机似乎总是拥有相同的照明。知道为什么它不工作吗?

这是我运行项目时的样子(圆锥显示灯光的来源):http://i.imgur.com/uEHe7Ea.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);
}

1 个答案:

答案 0 :(得分:3)

至少有两个问题会妨碍您获得良好的照明。第一个应该很容易解决。第二个更深入。

纹理组合设置

以下调用确定如何将光照计算的结果与从纹理中读取的颜色组合:

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

如名称所示,GL_REPLACE表示由光照产生的颜色由纹理颜色替换。因此,根据定义,如果在启用纹理的情况下使用此设置,则不会获得光照。

将灯光颜色与纹理颜色相结合的最常见设置是GL_MODULATE

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

这意味着两种颜色(来自光照和纹理)相乘

每顶点照明

OpenGL中的传统固定功能管道使用每顶点照明。这意味着每个顶点仅评估一次光照方程,结果是在整个多边形上进行插值。

对于非常大的图元,每顶点光照效果很差,例如在将整个平面绘制为单个大的多边形的情况下。特别是镜面高光通常会以这种方式丢失,如果基元是两个大的话,甚至漫反射项也会受到影响。

要解决此问题,有两个主要选项:

  • 将平面细分为较小的多边形。这将引入更多顶点,其中将评估光照,从而减少插值导致的问题。
  • 使用每片段照明。我相信人们可能已经找到了用固定管道做到这一点的方法,但我认为这并不容易。你真的进入了一个可编程管道非常优越的领域。

如果您之前没有处理过,那么转移到可编程管道对您来说是一个更大的步骤,我仍然会考虑它。在现代版本的OpenGL(Core Profile,以及ES 2.x及更高版本)中,固定管道甚至不再可用,因此您无论如何都要迟早了解着色器编程。