OpenGL Multiple Light Sources

  • Sack TV
    Likes 0

    Problem Description

    I'm following the Modern OpenGL YouTube-Tutorial from your YouTube-Channel. I created a class for cubes and lamps. To calculate the lighting on cubes the positions of the lights is needed. This position is a vec3 array. This is working fine, but when i have more then one light-object i would have to pass the cube two arrays, which I don't know how to do. 

    This is my code:

     

    Cube class:

    #include "cubeVertices.h"

    #include "cube.hpp"

     

    using namespace glm;

     

    Cube::Cube(Shader shader):

    shader(shader) {

        glGenVertexArrays(1, &this->VAO);

        glGenBuffers(1, &this->VBO);

        

        glBindVertexArray(this->VAO);

        

        glBindBuffer(GL_ARRAY_BUFFER, VBO);

        glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW);

        

        //Pos

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid *) 0);

        glEnableVertexAttribArray(0);

        

        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid *) (3 * sizeof(GLfloat)));

        glEnableVertexAttribArray(1);

        

        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid *) (6 * sizeof(GLfloat)));

        glEnableVertexAttribArray(2);

        

        glBindVertexArray(0);

    }

     

    Cube::~Cube() {

        glDeleteVertexArrays(1, &this->VAO);

        glDeleteBuffers(1, &this->VBO);

    }

     

    void Cube::registerTexture(GLuint texture, const char* name) {

        glActiveTexture(GL_TEXTURE0);

        glBindTexture(GL_TEXTURE_2D, texture);

        glUniform1i(glGetUniformLocation(shader.program, name), 0);

    }

     

    void Cube::render(GLfloat size, vec3 positions[], int amount, vec3 lightPos[], int lightAmount, float reflection, mat4 projection, Camera camera, bool spotLight) {

        GLint viewPosLoc = glGetUniformLocation(shader.program, "viewPos");

        glUniform3f(viewPosLoc, camera.getPosition().x, camera.getPosition().y, camera.getPosition().z);

        

        GLint modelLoc = glGetUniformLocation(shader.program, "model");

        GLint viewLoc = glGetUniformLocation(shader.program, "view");

        GLint projLoc = glGetUniformLocation(shader.program, "projection");

        

        for(int i = 0; i < lightAmount; i++) {

            std::string pointLightBase = "pointLight[" + std::to_string(i) + "].";

            glUniform3f(glGetUniformLocation(shader.program, (pointLightBase + "position").c_str()), lightPos[i].x, lightPos[i].y, lightPos[i].z);

            glUniform3f(glGetUniformLocation(shader.program, (pointLightBase + "ambient").c_str()), 0.0f, 0.0f, 0.0f);

            glUniform3f(glGetUniformLocation(shader.program, (pointLightBase + "diffuse").c_str()), 0.8f, 0.8f, 0.8f);

            glUniform3f(glGetUniformLocation(shader.program, (pointLightBase + "specular").c_str()), 1.0f, 1.0f, 1.0f);

            glUniform1f(glGetUniformLocation(shader.program, (pointLightBase + "constant").c_str()),1.0f);

            glUniform1f(glGetUniformLocation(shader.program, (pointLightBase + "linear").c_str()), 0.0f);

            glUniform1f(glGetUniformLocation(shader.program, (pointLightBase + "quadratic").c_str()), 0.032f);

        }

        

        if(spotLight) {

            glUniform3f(glGetUniformLocation(shader.program, "spotLight.position"), camera.getPosition().x, camera.getPosition().y, camera.getPosition().z);

            glUniform3f(glGetUniformLocation(shader.program, "spotLight.direction"), camera.getFront().x, camera.getFront().y, camera.getFront().z);

            glUniform3f(glGetUniformLocation(shader.program, "spotLight.ambient"), 0.0f, 0.0f, 0.0f);

            glUniform3f(glGetUniformLocation(shader.program, "spotLight.diffuse"), 0.8f, 0.8f, 0.8f);

            glUniform3f(glGetUniformLocation(shader.program, "spotLight.specular"), 1.0f, 1.0f, 1.0f);

            glUniform1f(glGetUniformLocation(shader.program, "spotLight.constant"), 1.0f);

            glUniform1f(glGetUniformLocation(shader.program, "spotLight.linear"), 0.09f);

            glUniform1f(glGetUniformLocation(shader.program, "spotLight.quadratic"), 0.032f);

            glUniform1f(glGetUniformLocation(shader.program, "spotLight.cutOff"), cos(radians(12.5f)));

            glUniform1f(glGetUniformLocation(shader.program, "spotLight.outerCutOff"), cos(radians(15.0f)));

        }

        else {

            glUniform3f(glGetUniformLocation(shader.program, "spotLight.position"), camera.getPosition().x, camera.getPosition().y, camera.getPosition().z);

            glUniform3f(glGetUniformLocation(shader.program, "spotLight.direction"), camera.getFront().x, camera.getFront().y, camera.getFront().z);

            glUniform3f(glGetUniformLocation(shader.program, "spotLight.ambient"), 0.0f, 0.0f, 0.0f);

            glUniform3f(glGetUniformLocation(shader.program, "spotLight.diffuse"), 0.0f, 0.0f, 0.0f);

            glUniform3f(glGetUniformLocation(shader.program, "spotLight.specular"), 0.0f, 0.0f, 0.0f);

            glUniform1f(glGetUniformLocation(shader.program, "spotLight.constant"), 1.0f);

            glUniform1f(glGetUniformLocation(shader.program, "spotLight.linear"), 0.09f);

            glUniform1f(glGetUniformLocation(shader.program, "spotLight.quadratic"), 0.032f);

            glUniform1f(glGetUniformLocation(shader.program, "spotLight.cutOff"), cos(radians(20.0f)));

            glUniform1f(glGetUniformLocation(shader.program, "spotLight.outerCutOff"), cos(radians(25.0f)));

        }

        

        glUniform1f(glGetUniformLocation(shader.program, "material.shininess"), reflection);

        

        mat4 view(1);

        view = camera.getViewMatrix();

        

        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, value_ptr(view));

        glUniformMatrix4fv(projLoc, 1, GL_FALSE, value_ptr(projection));

        glBindVertexArray(VAO);

        

        for(int i = 0; i < amount; i++) {

            mat4 model(1);

            model = translate(model, positions[i]);

            model = scale(model, vec3(size));

            glUniformMatrix4fv(modelLoc, 1, GL_FALSE, value_ptr(model));

            

            glDrawArrays(GL_TRIANGLES, 0, 36);

        }

        glBindVertexArray(0);

    }

     

    Light class:

    LuminousCube::LuminousCube(Shader shader):

    shader(shader) {

        glGenVertexArrays(1, &this->VAO);

        glGenBuffers(1, &this->VBO);

        

        glBindVertexArray(this->VAO);

        

        glBindBuffer(GL_ARRAY_BUFFER, this->VBO);

        glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW);

        

        //Pos

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid *) 0);

        glEnableVertexAttribArray(0);

        

        glBindBuffer(GL_ARRAY_BUFFER, 0);

        

        glBindVertexArray(0);

    }

     

    LuminousCube::~LuminousCube() {

        glDeleteVertexArrays(1, &this->VAO);

        glDeleteBuffers(1, &this->VBO);

    }

     

    void LuminousCube::render(GLfloat size, vec3 positions[], int amount, mat4 projection, Camera camera) {

        mat4 view(1);

        view = camera.getViewMatrix();

        mat4 model(1);

        

        GLint modelLoc = glGetUniformLocation(shader.program, "model");

        GLint viewLoc = glGetUniformLocation(shader.program, "view");

        GLint projLoc = glGetUniformLocation(shader.program, "projection");

        

        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, value_ptr(view));

        glUniformMatrix4fv(projLoc, 1, GL_FALSE, value_ptr(projection));

        

        glBindVertexArray(VAO);

        

        for(int i = 0; i < amount; i++) {

            mat4 model(1);

            model = translate(model, positions[i]);

            model = scale(model, vec3(size));

            glUniformMatrix4fv(modelLoc, 1, GL_FALSE, value_ptr(model));

            

            glDrawArrays(GL_TRIANGLES, 0, 36);

        }

        glBindVertexArray(0);

    }

     

    Game-Loop in main.cpp:

     while (!glfwWindowShouldClose(window)) {

            GLfloat currentFrame = glfwGetTime();

            deltaTime = currentFrame - lastFrame;

            lastFrame = currentFrame;

            

            glfwPollEvents();

            doMovement();

            

            glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            

            glfwGetFramebufferSize(window, &screenWidth, &screenHeight);

            glViewport(0, 0, screenWidth, screenHeight);

            

            mat4 projection = perspective(45.0f, (GLfloat)screenWidth / (GLfloat)screenHeight, 0.1f, 100.0f);

     

            cubeShader.use();

         

            cube1.registerTexture(texture1, "cube1");

            cube1.render(1.0f, cubePos,  sizeof(cubePos) / sizeof(vec3), lightPos,  sizeof(lightPos) / sizeof(vec3), 30.0f, projection, camera, spotLight);

     

            lightShader.use();

            lamp1.render(3.1415f / 4, vec3(1.0f, 0.0f, 0.0f), vec3(0.2f), lightPos, sizeof(lightPos) / sizeof(vec3), projection, camera);

     

            glfwSwapBuffers(window);

        }

  • Sonar Systems admin
    Likes 0

    Pass to the shader?

  • Sack TV
    Likes 0

    I don't know if it is the correct english word, but the shader of the cube needs the positions of the lamps, this is what i mean by pass. 

  • Sack TV
    Likes 0

    Edit: i solved this issue.

    Also, I get another problem, I give the cube shader the light positions. I have 2 dice objects and 2 lamp objects. The first cube object receives the light positions of the first light object, the second cube object receives the light positions of the second light object. But also the second cube objects are illuminated by the first light objects and not by the second, how can I change that?


  • Sonar Systems admin
    Likes 0

    Can you show me the result and code.

  • Sack TV
    Likes 0

    The code has not changed, I deleted a part of the cube code due to an earlier test, the code above works.

    My approach to multiple light objects is to merge the light fields and then pass the merged fields to the cube shader. I think it would work, but I have some errors, maybe you can help me solve the problems.

    I made this function to merge two arrays: Edit this is fixed

    int * combine arrays (int * array1, int * array2, const int array1Size, const int array2Size) {

    static int result [7] = {0};

    for (int i = 0; i

    result [i] = array1 [i];

    }

    for (int i = array1Size; i

    result [i] = array2 [i - array1Size];

    }

    return result;

    }

    It works, but the problem is that the size of the result is fixed and I do not know how to use the array sizes of the arrays to be merged, which are passed into the function, because this: 
    static int result[array1Size + array2Size]; doesn't work. 

     

    Is there a way to pass the number of point lights to the fragment shader of the cube? Because now, the number of point lights is just a define.


  • Sonar Systems admin
    Likes 0

  • Sonar Systems admin
    Likes 0

  • Sack TV
    Likes 0

    Can you please just send me the code HERE, i don’t want to watch a 45 minute video for a few lines of code.

  • Sonar Systems admin
    Likes 0

  • Sack TV
    Likes 0

    I DON’T want the array-size as a define, i asked if there is a way to pass the shader the array-size.

  • Sonar Systems admin
    Likes 0

    ?     

  • Sack TV
    Likes 0

    Is there a way to pass the shader the number of point lights other than with a define?

  • Sonar Systems admin
    Likes 0

    A regular variable

  • Sack TV
    Likes 0

    But how, I tried this:

    uniform const int arraySize;

    but it doesn't work.

  • Sonar Systems admin
    Likes 0

    What happens?

  • Sack TV
    Likes 0

    Nothing, i just get an error that this is not right, I need a way to pass in a const int.

  • Sonar Systems admin
    Likes 0

    What’s the exact error?

  • Sack TV
    Likes 0

    Seriously, can you just send me the code to pass a const int into the shader?

    But here the eroor: Infolog: ERROR: 0:45: storage modifier qualifier 'const' must precede storage qualifiers

  • Sonar Systems admin
    Likes 0

  • Sack TV
    Likes 0

    Thank you

  • Sonar Systems admin
    Likes 0

    You are very welcome.

Login to reply