01 OpenGL 入门

OpenGL 参考资料:

https://learnopengl.com/  原版

https://learnopengl-cn.github.io/  中文版

https://www.bilibili.com/video/BV11W411N7b9?from=search&seid=8920882218134207707(傅老师视频 ,目前 共有三部分)

https://www.icourse163.org/course/HUST-1003636001   大学mooc 课程

三个名词:

计算机图形学,opengl   输入:结构化数据(y = ax +b )  输出:显示器上显示的图像信号

计算机视觉, opencv  输入:显示器上显示的图像信号   输出:结构化数据(y = ax +b )

数字图像处理,ps   输入:显示器上显示的图像信号    输出: 显示器上显示的图像信号   

OpenGL 配置:

GLAD,GLFW + CLion 编辑器:(个人觉得 jetbrains 的产品比vs 好用 )

参考文章:https://www.pianshen.com/article/17731169605/

注:glad 网站很容易访问,glfw 网站下载很慢,可以使用下面的现成文件:

https://files.cnblogs.com/files/zach0812/glad_and_glfw_win64.zip

测试代码:

#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

using namespace std;

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);


    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        glfwTerminate();
        return -1;
    }

    glViewport(0, 0, 800, 600);

    while (!glfwWindowShouldClose(window)) {

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);


        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
main.cpp

如果都没问题了,测试效果如下:

Hello Triangle:

#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

using namespace std;

float vertices[] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f, 0.5f, 0.0f
};

const char *vertexShaderSrc = "#version 330 core                                           
"
                              "layout (location = 0) in vec3 aPos;                         
"
                              "void main(){                                                
"
                              "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);}       
";

const char *fragmentShaderSrc = "#version 330 core
"
                                "out vec4 FragColor;
"
                                "void main(){
"
                                "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);} 
";

void porcessInput(GLFWwindow *window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }
}

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);


    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        glfwTerminate();
        return -1;
    }

    glViewport(0, 0, 800, 600);
    // VAO vertex array obj
    // VBO vertex buffer obj
    // EBO ele buffer obj

    // gpu 中生成一个 VAO
    unsigned int VAO;
    glGenVertexArrays(1, &VAO); // 产生一个 VAO,返回的是 VAO 的 id
    glBindVertexArray(VAO);

    // 把cpu输入的VBO 绑定到 上面的VAO
    unsigned int VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


    // 生成一个vertex shader
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL); // 一个字符串 加载源码
    glCompileShader(vertexShader);


    // 生称一个fragment shader
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL);
    glCompileShader(fragmentShader);


    // 造一个program
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader); // 将 vertex shader 贴到 program
    glAttachShader(shaderProgram, fragmentShader); // 将 fragment shader 贴到 program
    glLinkProgram(shaderProgram);


    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);


    while (!glfwWindowShouldClose(window)) {
        porcessInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shaderProgram);
        glDrawArrays(GL_TRIANGLES,0,3);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
main.cpp
#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

// 几何阶段 和  光栅化阶段 !!!
// vertex shader  &   fragment shader

using namespace std;

//绘制四边形
// 方法一: VBO + VAO

// 顶点数据
float vertices[] = {
        // 第一个三角形
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f, 0.5f, 0.0f,
        // 第二个三角形
        0.5f, -0.5f, 0.0f,
        0.0f, 0.5f, 0.0f,
        0.5f, 0.5f, 0.0f,
};

const char *vertexShaderSrc = "#version 330 core                                           
"
                              "layout (location = 0) in vec3 aPos;                         
"
                              "void main(){                                                
"
                              "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);}       
";

const char *fragmentShaderSrc = "#version 330 core
"
                                "out vec4 FragColor;
"
                                "void main(){
"
                                "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);} 
";

