OpenGL:光照模型视图投影变换

Posted unclerunning

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL:光照模型视图投影变换相关的知识,希望对你有一定的参考价值。

OpenGL:光照、模型视图投影变换

数学基础

矩阵与线性变换

坐标系变换

深入探索透视投影变换

OpenGL Normal Vector Transformation

程序

太阳系,为简化内容,所以使用正方体代替球体,模拟太阳系中的太阳,地球和月亮。主要目的是展示OpenGL中用到的几个坐标系变换以及光照处理。

库配置

Creating a window

GLM

程序图示





代码

#include <iostream>
#include <cmath>

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>

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

// Other includes
#include "shaderwrapper.h"

// Function prototypes
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
static void init();
static void initBuffer();

// Window dimensions
static const GLuint WIDTH = 800, HEIGHT = 600;
static GLFWwindow* window;

static GLuint VBO, VAO;


// The MAIN function, from here we start the application and run the game loop
int main()

    init();
    initBuffer();

    //light position in world space
    glm::vec3 lightPos(8.0f,8.0f,8.0f);

    //eye position in world space
    glm::vec3 eyePos(-12.0f, 12.0f, 12.0f);

    //local positions
    glm::vec3 cubePositions[] = 
        glm::vec3(8.0f,0.0f,0.0f),
        glm::vec3(3.0f,0.0f,0.0f)
    ;

    //sun
    GLfloat Sun_angle = 0.0f;
    GLfloat Sun_angle_step = 1.0f;
    glm::vec3 Sun_color(1.0f,0.0f,0.0f);
    //earth
    GLfloat Earth_self_angle = 0.0f;
    GLfloat Earth_angle_step = 1.0f;
    GLfloat Earth_sun_angle = 0.0f;
    GLfloat Earth_sun_step = 2.0f;
    glm::vec3 Earth_color(0.0f, 1.0f, 0.0f);
    //moon
    GLfloat Moon_self_angle = 0.0f;
    GLfloat Moon_angle_step = 2.0f;
    GLfloat Moon_earth_angle = 0.0f;
    GLfloat Moon_earth_step = 3.0f;
    glm::vec3 Moon_color(1.0f, 1.0f, 1.0f);

    // Build and compile our shader program
    Shader ourShader("shaders/mvp_test.vs", "shaders/mvp_test.frag");
    //get locations of uniform variables 
    GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
    GLint projLoc = glGetUniformLocation(ourShader.Program, "projection");
    GLint lightPosLoc = glGetUniformLocation(ourShader.Program, "lightPos");
    GLint colorLoc = glGetUniformLocation(ourShader.Program, "objectColor");
    GLint viewPosLoc = glGetUniformLocation(ourShader.Program, "viewPos");

    // Camera/View transformation
    glm::mat4 view;
    view = glm::lookAt(eyePos, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    // Projection 
    glm::mat4 projection;
    projection = glm::perspective(45.0f, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);

    // Activate shader
    ourShader.Use();
    // Pass the matrices to the shader
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
    glUniform3f(lightPosLoc, lightPos.x, lightPos.y, lightPos.z);
    glUniform3fv(viewPosLoc, 1, glm::value_ptr(eyePos));

    // loop
    GLfloat startTime = glfwGetTime();
    while (!glfwWindowShouldClose(window))
    
        glfwPollEvents();

        // Render
        // Clear the color buffer and depth buffer
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Calculate delta time of current frame
        GLfloat deltaTime = glfwGetTime() - startTime;
        //sun
        Sun_angle = Sun_angle_step * deltaTime;
        //earth
        Earth_self_angle = Earth_angle_step * deltaTime;
        Earth_sun_angle = Earth_sun_step*deltaTime;
        //moon
        Moon_self_angle = Moon_angle_step * deltaTime;
        Moon_earth_angle = Moon_earth_step * deltaTime;

        // Get the uniform locations
        GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
        GLint normalTransformLoc = glGetUniformLocation(ourShader.Program, "normalTransform");


        glBindVertexArray(VAO);

            //### sun ###
            glm::mat4 sun_model;
            sun_model = glm::scale(sun_model,glm::vec3(1.6f,1.6f,1.6f)); //放大坐标系
            sun_model = glm::rotate(sun_model, Sun_angle, glm::vec3(0.0f, 1.0f, 0.0f)); //绕坐标系y轴旋转
            glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(sun_model));
            //normal transform
            glm::mat4 sun_normalTransform;
            sun_normalTransform = glm::inverse(sun_model);
            sun_normalTransform = glm::transpose(sun_normalTransform);
            glUniformMatrix4fv(normalTransformLoc, 1, GL_FALSE, glm::value_ptr(sun_normalTransform));   
            glUniform3fv(colorLoc, 1, glm::value_ptr(Sun_color));
            glDrawArrays(GL_TRIANGLES, 0, 36);

            //### earth ###
            glm::mat4 earth_model;
            //绕y轴旋转坐标系W得到新坐标系W1
            earth_model = glm::rotate(earth_model, Earth_sun_angle, glm::vec3(0.0f, 1.0f, 0.0f));
            //平移坐标系W1得到新坐标系W2
            earth_model = glm::translate(earth_model, cubePositions[0]);
            //绕y轴旋转坐标系W2得到新坐标系W3                
            earth_model = glm::rotate(earth_model, Earth_self_angle, glm::vec3(0.0f, 1.0f, 0.0f));
            glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(earth_model));
            //normal transform
            glm::mat4 earth_normalTransform;
            earth_normalTransform = glm::inverse(earth_model);
            earth_normalTransform = glm::transpose(earth_normalTransform);
            glUniformMatrix4fv(normalTransformLoc, 1, GL_FALSE, glm::value_ptr(earth_normalTransform));
            glUniform3fv(colorLoc, 1, glm::value_ptr(Earth_color));
            glDrawArrays(GL_TRIANGLES, 0, 36);

            //### moon ###
            glm::mat4 moon_model;
            //start from earth's coordinate
            moon_model = earth_model;
            moon_model = glm::scale(moon_model, glm::vec3(0.5f, 0.5f, 0.5f));
            moon_model = glm::rotate(moon_model, Moon_earth_angle, glm::vec3(0.0f, 1.0f, 0.0f));
            moon_model = glm::translate(moon_model, cubePositions[1]);
            moon_model = glm::rotate(moon_model, Moon_self_angle, glm::vec3(0.0f, 1.0f, 0.0f));
            glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(moon_model));
            //normal transform
            glm::mat4 moon_normalTransform;
            moon_normalTransform = glm::inverse(moon_model);
            moon_normalTransform = glm::transpose(moon_normalTransform);
            glUniformMatrix4fv(normalTransformLoc, 1, GL_FALSE, glm::value_ptr(moon_normalTransform));
            glUniform3fv(colorLoc, 1, glm::value_ptr(Moon_color));
            glDrawArrays(GL_TRIANGLES, 0, 36);

        glBindVertexArray(0);

        // Swap the screen buffers
        glfwSwapBuffers(window);
    
    // Properly de-allocate all resources once they've outlived their purpose
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    // Terminate GLFW, clearing any resources allocated by GLFW.
    glfwTerminate();
    return 0;





