Thread: Lighting with OpenGL

  1. #1
    Registered User
    Join Date
    Jul 2011
    Posts
    22

    Unhappy Lighting with OpenGL

    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

  2. #2
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,739
    By the way I see it, you apply no color to the plane! How did you expect it to draw anything other that the light's properties?
    Assuming that you're learning about lighting, you also know about materials, right? You need to set a color for the plane by applying a texture or enabling "GL_COLOR_MATERIAL" and passing a "glColor*".
    Devoted my life to programming...

  3. #3
    Registered User
    Join Date
    Jul 2011
    Posts
    22
    I do set the color for my object, but I did not post that piece. I disable lighting in my project and the colored blue tessellated plane displays properly as blue. Only when I try adding in my lights does it start acting up. Just enabling lighting makes the whole window dark, then adding in my light object turns the plane into pure white with a black background.

    Thanks for the response.

  4. #4
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,739
    Like I said, did you do this at the beginning?:
    Code:
    glEnable(GL_COLOR_MATERIAL);
    Devoted my life to programming...

  5. #5
    Registered User
    Join Date
    Jul 2011
    Posts
    22
    Ah, I commented that line of code out originally because it looked like I disabled lighting (this is when I wasn't calculating the normals on each plane). But I forgot about it possibly doing anything. It hasn't completely fixed the problem, but I think I know where it might lie. Now that I enabled that line of code, I have my tessellated plane drawing a some white squares in a line. I believe that my normals are not getting generated properly. I will be doing some more tests.

    Thanks again

  6. #6
    Registered User
    Join Date
    Jul 2011
    Posts
    22
    Well, I havn't made too much progress on this. In fact, I think by trouble shooting I made the problem worse. I started out with no lighting, then added in "GL_COLOR_MATERIAL" which got it work to a degree. It was drawing a some blinding white boxes on the tessellated plane in a narrow line. I also used shine which got it to be wider, but still not what I was looking for. I was assuming my normal vertexes were not accurately portrayed, so I got to work. I used some green lines to show the direction I was making the vertexes in, and low and behold they were off. Not too much of a surprise. I was trouble shooting that for a while, but stopped to implement more camera commands. After a while I found that I forgot a negative sign in the j hat component (its always a negative sign right?). I even made a new vector class for calculations (needed to do it anyways). Even though I fixed that problem, the normals are still not quite being calculated correctly, but moving right along with a most of the normals showing up in the right direction. I removed the debug green lines and enabled light again only to see that light is not doing anything anymore.

    Im not sure how I messed that one up. I did not even touch lighting. If anyone knows what might be going on that would be great.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. OpenGL lighting
    By Zishaan in forum Game Programming
    Replies: 6
    Last Post: 04-21-2007, 03:24 PM
  2. OpenGL lighting problems
    By kawk in forum Game Programming
    Replies: 11
    Last Post: 04-18-2007, 10:08 AM
  3. OpenGL lighting
    By BabyG in forum Game Programming
    Replies: 3
    Last Post: 08-29-2004, 09:58 AM
  4. Lighting in OpenGL
    By MathFan in forum Game Programming
    Replies: 5
    Last Post: 06-28-2004, 12:56 PM
  5. need help with opengl lighting!!
    By genghis37 in forum Game Programming
    Replies: 1
    Last Post: 06-22-2002, 12:28 AM