Несколько прожекторов в opengl не работают

Я использую opengl в образовательных целях, но у меня возникают проблемы с созданием нескольких прожекторов для представления уличных фонарей. Я использую итератор для создания нескольких, однако в конце концов свет получает только последний прожектор, я считаю, что проблема в методе addlight, однако я не знаю, что происходит.

На изображении ниже вы можете увидеть, как это происходит.

https://i.stack.imgur.com/ysnOd.jpg

#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();
}

person lllll    schedule 07.05.2019    source источник
comment
Возможно, попробуйте напечатать lamp.size в Add, чтобы увидеть, сколько их там, или поместите в цикл оператор точки останова / cout, чтобы увидеть, сколько раз он повторяется. Кроме того, вы создаете свои прожекторы ужасным образом, вам следует отказаться от динамического распределения памяти и просто иметь lamp.emplace_back({-8.0f, 5.f, (i*10) + 30.0f, 1.f});, поскольку в настоящее время у вас происходит утечка памяти.   -  person Tas    schedule 08.05.2019
comment
Спасибо за предупреждение. Что касается размера лампы, он печатает правильный номер.   -  person lllll    schedule 08.05.2019
comment
Когда вы говорите, что они не рисуют, вы имеете в виду, что цилиндры и конусы не рисуют, или вы имеете в виду, что световые эффекты не рисуют на других объектах?   -  person user253751    schedule 08.05.2019
comment
Я имею в виду, что свет исходит только из цилиндра, тогда как он должен исходить и из других.   -  person lllll    schedule 08.05.2019
comment
Я добавил изображение, чтобы показать, что происходит   -  person lllll    schedule 08.05.2019
comment
Здесь нет никакого кода, который рисует дорогу.   -  person user253751    schedule 08.05.2019
comment
@immibis добавил.   -  person lllll    schedule 08.05.2019


Ответы (2)


Вы всегда устанавливаете только LIGHT1, что означает, что будет включен только 1 свет (последний). Если вы укажете GL_LIGHT0 + index, вы сможете включить больше.

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);
}

И тогда вам просто нужно передать индекс при включении

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();

    }
}

Просто имейте в виду, что у вас может закончиться свет после 8, поэтому вы можете проверить значение GL_MAX_LIGHTS...

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

Предположительно, вы рисуете дорогу после того, как нарисовали все огни.

Ваш код делает это:

  • For each light:
    • Set light 1 according to that light's parameters
    • Нарисуйте форму самого света
  • Нарисуй дорогу.

Когда дорога отрисовывается, свет 1 настраивается с параметрами последнего нарисованного света. Таким образом, он использует эти параметры освещения для рисования дороги. Вы уже перезаписали все параметры других огней.

Если вы хотите нарисовать дорогу со всеми огнями, то все источники света должны быть настроены при рисовании дороги. Не только последний.

Обратите внимание, что вы можете настроить только 8 источников света одновременно в OpenGL. Если на дорогу направлено более 8 огней, вам придется разделить дорогу на разные участки, чтобы на каждом участке было до 8 огней.


Стандартный отказ от ответственности, если вы еще не знаете: вы используете OpenGL старого стиля (с фиксированными функциями), который был заменен OpenGL на основе шейдеров (версии 3 и 4). Этот API подходит для простых программ, но он не позволит вам использовать всю гибкость и производительность вашей видеокарты.

person user253751    schedule 08.05.2019