-1

I'm using the Blinn-Phong algorithm to calculate the lighting in a scene, and I'm not factoring in distance yet. I've also disabled my HDR and Specular calculations until I get this first issue fixed.

I'm somewhere on the order of 95% sure that it's a mistake in my fragment shader, but I'm setting up a full MCVE just in case I made a mistake elsewhere.

Fragment Shader:

R"DATA(#version 430
layout(location = 0) in vec3 vertex_color;
layout(location = 1) in vec3 vertex_normal;
layout(location = 2) in vec3 vertex_position;

layout(location = 0) out vec4 fragment_color;

uniform float ambient_factor = 0.05;
uniform float diffuse_factor = 1;
//Specular Lighting is disabled until I figure out where the mistake is.
uniform float specular_factor = 0;
uniform float specular_shininess = 15;

uniform vec4 light_position = vec4(2, 0, 2, 1);
uniform vec4 light_color = vec4(1, 1, 1, 1);

uniform float exposure = 1;

uniform vec4 eye;

void main() {
    vec3 texture_color = vertex_color;
    vec3 normalized_fragment_normal = normalize(vertex_normal);

    vec3 light_direction = normalize(light_position.xyz - vertex_position);
    vec3 eye_direction = normalize(eye.xyz - vertex_position);
    vec3 halfway_vector = normalize(light_direction + eye_direction);

    float diffuse_strength = clamp(dot(normalized_fragment_normal, light_direction), 0, 1);
    float blinn_phong_specular_strength = max(dot(normalized_fragment_normal, halfway_vector), 0);

    vec3 working_color = vec3(
        texture_color * ambient_factor + 
        light_color.xyz * light_color.w * texture_color * diffuse_strength * diffuse_factor + 
        light_color.xyz * light_color.w * pow(blinn_phong_specular_strength, specular_shininess) * specular_factor
    );

    //For handling HDR, but disabling for now so that the lighting differences/mistakes are more obvious.
    //const float gamma = 2.2;
    //vec3 mapped = vec3(1) - exp(-working_color * exposure);

    //mapped = pow(mapped, vec3(1 / gamma));

    //fragment_color = vec4(mapped, 1);
    fragment_color = vec4(working_color, 1);
})DATA"

Vertex Shader:

R"DATA(#version 430
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;
layout(location = 2) in vec3 normal;

layout(location = 0) out vec3 vertex_color;
layout(location = 1) out vec3 vertex_normal;
layout(location = 2) out vec3 vertex_position;

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model_position;
uniform mat4 model_normal;

void main() {
    gl_Position = projection * view * model_position * vec4(position, 1);
    vertex_color = color;
    vertex_normal = (model_normal * vec4(normal, 0)).xyz;
    vertex_position = (model_position * vec4(position, 1)).xyz;
})DATA"

Shaders.h:

#pragma once

#pragma warning( push )
#pragma warning( once : 4251)
#include<glbinding\gl\gl.h>
#include<glbinding\Binding.h>
#pragma warning( pop ) 

const char * vert_src = ""
#include "Cube.vert.glsl"
;

const char * frag_src = ""
#include "Cube.frag.glsl"
;

//The two Light shaders are just pass-through shaders that make the cube look pure white.
const char * light_vert_src = ""
#include "Light.vert.glsl"
;

const char * light_frag_src = ""
#include "Light.frag.glsl"
;

namespace shaders {
    using namespace gl;
    class failed_shader_compilation_exception : public std::runtime_error {
        std::string error_log;
    public:
        failed_shader_compilation_exception(std::string const& why, std::string const& err) :
            std::runtime_error(why),
            error_log(err) {}
        std::string get_log() const {
            return error_log;
        }
    };