void porcessInput(GLFWwindow *window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }
}

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);


    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        glfwTerminate();
        return -1;
    }

    glViewport(0, 0, 800, 600);

    // opengl 默认绘制 逆时针 点 为正面, 下面开启 背面剔除 这样就不会绘制 顺时针的点
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);



    //  生成立方体的 VBO  和 VAO
    unsigned int VBO, VAO;
    glGenBuffers(1, &VBO);
    glGenVertexArrays(1, &VAO);

    // 绑定VBO 并传入顶点数据
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 绑定VAO
    glBindVertexArray(VAO);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);



    //===================================
    // 生成一个vertex shader
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL); // 一个字符串 加载源码
    glCompileShader(vertexShader);

    // 生称一个fragment shader
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL);
    glCompileShader(fragmentShader);

    // 造一个program
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader); // 将 vertex shader 贴到 program
    glAttachShader(shaderProgram, fragmentShader); // 将 fragment shader 贴到 program
    glLinkProgram(shaderProgram);


    while (!glfwWindowShouldClose(window)) {
        porcessInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shaderProgram);
        glDrawArrays(GL_TRIANGLES, 0, 6);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
main.cpp (剔除 背面)

关于 VBO  vAO  EBO :

VBO + VAO 绘制 四边形:

#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

// 几何阶段 和  光栅化阶段 !!!
// vertex shader  &   fragment shader

using namespace std;

//绘制四边形
// 方法一: VBO + VAO

// 顶点数据
float vertices[] = {
        // 第一个三角形
        0.5f, 0.5f, 0.0f, // 右上
        0.5f, -0.5f, 0.0f, // 右下
        -0.5f, -0.5f, 0.0f, // 左下
        // 第二个三角形
        0.5f, 0.5f, 0.0f, // 右上
        -0.5f, -0.5f, 0.0f, // 左下
        -0.5f, 0.5f, 0.0f // 左上

};

const char *vertexShaderSrc = "#version 330 core                                           
"
                              "layout (location = 0) in vec3 aPos;                         
"
                              "void main(){                                                
"
                              "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);}       
";

const char *fragmentShaderSrc = "#version 330 core
"
                                "out vec4 FragColor;
"
                                "void main(){
"
                                "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);} 
";

