Multiple spotlights in opengl doesn't work

442 Views Asked by At

I'm using opengl for educational purposes, but I'm having trouble creating multiple spotlights to represent street lamps. I use an iterator to create several however in the end only the last spotlight gets the light, I believe the problem is in the addlight method however I do not know what is happening.

In image below you can see happen.

https://imgur.com/Y77eHln

#include "CreateLamps.h"

std::vector<SpotLight> lamp;

CreateLamps::CreateLamps(int number) {

    for (int i = 0; i < number; i++) {
        SpotLight *spot = new SpotLight(-8.0f, 5.f, (i*10) + 30.0f, 1.f);
        lamp.push_back(*spot);
    }

}

void CreateLamps::Add() {

    std::vector<SpotLight>::iterator it = lamp.begin();

    while (it != lamp.end())
    {

        glPushMatrix();
        glTranslatef(1, 0, 30.0);
        glTranslatef(it->position[0], it->position[3] * 3, it->position[2]);
        glRotatef(100.f, -5.0, -10, 0);
        it->addlight();
        it->draw();
        it++;
        glPopMatrix();

    }
}

#include "SpotLight.h"

using namespace std;

GLfloat target[3] = { 0.0f, 0.0f, 0.0f };
GLfloat color[3] = { 1.0f, 1.0f, 1.0f };
GLfloat cutoff(5.0f);
GLfloat exponent(15.0f);

SpotLight::SpotLight(GLfloat x, GLfloat y, GLfloat z, GLfloat w) {

    position[0] = x;
    position[1] = y;
    position[2] = z;
    position[3] = w;

    direction[0] = target[0] - position[0];
    direction[1] = target[1] - position[1];
    direction[2] = (target[2] - position[2]);

}

void SpotLight::addlight() {

    glEnable(GL_LIGHT1);

    glLightfv(GL_LIGHT1, GL_DIFFUSE, color);
    glLightfv(GL_LIGHT1, GL_SPECULAR, color);
    glLightfv(GL_LIGHT1, GL_POSITION, position);

    glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, direction);
    glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, cutoff);
    glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, exponent);

}

void SpotLight::draw() {
    if (!glIsEnabled(GL_LIGHT1)) 
        return;

    glPushMatrix();
    GLfloat up[3] = { 0, 1, 0 };
    lookAt(position, target, up);

    GLfloat ambient[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
    GLfloat diffuse[4] = { 0.01f, 0.01f, 0.01f, 1.0f };
    GLfloat specular[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
    GLfloat shininess = 32.0f;

    glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
    glMaterialf(GL_FRONT, GL_SHININESS, shininess);

    glutSolidCone(0.3, 0.6, 10, 10);
    glPushMatrix();
    glTranslatef(0, 0, 0.1f);
    glutSolidCylinder(0.2, 0.39, 10, 10);
    glPopMatrix();

    glDisable(GL_LIGHTING);
    glColor3fv(color);
    glutSolidSphere(0.2, 100, 100);
    glEnable(GL_LIGHTING);
    glPopMatrix();
}


void SpotLight::normalize(const GLfloat* vec, GLfloat* output)
{
    GLfloat length = sqrtf(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
    output[0] /= length;
    output[1] /= length;
    output[2] /= length;
}

void SpotLight::cross(const GLfloat* vec1, const GLfloat* vec2, GLfloat * output) {
    output[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
    output[1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
    output[2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
}

void SpotLight::lookAt(GLfloat* eye, GLfloat* center, GLfloat* up)
{
    GLfloat f[3] = { center[0] - eye[0],
                     center[1] - eye[1],
                     center[2] - eye[2] };

    normalize(f, f);
    GLfloat u[3];
    normalize(up, u);
    GLfloat s[3];
    cross(f, u, s);
    normalize(s, s);
    cross(s, f, u);
    normalize(u, u);

}

void drawScene() {

    glPushMatrix();
    glTranslatef(pointlight.position[0], pointlight.position[1], pointlight.position[2]);
    pointlight.addLight();
    glPopMatrix();

    // Draw road
    glPushMatrix();
    glScalef(10, 10, 8.5);
    glTranslatef(-0.018f, 0, 0.75);
    glRotatef(180.f, 0, 1, 0);
    models[0]->renderTheModel();
    glPopMatrix();

    //Draw Car Model
    glPushMatrix();
    glMultMatrixf(carros[0]->local);
    carros[0]->draw();
    glPopMatrix();

//Draw spotlights
    glPushMatrix();
    lamps->Add();
    glPopMatrix();
}
2

There are 2 best solutions below

0
user253751 On

Presumably you are drawing the road after drawing all of the lights.

Your code does this:

  • For each light:
    • Set light 1 according to that light's parameters
    • Draw the shape of the light itself
  • Draw the road.

When the road gets drawn, light 1 is set up with the parameters of the last light that was drawn. So it uses these light parameters to draw the road. You overwrote all the parameters of the other lights already.

If you want to draw the road with all the lights, then all the lights have to be set up when you draw the road. Not just the last one.

Note that you can only set up 8 lights at once in OpenGL. If have more than 8 lights pointing at the road, you will have to split up the road into different sections so that each section has up to 8 lights.


Standard disclaimer in case you aren't aware already: You are using old-style (fixed-function) OpenGL which has been superseded by shader-based OpenGL (version 3 and 4). This API is okay for simple programs but it won't let you use the full flexibility and performance of your graphics card.

0
robthebloke On

You are only ever setting LIGHT1, which means only 1 light is going to have been enabled (the last one). If you specify GL_LIGHT0 + index, you'll be able to enable more.

void SpotLight::addlight(int index) {

    glEnable(GL_LIGHT0 + index);

    glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, color);
    glLightfv(GL_LIGHT0 + index, GL_SPECULAR, color);
    glLightfv(GL_LIGHT0 + index, GL_POSITION, position);

    glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction);
    glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, cutoff);
    glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, exponent);
}

And then you simply need to pass the index in when enabling

void CreateLamps::Add() {

    std::vector<SpotLight>::iterator it = lamp.begin();

    while (it != lamp.end())
    {

        glPushMatrix();
        glTranslatef(1, 0, 30.0);
        glTranslatef(it->position[0], it->position[3] * 3, it->position[2]);
        glRotatef(100.f, -5.0, -10, 0);
        it->addlight(it - lamp.begin());
        it->draw();
        it++;
        glPopMatrix();

    }
}

Just be aware that you might run out of lights after 8, so you might want to check the value of GL_MAX_LIGHTS...

int numLights = 0;
glGetIntegerv(GL_MAX_LIGHTS, &numLights);
std::cout << "GL_MAX_LIGHTS " << numLights << std::endl;