    void handle_shader_error(GLuint shader, std::string const& type, bool is_shader = true) {
        int log_length;
        if (is_shader)
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
        else
            glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &log_length);
        std::string errlog;
        errlog.resize(log_length);
        if (is_shader)
            glGetShaderInfoLog(shader, log_length, nullptr, &errlog[0]);
        else
            glGetProgramInfoLog(shader, log_length, nullptr, &errlog[0]);
        if (is_shader)
            glDeleteShader(shader);
        else
            glDeleteProgram(shader);
        throw failed_shader_compilation_exception("The " + type + " failed to Compile", errlog);
    }

    GLuint get_program(const char * vsrc, const char * fsrc) {
        GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
        int ret;

        glShaderSource(vertex_shader, 1, &vsrc, nullptr);
        glCompileShader(vertex_shader);
        glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret);
        if (!ret) {
            handle_shader_error(vertex_shader, "Vertex Shader");
        }

        GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);

        glShaderSource(fragment_shader, 1, &fsrc, nullptr);
        glCompileShader(fragment_shader);
        glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret);
        if (!ret) {
            glDeleteShader(vertex_shader);
            handle_shader_error(fragment_shader, "Fragment Shader");
        }

        GLuint program = glCreateProgram();
        glAttachShader(program, vertex_shader);
        glAttachShader(program, fragment_shader);
        glLinkProgram(program);
        glDeleteShader(vertex_shader);
        glDeleteShader(fragment_shader);

        glGetProgramiv(program, GL_LINK_STATUS, &ret);
        if (!ret) {
            handle_shader_error(program, "Program", false);
        }
        return program;
    }
}

Main.cpp:

#define GLFW_INCLUDE_NONE
#include<GLFW\glfw3.h>

#pragma warning( push )
#pragma warning( once : 4251)
#include<glbinding\gl43core\gl.h>
#include<glbinding\Binding.h>
#pragma warning( pop ) 

#include<iostream>

#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<glm/gtc/type_ptr.hpp>

#include "Shaders.h"

float vertex_data[] {
    0, 0, 0,    1, 0, 0,    0, 0, 1,
    1, 0, 0,    1, 0, 0,    0, 0, 1,
    1, 1, 0,    1, 0, 0,    0, 0, 1,
    0, 0, 0,    1, 0, 0,    0, 0, 1,
    1, 1, 0,    1, 0, 0,    0, 0, 1,
    0, 1, 0,    1, 0, 0,    0, 0, 1,

    1, 0, 0,    0, 1, 0,    1, 0, 0,
    1, 0, -1,   0, 1, 0,    1, 0, 0,
    1, 1, -1,   0, 1, 0,    1, 0, 0,
    1, 0, 0,    0, 1, 0,    1, 0, 0,
    1, 1, -1,   0, 1, 0,    1, 0, 0,
    1, 1, 0,    0, 1, 0,    1, 0, 0,

    1, 0, -1,   0, 1, 1,    0, 0, -1,
    0, 0, -1,   0, 1, 1,    0, 0, -1,
    0, 1, -1,   0, 1, 1,    0, 0, -1,
    1, 0, -1,   0, 1, 1,    0, 0, -1,
    0, 1, -1,   0, 1, 1,    0, 0, -1,
    1, 1, -1,   0, 1, 1,    0, 0, -1,

    0, 0, -1,   1, 0, 1,    -1, 0, 0,
    0, 0, 0,    1, 0, 1,    -1, 0, 0,
    0, 1, 0,    1, 0, 1,    -1, 0, 0,
    0, 0, -1,   1, 0, 1,    -1, 0, 0,
    0, 1, 0,    1, 0, 1,    -1, 0, 0,
    0, 1, -1,   1, 0, 1,    -1, 0, 0,

    0, 1, 0,    0, 0, 1,    0, 1, 0,
    1, 1, 0,    0, 0, 1,    0, 1, 0,
    1, 1, -1,   0, 0, 1,    0, 1, 0,
    0, 1, 0,    0, 0, 1,    0, 1, 0,
    1, 1, -1,   0, 0, 1,    0, 1, 0,
    0, 1, -1,   0, 0, 1,    0, 1, 0,

    0, 0, 0,    1, 1, 0,    0, -1, 0,
    0, 0, -1,   1, 1, 0,    0, -1, 0,
    1, 0, -1,   1, 1, 0,    0, -1, 0,
    0, 0, 0,    1, 1, 0,    0, -1, 0,
    1, 0, -1,   1, 1, 0,    0, -1, 0,
    1, 0, 0,    1, 1, 0,    0, -1, 0,
};