void porcessInput(GLFWwindow *window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }
}

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);


    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        glfwTerminate();
        return -1;
    }

    glViewport(0, 0, 800, 600);

    //  生成立方体的 VBO  和 VAO
    unsigned int VBO,VAO;
    glGenBuffers(1,&VBO);
    glGenVertexArrays(1,&VAO);

    // 绑定VBO 并传入顶点数据
    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices),vertices,GL_STATIC_DRAW);

    // 绑定VAO
    glBindVertexArray(VAO);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);



    //===================================
    // 生成一个vertex shader
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL); // 一个字符串 加载源码
    glCompileShader(vertexShader);

    // 生称一个fragment shader
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL);
    glCompileShader(fragmentShader);

    // 造一个program
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader); // 将 vertex shader 贴到 program
    glAttachShader(shaderProgram, fragmentShader); // 将 fragment shader 贴到 program
    glLinkProgram(shaderProgram);


    while (!glfwWindowShouldClose(window)) {
        porcessInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glBindVertexArray(VAO);
        glUseProgram(shaderProgram);
        glDrawArrays(GL_TRIANGLES, 0, 6);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
main.cpp

VBO + VAO + EBO(索引)绘制 四边形:

#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

// 几何阶段 和  光栅化阶段 !!!
// vertex shader  &   fragment shader

using namespace std;

//绘制四边形
// 方法二: VBO + VAO + EBO


// 顶点数据
float vertices[] = {
        0.5f, 0.5f, 0.0f, // 右上
        -0.5f, 0.5f, 0.0f, // 左上
        -0.5f, -0.5f, 0.0f, // 左下
        0.5f, -0.5f, 0.0f, // 右下
};
// 0 1 2       2 3 0
unsigned int indices[] ={
        0,1,2, // 第一个三角形
        2,3,0  // 第二个三角形
};




const char *vertexShaderSrc = "#version 330 core                                           
"
                              "layout (location = 0) in vec3 aPos;                         
"
                              "void main(){                                                
"
                              "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);}       
";

const char *fragmentShaderSrc = "#version 330 core
"
                                "out vec4 FragColor;
"
                                "void main(){
"
                                "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);} 
";

void porcessInput(GLFWwindow *window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }
}

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);


    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        glfwTerminate();
        return -1;
    }

    glViewport(0, 0, 800, 600);

    // 去除 背面 (逆时针为正面)
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);



    //  生成立方体的 VBO  和 VAO 和 EBO
    unsigned int VBO,VAO,EBO;
    glGenBuffers(1,&VBO);
    glGenBuffers(1,&EBO);
    glGenVertexArrays(1,&VAO);

    // 绑定VBO 并传入顶点数据
    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices),vertices,GL_STATIC_DRAW);

    // 绑定EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices),indices,GL_STATIC_DRAW);

    // 绑定VAO
    glBindVertexArray(VAO);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);



    //===================================
    // 生成一个vertex shader
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL); // 一个字符串 加载源码
    glCompileShader(vertexShader);

    // 生称一个fragment shader
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL);
    glCompileShader(fragmentShader);

    // 造一个program
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader); // 将 vertex shader 贴到 program
    glAttachShader(shaderProgram, fragmentShader); // 将 fragment shader 贴到 program
    glLinkProgram(shaderProgram);


    while (!glfwWindowShouldClose(window)) {
        porcessInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glBindVertexArray(VAO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
        glUseProgram(shaderProgram);
        glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
main.cpp

使用线框模式:

#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

// 几何阶段 和  光栅化阶段 !!!
// vertex shader  &   fragment shader

using namespace std;

//绘制四边形
// 方法一: VBO + VAO

// 顶点数据
float vertices[] = {
        // 第一个三角形
        0.5f, 0.5f, 0.0f, // 右上
        0.5f, -0.5f, 0.0f, // 右下
        -0.5f, -0.5f, 0.0f, // 左下
        // 第二个三角形
        0.5f, 0.5f, 0.0f, // 右上
        -0.5f, -0.5f, 0.0f, // 左下
        -0.5f, 0.5f, 0.0f // 左上

};

const char *vertexShaderSrc = "#version 330 core                                           
"
                              "layout (location = 0) in vec3 aPos;                         
"
                              "void main(){                                                
"
                              "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);}       
";

const char *fragmentShaderSrc = "#version 330 core
"
                                "out vec4 FragColor;
"
                                "void main(){
"
                                "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);} 
";

void porcessInput(GLFWwindow *window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }
}

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);


    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        glfwTerminate();
        return -1;
    }

    glViewport(0, 0, 800, 600);

    // 使用线框模式
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    //  生成立方体的 VBO  和 VAO
    unsigned int VBO,VAO;
    glGenBuffers(1,&VBO);
    glGenVertexArrays(1,&VAO);

    // 绑定VBO 并传入顶点数据
    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices),vertices,GL_STATIC_DRAW);

    // 绑定VAO
    glBindVertexArray(VAO);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);



    //===================================
    // 生成一个vertex shader
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL); // 一个字符串 加载源码
    glCompileShader(vertexShader);

    // 生称一个fragment shader
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL);
    glCompileShader(fragmentShader);

    // 造一个program
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader); // 将 vertex shader 贴到 program
    glAttachShader(shaderProgram, fragmentShader); // 将 fragment shader 贴到 program
    glLinkProgram(shaderProgram);


    while (!glfwWindowShouldClose(window)) {
        porcessInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glBindVertexArray(VAO);
        glUseProgram(shaderProgram);
        glDrawArrays(GL_TRIANGLES, 0, 6);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
View Code

Shader (着色器)

https://learnopengl-cn.github.io/01%20Getting%20started/05%20Shaders/

GLSL 

OpenGL使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。

注: vertex shader 一定要输出 gl_position , fragment shader 一定要输出FragColor,除了这些必备的之外,也可以携带其他的信息~

Uniform 

#include <iostream>
#include <cmath>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

// 几何阶段 和  光栅化阶段 !!!
// vertex shader  &   fragment shader

using namespace std;

//绘制四边形
// 方法二: VBO + VAO + EBO

// 顶点数据
float vertices[] = {
        0.5f, 0.5f, 0.0f, // 右上
        -0.5f, 0.5f, 0.0f, // 左上
        -0.5f, -0.5f, 0.0f, // 左下
        0.5f, -0.5f, 0.0f, // 右下
};
// 0 1 2       2 3 0
unsigned int indices[] ={
        0,1,2, // 第一个三角形
        2,3,0  // 第二个三角形
};

const char *vertexShaderSrc = "#version 330 core                                           
"
                              "layout (location = 0) in vec3 aPos;                         
"
                              "out vec4 vertexColor;  
"
                              "void main(){                                                
"
                              "    vertexColor =  vec4(1.0,0,0, 1.0);        
"
                              "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);}       
";

const char *fragmentShaderSrc = "#version 330 core
"
                                "in vec4 vertexColor;
"
                                "uniform vec4 ourColor;
" // 意思是从cpu 直接传递ourColor 变量到 fragmentShader~
                                "out vec4 FragColor;
"
                                "void main(){
"
                                "   FragColor = ourColor;} 
";

void porcessInput(GLFWwindow *window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }
}

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);


    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        glfwTerminate();
        return -1;
    }

    glViewport(0, 0, 800, 600);

    // 去除 背面 (逆时针为正面)
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);



    //  生成立方体的 VBO  和 VAO 和 EBO
    unsigned int VBO,VAO,EBO;
    glGenBuffers(1,&VBO);
    glGenBuffers(1,&EBO);
    glGenVertexArrays(1,&VAO);

    // 绑定VBO 并传入顶点数据
    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices),vertices,GL_STATIC_DRAW);

    // 绑定EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices),indices,GL_STATIC_DRAW);

    // 绑定VAO
    glBindVertexArray(VAO);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);



    //===================================
    // 生成一个vertex shader
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL); // 一个字符串 加载源码
    glCompileShader(vertexShader);

    // 生称一个fragment shader
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL);
    glCompileShader(fragmentShader);

    // 造一个program
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader); // 将 vertex shader 贴到 program
    glAttachShader(shaderProgram, fragmentShader); // 将 fragment shader 贴到 program
    glLinkProgram(shaderProgram);


    while (!glfwWindowShouldClose(window)) {
        porcessInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glBindVertexArray(VAO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);

        float timeValue = glfwGetTime();
        float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
        int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
        glUseProgram(shaderProgram);
        glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f); // 给ourColor 赋值

        glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
