splunk
splunk

Reputation: 6789

lighting in OpenGL with shaders

I'm trying to apply some lighting to texture. I have created a textured cube and I placed a camera inside of it. Now, I'd like to light its internal faces. I've been told I should use shaders, so I read many tutorials and I've created:

vertex shader:

const GLchar* vertexSkySource =
#if defined(__APPLE_CC__)
"#version 150 core\n"
#else
"#version 130\n"
#endif
"uniform mat3 view_rot;"
"in vec3 position;"
"out vec3 Coord;"
"void main() {"
"   Coord = view_rot * position;"
"   gl_Position = vec4(position, 1.0);"
"}";

fragment shader

const GLchar* fragmentSkySource =
#if defined(__APPLE_CC__)
"#version 150 core\n"
#else
"#version 130\n"
#endif
"in vec3 Coord;"
"out vec4 outColor;"
"uniform samplerCube textureSampler;"
"void main() {"
"   outColor =  texture(textureSampler, Coord);"
"}";

After I initialize them

void initialize_shader()
{
    // shader per la skybox
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexSkySource, NULL);
    glCompileShader(vertexShader);
    {
        GLchar log[512];
        GLsizei slen = 0;
        glGetShaderInfoLog(vertexShader, 512, &slen, log);
        if (slen)
            std::cerr << log << std::endl;
    }

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentSkySource, NULL);
    glCompileShader(fragmentShader);
    {
        GLchar log[512];
        GLsizei slen = 0;
        glGetShaderInfoLog(fragmentShader, 512, &slen, log);
        if (slen)
            std::cerr << log << std::endl;
    }

    skyProgram = glCreateProgram();
    glAttachShader(skyProgram, vertexShader);
    glAttachShader(skyProgram, fragmentShader);
    glBindFragDataLocation(skyProgram, 0, "outColor");
    glLinkProgram(skyProgram);
    GLint status = 0;
    glGetProgramiv(skyProgram, GL_LINK_STATUS, &status);
    if (!status)
    {
        std::cout << "failed to link" << std::endl;
        GLchar log[256];
        GLsizei slen = 0;
        glGetProgramInfoLog(skyProgram, 256, &slen, log);
        std::cout << log << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

Then in my draw method which will be called inside main method I do this:

glm::vec3 light_direction = glm::normalize(glm::vec3(1.f, 1.f, 3.f));
glm::vec3 light_position = glm::vec3(1.0f, 1.0f, 0.0f);
glm::vec3 light_intensity = glm::vec3(1.f, 1.f, 1.f);

glDepthMask(GL_FALSE);
glUseProgram(skyProgram);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureCube);
glUniform1i(glGetUniformLocation(skyProgram, "textureSampler"), 3);
glUniform3fv(glGetUniformLocation(skyProgram, "light_direction"), 1, &light_direction[0]);
glUniform3fv(glGetUniformLocation(skyProgram, "light_intensity"), 1, &light_intensity[0]);
glUniform3fv(glGetUniformLocation(skyProgram, "view_position"), 1, &camera_position[0]);
glUniform1f(glGetUniformLocation(skyProgram, "shininess"), 60); // shininess = 60, range is [0.0 - 128.0] 
glUniformMatrix3fv(glGetUniformLocation(skyProgram, "view_rot"), 1, GL_FALSE, &(glm::mat3(glm::inverse(view)))[0][0]);

I can't see lights on the cube faces, what should I add to my shaders?

Upvotes: 0

Views: 1326

Answers (1)

SurvivalMachine
SurvivalMachine

Reputation: 8356

You are sending light parameters (light_direction, light_intensity, view_position and shininess) into the shader, but you're not receiving them or doing anything with them. Your fragment shader only reads a texture but doesn't apply any lighting to it:

outColor =  texture(textureSampler, Coord);

Complete source to shading would be big and without seeing more code is hard to give, so I'll give some pointers:

  • The first thing would be adding some glGetError() calls into various parts of your C++ code so you'll know if you use OpenGL API wrong.
  • In addition to position, you'll need to send vertex normals to the shader
  • You'll need to choose a shading algorithm, Blinn-Phong is simple and widely used.
  • You'll need to make sure that normal and light direction are in the same coordinate-space

So, in the end your outColor needs to be multiplied with the calculated shading:

outColor =  texture(textureSampler, Coord) * shading;

but you'll need to modify your vertex and fragment shader to calculate it based on the light's direction and vertex normal.

Edit based on GitHub project:

I compiled and ran the project and had to fix some problems:

  • Include and Library paths were set for your computer and not relative to the project directory.

  • In the fragment shader you are declaring "shading" as "out". Remove that line and add vec4 shading = vec4(0.0, 0.0, 0.0, 1.0); before shading += vec4...

  • vec4(light_intensity) is wrong and doesn't compile on my NVIDIA Windows driver, replace with vec4(light_intensity,1.0)

I couldn't get anything on the screen even if I modified the shader to always output red.

Upvotes: 2

Related Questions