float light_cube_data[]{
    0, 0, 0,    1, 0, 0,    1, 1, 0,
    0, 0, 0,    1, 1, 0,    0, 1, 0,

    1, 0, 0,    1, 0, -1,   1, 1, -1,
    1, 0, 0,    1, 1, -1,   1, 1, 0,

    1, 0, -1,   0, 0, -1,   0, 1, -1,
    1, 0, -1,   0, 1, -1,   1, 1, -1,

    0, 0, -1,   0, 0, 0,    0, 1, 0,
    0, 0, -1,   0, 1, 0,    0, 1, -1,

    0, 1, 0,    1, 1, 0,    1, 1, -1,
    0, 1, 0,    1, 1, -1,   0, 1, -1,

    0, 0, 0,    0, 0, -1,   1, 0, -1,
    0, 0, 0,    1, 0, -1,   1, 0, 0,
};

int main() {
    glfwInit();
    GLFWwindow * window = glfwCreateWindow(300, 300, "bluh", nullptr, nullptr);
    glfwMakeContextCurrent(window);
    glbinding::Binding::initialize();
    using namespace gl43core;
    GLuint program = 0, light_program = 0;
    try {
        program = shaders::get_program(vert_src, frag_src);
        light_program = shaders::get_program(light_vert_src, light_frag_src);
    }
    catch (shaders::failed_shader_compilation_exception const& e) {
        std::cerr << e.what() << std::endl;
        std::cerr << e.get_log() << std::endl;
        system("pause");
        return 1;
    }
    glUseProgram(program);
    GLuint vao, vbo;
    GLuint light_vao, light_vbo;

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(0, 3, GL_FLOAT, false, 9 * sizeof(GLfloat), (void*)0);
    glVertexAttribPointer(1, 3, GL_FLOAT, false, 9 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glVertexAttribPointer(2, 3, GL_FLOAT, false, 9 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));

    glGenVertexArrays(1, &light_vao);
    glBindVertexArray(light_vao);
    glGenBuffers(1, &light_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, light_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(light_cube_data), light_cube_data, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * sizeof(GLfloat), (void*)0);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    glm::mat4 view = glm::lookAt(glm::vec3(2, 3, 3), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
    struct manip_data {
        glm::quat view_quat;
        glm::vec3 view_position;
        glm::vec4 light_position{ 3, 0, 3, 1 };
        glm::vec4 light_color{ 1, 1, 1, 1 };
        double prior_time;
        double current_time;
    };

    manip_data data;
    data.view_quat = glm::quat(view);
    data.view_position = glm::vec3(glm::inverse(view)[3]);
    data.prior_time = data.current_time = glfwGetTime();

    glfwSetWindowUserPointer(window, &data);
    glfwSetKeyCallback(window, [](GLFWwindow * window, int key, int code, int action, int modifier) {
        manip_data & data = *(reinterpret_cast<manip_data *>(glfwGetWindowUserPointer(window)));
        data.current_time = glfwGetTime();
        double dt = data.current_time - data.prior_time;
        if (action == GLFW_PRESS || action == GLFW_REPEAT) {
            switch (key) {
            case GLFW_KEY_W: data.view_position += glm::inverse(data.view_quat) * glm::vec3(0, 0, -1) * float(dt) * 50.f; break;
            case GLFW_KEY_S: data.view_position += glm::inverse(data.view_quat) * glm::vec3(0, 0, 1) * float(dt) * 50.f; break;
            case GLFW_KEY_A: data.view_position += glm::inverse(data.view_quat) * glm::vec3(-1, 0, 0) * float(dt) * 50.f; break;
            case GLFW_KEY_D: data.view_position += glm::inverse(data.view_quat) * glm::vec3(1, 0, 0) * float(dt) * 50.f; break;
            case GLFW_KEY_LEFT_SHIFT: data.view_position += glm::inverse(data.view_quat) * glm::vec3(0, 1, 0) * float(dt) * 50.f; break;
            case GLFW_KEY_LEFT_CONTROL: data.view_position += glm::inverse(data.view_quat) * glm::vec3(0, -1, 0) * float(dt) * 50.f; break;

            case GLFW_KEY_KP_8: data.view_quat = glm::angleAxis(-float(dt) * 50, glm::vec3(1, 0, 0)) * data.view_quat; break;
            case GLFW_KEY_KP_2: data.view_quat = glm::angleAxis(float(dt) * 50, glm::vec3(1, 0, 0)) * data.view_quat; break;
            case GLFW_KEY_KP_4: data.view_quat = glm::angleAxis(-float(dt) * 50, glm::vec3(0, 1, 0)) * data.view_quat; break;
            case GLFW_KEY_KP_6: data.view_quat = glm::angleAxis(float(dt) * 50, glm::vec3(0, 1, 0)) * data.view_quat; break;
            case GLFW_KEY_KP_9: data.view_quat = glm::angleAxis(-float(dt) * 50, glm::vec3(0, 0, -1)) * data.view_quat; break;
            case GLFW_KEY_KP_7: data.view_quat = glm::angleAxis(float(dt) * 50, glm::vec3(0, 0, -1)) * data.view_quat; break;
            }
        }
        data.prior_time = data.current_time;
    });

    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
        data.prior_time = glfwGetTime();
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glm::mat4 projection = glm::perspective(glm::radians(60.f), float(width) / height, 0.1f, 100.f);
        glm::mat4 model;
        glm::mat4 normal_model;

        view = glm::translate(glm::mat4_cast(data.view_quat), -data.view_position);
        glm::vec4 eye = glm::inverse(view)[3];
        glm::vec4 light_position{ 1.25, 0.5, 1.25, 1 };

        glUseProgram(program);
        glBindVertexArray(vao);
        glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, false, glm::value_ptr(projection));
        glUniformMatrix4fv(glGetUniformLocation(program, "view"), 1, false, glm::value_ptr(view));
        glUniformMatrix4fv(glGetUniformLocation(program, "model_position"), 1, false, glm::value_ptr(model));
        glUniformMatrix4fv(glGetUniformLocation(program, "model_normal"), 1, false, glm::value_ptr(normal_model));
        glUniform4fv(glGetUniformLocation(program, "eye"), 1, glm::value_ptr(eye));
        glUniform4fv(glGetUniformLocation(program, "light_position"), 1, glm::value_ptr(light_position));

        glDrawArrays(GL_TRIANGLES, 0, sizeof(vertex_data) / sizeof(GLfloat) / 9);

        model = glm::translate(model, glm::vec3(light_position));
        model = glm::scale(model, glm::vec3(0.25, 0.25, 0.25));

        glUseProgram(light_program);
        glBindVertexArray(light_vao);

        glUniformMatrix4fv(glGetUniformLocation(light_program, "projection"), 1, false, glm::value_ptr(projection));
        glUniformMatrix4fv(glGetUniformLocation(light_program, "view"), 1, false, glm::value_ptr(view));
        glUniformMatrix4fv(glGetUniformLocation(light_program, "model_position"), 1, false, glm::value_ptr(model));

        glDrawArrays(GL_TRIANGLES, 0, sizeof(light_cube_data) / sizeof(GLfloat) / 3);

        glfwSwapBuffers(window);
    }

    return 0;
}

This is a picture of the default rendering position, with some annotations I added to identify how I know the lighting is wrong.

Picture of Incorrect Lighting

I'm using GLFW and glbinding for my OpenGL API access, but GLEW has virtually identical code if you use it instead of glbinding. I'm also using GLM for math functions.

Community
  • 1
  • 1
Xirema
  • 18,577
  • 4
  • 26
  • 60

1 Answers1

3

You are re-using the vertex colors as the normals, and never use the actual normals in your array:

glVertexAttribPointer(1, 3, GL_FLOAT, false, 9 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
glVertexAttribPointer(2, 3, GL_FLOAT, false, 9 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
derhass
  • 38,787
  • 2
  • 42
  • 61
  • *Sigh*. Yeah, I knew it had to be something stupid like that. If only I hadn't assumed the Fragment Shader was the problem. Anyways, thanks. That's a good catch. – Xirema Jan 19 '17 at 22:18