// Is called whenever a key is pressed/released via GLFW
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)

    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);



static void init()

    // Init GLFW
    glfwInit();
    // Set all the required options for GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    // Create a GLFWwindow object that we can use for GLFW's functions
    window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
    glfwMakeContextCurrent(window);

    // Set the required callback functions
    glfwSetKeyCallback(window, key_callback);

    // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
    glewExperimental = GL_TRUE;
    // Initialize GLEW to setup the OpenGL Function pointers
    glewInit();

    // Define the viewport dimensions
    glViewport(0, 0, WIDTH, HEIGHT);

    glEnable(GL_DEPTH_TEST);




static void initBuffer()

    // Set up vertex data (and buffer(s)) and attribute pointers
    GLfloat vertices[] = 
        -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
    ;

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // Position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    // Normal attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(0); // Unbind VAO

shaderwrapper.h:

#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

#include <GL/glew.h>

class Shader

public:
    GLuint Program;
    // Constructor generates the shader on the fly
    Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
    
        // 1. Retrieve the vertex/fragment source code from filePath
        std::string vertexCode;
        std::string fragmentCode;
        std::ifstream vShaderFile;
        std::ifstream fShaderFile;
        // ensures ifstream objects can throw exceptions:
        vShaderFile.exceptions(std::ifstream::badbit);
        fShaderFile.exceptions(std::ifstream::badbit);
        try
        
            // Open files
            vShaderFile.open(vertexPath);
            fShaderFile.open(fragmentPath);
            std::stringstream vShaderStream, fShaderStream;
            // Read file's buffer contents into streams
            vShaderStream << vShaderFile.rdbuf();
            fShaderStream << fShaderFile.rdbuf();
            // close file handlers
            vShaderFile.close();
            fShaderFile.close();
            // Convert stream into string
            vertexCode = vShaderStream.str();
            fragmentCode = fShaderStream.str();
        
        catch (std::ifstream::failure e)
        
            std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
        
        const GLchar* vShaderCode = vertexCode.c_str();
        const GLchar * fShaderCode = fragmentCode.c_str();
        // 2. Compile shaders
        GLuint vertex, fragment;
        GLint success;
        GLchar infoLog[512];
        // Vertex Shader
        vertex = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex, 1, &vShaderCode, NULL);
        glCompileShader(vertex);
        // Print compile errors if any
        glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
        if (!success)
        
            glGetShaderInfoLog(vertex, 512, NULL, infoLog);
            std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\\n" << infoLog << std::endl;
        
        // Fragment Shader
        fragment = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment, 1, &fShaderCode, NULL);
        glCompileShader(fragment);
        // Print compile errors if any
        glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
        if (!success)
        
            glGetShaderInfoLog(fragment, 512, NULL, infoLog);
            std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\\n" << infoLog << std::endl;
        
        // Shader Program
        this->Program = glCreateProgram();
        glAttachShader(this->Program, vertex);
        glAttachShader(this->Program, fragment);
        glLinkProgram(this->Program);
        // Print linking errors if any
        glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
        if (!success)
        
            glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
            std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\\n" << infoLog << std::endl;
        
        // Delete the shaders as they're linked into our program now and no longer necessery
        glDeleteShader(vertex);
        glDeleteShader(fragment);

    
    // Uses the current shader
    void Use()
    
        glUseProgram(this->Program);
    
