1

最近,我一直在尝试使用本网站中描述的 Blinn-Phong 着色模型为简单的 OpenGL 场景添加光照。

我试图尽可能地遵循本教程。然而,灯光似乎关闭了,尤其是在立方体的侧面,因为光源开始在前面移动。

我相信这与由于模型矩阵上的旋转或在照明着色器中做错了什么而导致法线的位置不在正确位置有关,但是,我不确定其中是否真的是原因。

顺便说一下,这里是源代码:

#include <glad/glad.h>

#include <SFML/Graphics.hpp>

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

#include <iostream>
#include <cstdlib>
#include <cmath>

// Vertex shader for the light source cube
const std::string source_vert_shader = R"(
    #version 330 core

    layout (location = 0) in vec3 vertPos;

    uniform mat4 proj, view, model;

    void main() {
        gl_Position = proj * view * model * vec4(vertPos, 1);
    }
)";

// Fragment shader for the light source cube
const std::string source_frag_shader = R"(
    #version 330 core

    out vec4 FragColor;

    void main() {
        FragColor = vec4(1);
    }
)";

// Vertex shader for the cube
const std::string cube_vert_shader = R"(
    #version 330 core

    layout (location = 0) in vec3 vertPos;
    layout (location = 1) in vec3 vertNorm;

    uniform mat4 proj, view, model;

    out vec3 fragPos;
    out vec3 interNorm;

    void main() {
        fragPos = vec3(model * vec4(vertPos, 1));
        gl_Position = proj * view * vec4(fragPos, 1);
        interNorm = mat3(transpose(inverse(model))) * vertNorm;
    }
)";

// Fragment shader for the cube
const std::string cube_frag_shader = R"(
    #version 330 core

    in vec3 fragPos;
    in vec3 interNorm;

    out vec4 FragColor;

    uniform vec3 viewPos;
    uniform vec3 lightPos;
    uniform vec3 objectColor;

    const float pi = 3.14159265;
    const float shininess = 16;

    void main() {
        vec3 normal = normalize(interNorm);
        vec3 lightDir = normalize(lightPos - fragPos);
        float dist = length(lightPos - fragPos);
        float attenuation = 1 / (dist * dist);

        // Ambient light effect
        const float ambientStrength = 0.05;
        vec3 ambient = ambientStrength * objectColor;

        // Diffuse light effect
        float diff = max(dot(normal, lightDir), 0);
        vec3 diffuse = attenuation * diff * objectColor;

        // Specular light effect
        vec3 specular = vec3(0);
        if (diff != 0) {
            const float energy_conservation = (8 + shininess) / (8 * pi);
            vec3 viewDir = normalize(viewPos - fragPos);
            vec3 halfwayDir = normalize(lightDir + viewDir);
            float spec = energy_conservation * pow(max(dot(normal, halfwayDir), 0), shininess);
            specular = attenuation * spec * vec3(0.3);
        }

        const float gamma = 2.2;

        // Apply the different lighting techniques of the Phong shading model and finally apply gamma correction
        FragColor = vec4(pow(ambient + diffuse + specular, vec3(1 / gamma)), 1);
    }
)";

int main() {
    // Initialize the window
    sf::RenderWindow window(
        sf::VideoMode(1365, 768), "Lighting", sf::Style::Default,
        sf::ContextSettings(24, 8, 4, 3, 3, sf::ContextSettings::Core, true));

    // Initialize OpenGL functions
    gladLoadGLLoader(reinterpret_cast<GLADloadproc>(sf::Context::getFunction));

    // Specify the viewport of the scene
    glViewport(0, 0, window.getSize().x, window.getSize().y);

    // Enable depth testing
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    // Enable blending
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // Load the shaders into the application
    sf::Shader shader, source_shader;
    (void)shader.loadFromMemory(cube_vert_shader, cube_frag_shader);
    (void)source_shader.loadFromMemory(source_vert_shader, source_frag_shader);

    // Define the vertices of the cube and the light source cube
    float vertices[] = {
        // Vertices           Normals
        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
         0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f, 
         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f, 
         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f, 
        -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f, 
        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f, 

        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,

        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,

         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
         0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
         0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,

        -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
         0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,

        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
         0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f
    };

    // Attach the vertices in the vertices array to the VAO and the VBO
    GLuint vao, vbo;

    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);

    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), nullptr);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast<void*>(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    // The same VBO can be used to render the light source cube
    GLuint source_vao;

    glGenVertexArrays(1, &source_vao);
    glBindVertexArray(source_vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), nullptr);
    glEnableVertexAttribArray(0);

    // Projection matrix
    auto proj = glm::perspective(glm::radians(45.0f), static_cast<GLfloat>(window.getSize().x) / window.getSize().y, 0.1f, 100.0f);

    glm::vec3 view_pos(0.0f, 0.0f, -5.0f);

    // View/camera matrix
    glm::mat4 view(1.0f);
    view = glm::translate(view, view_pos);
    view = glm::rotate(view, glm::radians(45.0f), glm::vec3(1.0f, 1.0f, 1.0f));

    // Model matrix
    glm::mat4 model(1.0f);
    //model = glm::rotate(model, glm::radians(45.0f), glm::vec3(1.0f, 1.0f, 0.0f));

    // For the cube in the center
    shader.setUniform("proj", sf::Glsl::Mat4(glm::value_ptr(proj)));
    shader.setUniform("view", sf::Glsl::Mat4(glm::value_ptr(view)));
    shader.setUniform("model", sf::Glsl::Mat4(glm::value_ptr(model)));
    shader.setUniform("viewPos", sf::Glsl::Vec3(view_pos.x, view_pos.y, view_pos.z));
    shader.setUniform("objectColor", sf::Glsl::Vec3(1.0f, 0.3f, 1.0f));

    // For the light source cube
    source_shader.setUniform("proj", sf::Glsl::Mat4(glm::value_ptr(proj)));
    source_shader.setUniform("view", sf::Glsl::Mat4(glm::value_ptr(view)));

    sf::Clock clock;
    sf::Event evt{};
    while (window.isOpen()) {
        while (window.pollEvent(evt)) {
            if (evt.type == sf::Event::Closed) {
                // When window is closed, destroy the VAO and the VBO
                glDeleteBuffers(1, &vbo);
                glDeleteVertexArrays(1, &vao);
                window.close();
            }
            if (evt.type == sf::Event::Resized)
                // Update the viewport as the window is resized
                glViewport(0, 0, evt.size.width, evt.size.height);
        }
        // Clear the screen with a color
        glClearColor(0.8f, 0.2f, 0.6f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Calculate an angular factor based on the elapsed time
        auto const angular_factor = glm::radians(45.0f) * clock.getElapsedTime().asSeconds();

        sf::Shader::bind(&shader);
        // Makes the light source move in circles around the cube in the center
        glm::vec3 light_pos(
            6.0f * std::sin(angular_factor),
            0.0f,
            6.0f * std::cos(angular_factor)
        );
        shader.setUniform("lightPos", sf::Glsl::Vec3(light_pos.x, light_pos.y, light_pos.z));
        // Draw the cube
        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        sf::Shader::bind(&source_shader);
        model = glm::identity<glm::mat4>();
        model = glm::scale(model, glm::vec3(0.3f, 0.3f, 0.3f));
        model = glm::translate(model, light_pos);
        source_shader.setUniform("model", sf::Glsl::Mat4(glm::value_ptr(model)));
        // Draw the light source cube
        glBindVertexArray(source_vao);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        sf::Shader::bind(nullptr);

        // Swap the window's buffers
        window.display();
    }
}
4

0 回答 0