通过uniform 向shader 中传入cpu的数值

从VBO 里 挖更多的信息到VAO

#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

// 几何阶段 和  光栅化阶段 !!!
// vertex shader  &   fragment shader

using namespace std;

// 顶点数据
float vertices[] = {
        // 位置              // 颜色
        0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,   // 右下
        -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,   // 左下
        0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f    // 顶部
};

const char *vertexShaderSrc = "#version 330 core                                           
"
                              "layout (location = 0) in vec3 aPos;                         
"
                              "layout (location = 1) in vec3 aColor;                         
"
                              "out vec4 vertexColor;  
"
                              "void main(){                                                
"
                              "    vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);  
"
                              "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);}       
";

const char *fragmentShaderSrc = "#version 330 core
"
                                "in vec4 vertexColor;
"
                                "out vec4 FragColor;
"
                                "void main(){
"
                                "   FragColor = vertexColor;} 
";

void porcessInput(GLFWwindow *window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }
}

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);


    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        glfwTerminate();
        return -1;
    }

    glViewport(0, 0, 800, 600);

    //  生成立方体的 VBO  和 VAO
    unsigned int VBO,VAO;
    glGenBuffers(1,&VBO);
    glGenVertexArrays(1,&VAO);

    // 绑定VBO 并传入顶点数据
    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices),vertices,GL_STATIC_DRAW);

    // 绑定VAO
    glBindVertexArray(VAO);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
    glEnableVertexAttribArray(0);

    // 设置顶点对应颜色属性指针
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3* sizeof(float)));
    glEnableVertexAttribArray(1);


    //===================================
    // 生成一个vertex shader
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL); // 一个字符串 加载源码
    glCompileShader(vertexShader);

    // 生称一个fragment shader
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL);
    glCompileShader(fragmentShader);

    // 造一个program
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader); // 将 vertex shader 贴到 program
    glAttachShader(shaderProgram, fragmentShader); // 将 fragment shader 贴到 program
    glLinkProgram(shaderProgram);


    while (!glfwWindowShouldClose(window)) {
        porcessInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glBindVertexArray(VAO);
        glUseProgram(shaderProgram);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
main.cpp

效果图:

这个图片可能不是你所期望的那种,因为我们只提供了3个颜色,而不是我们现在看到的大调色板。这是在片段着色器中进行的所谓片段插值(Fragment Interpolation)的结果。当渲染一个三角形时,光栅化(Rasterization)阶段通常会造成比原指定顶点更多的片段。光栅会根据每个片段在三角形形状上所处相对位置决定这些片段的位置。
基于这些位置,它会插值(Interpolate)所有片段着色器的输入变量。比如说,我们有一个线段,上面的端点是绿色的,下面的端点是蓝色的。如果一个片段着色器在线段的70%的位置运行,它的颜色输入属性就会是一个绿色和蓝色的线性结合;更精确地说就是30%蓝 + 70%绿。

这正是在这个三角形中发生了什么。我们有3个顶点,和相应的3个颜色,从这个三角形的像素来看它可能包含50000左右的片段,片段着色器为这些像素进行插值颜色。如果你仔细看这些颜色就应该能明白了:红首先变成到紫再变为蓝色。片段插值会被应用到片段着色器的所有输入属性上。

Shader 类的构建:

对应文档中 从文件读取 部分~

更方便操作,从文件中读取 GLSL,也加入了编译时 的异常处理~

代码如下:

https://files.cnblogs.com/files/zach0812/Shader%E5%8C%85%E8%A3%85%E7%B1%BB_%E4%BB%8E%E6%96%87%E4%BB%B6%E4%B8%AD%E8%AF%BB%E5%8F%96GLSL.zip

Texture  (纹理/ 贴图)

纹理贴图教程:https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/ 

视频见b 站傅老师第一部分   Texture 章节~

stb_image.h 的测试:

https://github.com/nothings/stb/blob/master/stb_image.h

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

int main(){

    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(true); // 将图片 反转下 ,不然纹理贴图是 倒着的!!!
    unsigned char *data = stbi_load("../container.jpg", &width, &height, &nrChannels, 0);

    stbi_image_free(data);
    return  0 ;
}
stbTest.cpp

UV 坐标:

为了能够把纹理映射(Map)到三角形上,我们需要指定三角形的每个顶点各自对应纹理的哪个部分。这样每个顶点就会关联着一个纹理坐标(Texture Coordinate),用来标明该从纹理图像的哪个部分采样(译注:采集片段颜色)。之后在图形的其它片段上进行片段插值(Fragment Interpolation)! 这就需要用到 UV 坐标~  

加入 Texture:

纹理贴图代码

注: 需要下载 stb_image.h 文件,还有对应的图片,container.jpg 和 awesomeface.png 

https://files.cnblogs.com/files/zach0812/%E7%BA%B9%E7%90%86.zip

效果图:

Transformation 变换

进行操作的时候,顺序:先缩放,再旋转,最后位移~

矩阵操作起来是:

V = Mt * Mr * Ms * V(死记硬背就可) 算的时候要  先位移,再旋转,再位移。

Mt :位移矩阵

Mr:旋转矩阵

Ms:缩放矩阵

向量和 矩阵的区别:

在图学的世界里,向量是几何关系,可以描述出具体的三维空间特征。

矩阵是代数,是加速解决向量问题的工具。矩阵这个工具可以解决问题有很多,3维向量问题只是它能轻松解决的一种。

向量 括号 ( ),矩阵 中括号 [ ] 。

差异处:

1,向量的乘法有   点乘(投影)dot   和 叉乘 cross ~  。 其中的叉乘(可以用于计算法向量)

2,矩阵的乘法只是 矩阵行列式乘法 。

3,向量与矩阵相乘的时候如何计算?请把向量看做是一维矩阵(一般使用 列为主)。

注: GLSL的 vec4 * vec4 是 逐个元素相乘.    

缩放矩阵:

它是在单位矩阵的基础上来的,单位矩阵乘其他矩阵得到的还是其他矩阵。

第四个参数,如果表达的 x,y,z 是个坐标 那么即为 1, 如果表达的x,y,z 是个向量,那么即为0  。 总结,标量为1 ,向量为0 。 

位移矩阵:

它也是基于 单位矩阵,

旋转矩阵:

GLM:

OpenGL没有自带任何的矩阵和向量知识,所以我们必须定义自己的数学类和函数。在教程中我们更希望抽象所有的数学细节,使用已经做好了的数学库。幸运的是,有个易于使用,专门为OpenGL量身定做的数学库,那就是GLM。

GLM是OpenGL Mathematics的缩写,它是一个只有头文件的库,也就是说我们只需包含对应的头文件就行了,不用链接和编译。GLM可以在它们的网站上下载。把头文件的根目录复制到你的includes文件夹,然后你就可以使用这个库了。

glm 测试代码:

#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
int main(){
    glm::vec4 vec(1.0f,0,0,1.0f); // 声明一个(1,0,0,1) 的顶点  // (1,0,0,0)为向量

    // 我们的目标是将其 移动  (1,1,0) 到  (2,1,0)

    // 得到一个单位矩阵
    glm::mat4 trans;
    // 然后做出相应变化 得到位移矩阵
    trans = glm::translate(trans,glm::vec3(1.0f,1.0f,0));

    vec = trans * vec;

    cout << vec.x << vec.y << vec.z <<endl; // 2 1 0
}
main.cpp

工程代码:

https://files.cnblogs.com/files/zach0812/transformation.zip

效果图:

Coordinate System 坐标系统

整体工作就是将3d 几何关系通过数学运算得到2d 的数学画面(可能会丢失z轴信息,解决方法是:zbuffer 即深度缓冲)。

首先就是要将一个整体的每一个 model 从 Local Space  都变为 World Space (通过 Model Matrix 矩阵)。

然后需要给 World Space 价格摄像头 变为  View Space ,(通过 View Matrix)。

然后是 剔除 View Space 看不到的物体 变为 Clup Space ,(通过 Projection  Matrix  投影矩阵)。

最后就是将Clup Space 变为 Screen Space.(其实做的是转化为 NDC 坐标,(都是-1 - 1  范围 ))。opengl 会自动做。

工程代码:

https://files.cnblogs.com/files/zach0812/%E5%9D%90%E6%A0%87%E7%B3%BB%E7%BB%9F01.zip

效果图:

36顶点立方体:

代码:

https://files.cnblogs.com/files/zach0812/36%E9%A1%B6%E7%82%B9%E7%9A%84%E7%AB%8B%E6%96%B9%E4%BD%93.zip

效果图:

 

更多的立方体:

https://files.cnblogs.com/files/zach0812/%E6%9B%B4%E5%A4%9A%E7%AB%8B%E6%96%B9%E4%BD%93.zip

效果图:

Camera 摄像机

要定义一个摄像机,我们需要它在世界空间中的位置、观察的方向、一个指向它右测的向量以及一个指向它上方的向量。

实际上,由上面四个条件就可以算出 View Matrix ,计算方式如下:

这里叫做 LookAt 矩阵,可以直接调用glm 的lookAt函数即可获得!!! 

glm::mat4 view;

view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));

利用lookAt 得到 View Matrix

代码:

https://files.cnblogs.com/files/zach0812/%E6%8A%BD%E8%B1%A1%E5%87%BACamera%E7%B1%BB01.zip

效果图:

利用欧拉角  得到 View Matrix

俯仰角(Pitch)、偏航角(Yaw)和滚转角(Roll)

注: 默认的roll 为0 。

代码:

https://files.cnblogs.com/files/zach0812/%E4%BD%BF%E7%94%A8%E6%AC%A7%E6%8B%89%E8%A7%92%E6%9E%84%E5%BB%BACamera.zip

效果图:

使用鼠标控制摄像机

代码:

https://files.cnblogs.com/files/zach0812/%E4%BD%BF%E7%94%A8%E9%BC%A0%E6%A0%87%E6%8E%A7%E5%88%B6%E6%91%84%E5%83%8F%E6%9C%BA.zip

效果图:

  

原文地址:https://www.cnblogs.com/zach0812/p/13220295.html