;

#endif

vertex shader(mvp_test.vs):

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;

out vec3 Normal;
out vec3 FragPos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 normalTransform;


void main()

    gl_Position = projection * view * model * vec4(position, 1.0f);
    Normal = vec3(normalTransform*vec4(normal,1.0f));    
    FragPos = vec3(model * vec4(position, 1.0f));

fragment shader(mvp_test.frag):

#version 330 core
in vec3 Normal; 
in vec3 FragPos;  

out vec4 color;

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

void main()

    vec3 lightColor = vec3(1.0f,1.0f,1.0f);
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);  

    // ambient component
    float ambientStrength = 0.28f;
    vec3 ambient = ambientStrength * lightColor;

    // diffuse component
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

    // specular component
    float specularStrength = 0.5f;
    int shininess = 256;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm); 
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), shininess);
    vec3 specular = specularStrength * spec * lightColor; 

    // together
    vec3 result = (ambient + diffuse + specular) * objectColor;


    color = vec4(result, 1.0f);

references:

Basic Lighting
深入探索透视投影变换
OpenGL Projection Matrix
OpenGL Normal Vector Transformation

以上是关于OpenGL:光照模型视图投影变换的主要内容,如果未能解决你的问题,请参考以下文章

最简单光照模型中的光照方向及其变换

OpenGL的视图变换模型变换投影变换视口变换

WebGL或OpenGL关于模型视图投影变换的设置技巧

带有立方体贴图的 OpenGL 点光阴影映射

OPENGL若干重要基础概念

详解OpenGL的坐标系投影和几何变换