01OpenGL基本学习

文章目录

第一节

1、概念

图形API:跨平台,跨编程语言的图形程序接口,用于调用GPU上的指令功能。

立即模式vs核心模式
  • 立即模式:3.0版本之前不会暴露太多细节
  • 核心渲染模式:3.0版本之后推出大量自由的功能

2、问题

1、图形API是什么?

  • 是一个由Khronos组织制定并且维护的规范
    2、ARB与Khronos是什么?
    -ARB组织缩写 Khronos是一个非盈利的联盟。
    3、游戏引擎与图形API
    -游戏引擎由图形API组成

第二节

1、三维坐标系

2、什么是模型?

网格(Mesh):存储了一个模型的几何形状数据

比如三角形:由三个顶点按顺序构成。(逆时针转)

3、什么是颜色?

RGB:红绿蓝(三个通道0-255)

光:意味着红绿蓝的光的强度

物体:意味着对红绿蓝的光的反射百分比

4、材质

描述了物体表面如何与光发生反应

比如:颜色 金属非金属 光滑粗糙等

Mesh+Material = 各种效果

第三节渲染管线

渲染过程:

梳理:

顶点数据

三维变换

图元装配

剪裁剔除

(前面是第一阶段)

光栅化

片元着色

混合与测试(第二阶段)

第四节GLAD配置流程

1、为什么需要GLAD?

2、导入函数

配置网站:https://glad.dav1d.de/

第五节创建窗体

如图所示:

#include<iostream>

//注意:glad头文件必须在glfw之前引用
#include<glad/glad.h>
#include<GLFW/glfw3.h>
using namespace std;
/*
创建glfw窗体系统
*/

const int height = 600;
const int width = 800;
int main()
{
    //1、初始化GLWF基本环节
    glfwInit();
    // 设置主版本号和次版本号
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
    // 设置OpenGL核心配置
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    //2、创建窗体对象
    GLFWwindow*window = glfwCreateWindow(width,height, "LearnOpenGL",NULL,NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    // 设置窗体为当前上下文
    glfwMakeContextCurrent(window);


    //3、执行窗体循环
    while(!glfwWindowShouldClose(window))
    {
        //接收并且分发窗体消息
        //检查是否有需要处理的消息
        glfwPollEvents();
    }
    

    //4、退出GLFW
    glfwTerminate();

    return 0;
}

第六节事件回调

事件回调函数:

  • 事件回调函数:窗体激活响应鼠标等

第七节GLAD函数加载


2、OpenGL状态机



第七节封装

错误检查的封装

checkError.h
#pragma once
#ifdef Debug
#define GL_CALL(x) x;checkError();
#endif
void checkError();

checkError.cpp
#include "checkError.h"
#include<iostream>
#include<assert.h>
#include<glad/glad.h>
#include<GLFW/glfw3.h>
void checkError()
{
    GLenum errorCode = glGetError();

    
    switch(errorCode)
    {
        case GL_NO_ERROR:
            break;
        case GL_INVALID_ENUM:
            std::cout<<"GL_INVALID_ENUM"<<std::endl;
            break;
        case GL_INVALID_VALUE:
            std::cout<<"GL_INVALID_VALUE"<<std::endl;
            break;
        case GL_INVALID_OPERATION:
            std::cout<<"GL_INVALID_OPERATION"<<std::endl;
            break;
        case GL_INVALID_FRAMEBUFFER_OPERATION:
            std::cout<<"GL_INVALID_FRAMEBUFFER_OPERATION"<<std::endl;
            break;
        case GL_OUT_OF_MEMORY:
            std::cout<<"GL_OUT_OF_MEMORY"<<std::endl;
            break;
        default:
            std::cout<<"未知错误"<<std::endl;
    }
    assert(errorCode == GL_NO_ERROR);
}

第八节封装Application以及回调函数


封装后的Application代码:

Application.h

#pragma once
#include<glad/glad.h>
#include "GLFW/glfw3.h"
#include<iostream>
#define app Application::getInstance()

class GLFWwindow;
using ResizeCallback = void(*)(int width,int height);
using KeyBoardCallback = void(*)(int key,int action,int mods);
using MouseButtonCallback = void(*)(int button,int action,int mods);

class Application
{

    public:
    ~Application();
    //访问实例
    static Application* getInstance(); 

    bool init(const int width,const int height);
    bool update();
    bool destroy();

    uint32_t getWidth() const;
    uint32_t getHeight() const;
    //存放变量
    private:
    uint32_t mWidth{0};
    uint32_t mHeight{0};
    GLFWwindow*mWindow{nullptr};

    static Application*m_instance;
    
   
    private:
    //1、回到函数指针
    ResizeCallback mResizeCallback{nullptr}; 
    KeyBoardCallback mKeyBoardCallback{nullptr};
    MouseButtonCallback mMouseButtonCallback{nullptr};

    public:
    //2、设置回调函数
    void setResizeCallback(ResizeCallback callback)
    {
        mResizeCallback = callback;
    }

    void setKeyBoardCallback(KeyBoardCallback callback)
    {
        mKeyBoardCallback = callback;   
    }

    void setMouseButtonCallback(MouseButtonCallback callback)
    {
        mMouseButtonCallback = callback;
    }
    private:
    static void frameBufferSizeCallback(GLFWwindow* window,int width,int height);
    static void keyBoardCallback(GLFWwindow* window,int key,int action,int scancode,int mods);
    static void mouseButtonCallback(GLFWwindow* window,int button,int action,int mods);


    


    private:
    Application();
    void operator=(const Application&){};
    Application(const Application&){};
    void operator=(const Application&&){};
    Application(const Application&&){};

};

Application.cpp
#include "Application.h"
#include "GLFW/glfw3.h"


Application*Application::m_instance = nullptr;
// 非线程安全的封装
Application* Application::getInstance()
{
    if(m_instance == nullptr)
    {
        m_instance = new Application();
    }
    return m_instance;
}

uint32_t Application::getWidth() const
{
    return mWidth;
}
uint32_t Application::getHeight() const
{
    return mHeight;
}

bool Application::init(const int width = 800,const int height= 600)
{
    mWidth = width;
    mHeight = height;
        //1、初始化GLWF基本环节
    glfwInit();
    // 设置主版本号和次版本号
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
    // 设置OpenGL核心配置
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    
    //2、创建窗体对象
    mWindow = glfwCreateWindow(mWidth,mHeight, "LearnOpenGL",NULL,NULL);
    if (mWindow == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return false;
    }
    // 设置窗体为当前上下文
    glfwMakeContextCurrent(mWindow);

    //使用glad加载所有当期啊版本的opengl函数
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return false;
    }

    glfwSetFramebufferSizeCallback(mWindow, frameBufferSizeCallback);
    glfwSetKeyCallback(mWindow, keyBoardCallback);
    glfwSetMouseButtonCallback(mWindow, mouseButtonCallback);

    //this就是当前全局唯一的Application对象
    glfwSetWindowUserPointer(mWindow, this);
    return true;
}
bool Application::update()
{
    if(glfwWindowShouldClose(mWindow))
    {
        return false;
    }
     //接收并且分发窗体消息
    //检查是否有需要处理的消息
    glfwPollEvents();
    //渲染操作


    glfwSwapBuffers(mWindow); //双缓冲
    return true;
}
bool Application::destroy()
{
    //4、退出GLFW
    glfwTerminate();
}
//4
void Application::frameBufferSizeCallback(GLFWwindow* window,int width,int height)
{
    std::cout<<"Resize: "<<width<<" "<<height<<std::endl;
    Application*self = (Application*)glfwGetWindowUserPointer(window);
    self->mResizeCallback(width,height);

    // if(Application::getInstance()->mResizeCallback != nullptr)
    // {
    //     Application::getInstance()->mResizeCallback(width,height);
    // }
}
void Application::keyBoardCallback(GLFWwindow* window,int key,int scancode,int action,int mods)
{
    std::cout<<"key: "<<key<<" "<<action<<std::endl;
    if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, true);
    }
    Application*self = (Application*)glfwGetWindowUserPointer(window);
    self->mKeyBoardCallback(key,action,mods);
}

void Application::mouseButtonCallback(GLFWwindow* window,int button,int action,int mods)
{
    std::cout<<"mouse: "<<button<<" "<<action<<std::endl;
    Application*self = (Application*)glfwGetWindowUserPointer(window);
    self->mMouseButtonCallback(button,action,mods);
}



Application::Application()
{

}

Application::~Application()
{

}

第9节CPU与GPU



第十节标准化设备坐标(NDC)

1、为什么要NDC




第十一节VBO

1、什么是VBO





第十一节VAO







1、准备VBO

2、构建VAO

代码:

GLuint vao;
void prepareShader()
{
    GLuint posvbo,colorvbo;
    float vertices[] = {
        0.0f, 0.5f, 0.0f,
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f
    };
    float colors[] = {
        1.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 1.0f
    };
    //创建vao
    GL_CALL(glGenVertexArrays(1, &vao));
    GL_CALL(glBindVertexArray(vao));
    //创建vbo
    GL_CALL(glGenBuffers(1, &posvbo));
    GL_CALL(glBindBuffer(GL_ARRAY_BUFFER,posvbo));
    GL_CALL(glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW));

    GL_CALL(glGenBuffers(1, &colorvbo));
    GL_CALL(glBindBuffer(GL_ARRAY_BUFFER,colorvbo));
    GL_CALL(glBufferData(GL_ARRAY_BUFFER,sizeof(colors),colors,GL_STATIC_DRAW));

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

    glBindBuffer(GL_ARRAY_BUFFER,colorvbo);
    GL_CALL(glEnableVertexAttribArray(1));
    GL_CALL(glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0));

    //释放绑定
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glBindVertexArray(0);

}

第十二节Shader

什么是shader?

一种运行在GPU上的着色器程序(类c语言)

1、GLSL语言





2、shader的编译

第十三节绘制一个三角形

#include<iostream>

//注意:glad头文件必须在glfw之前引用
#include<glad/glad.h>
#include<GLFW/glfw3.h>
#include<assert.h>
#include<wrapper/checkError.h>
#include<app/Application.h>
using namespace std;
/*
        单例类(全局唯一实例)
        成员变量 +成员函数
        2.1 成员函数-init(初始化)
        2.2 成员函数-update(每一帧执行)
        2.3 成员函数-destroy(结尾执行)
        响应回调函数(Resize)
        3.1 声明一个函数指针ResizeCallback
        3.2 声明一个ResizeCallback类型的成员变量
        3.3 声明一个SetResizeCallback的函数 ,设置窗体变化响应回调函数
        3.4 声明一个static的静态函数,用于响应glfw窗体变化
        3.5 将静态函数设置到glfw的监听Resize监听当中
        3.6*学会使用glfw的UserPointer
        响应键盘消息(OnKeyBoard)

        4.1VBO的创建销毁
        4.2练习绑定vbo,向vbo传输数据
            -glBindBuffer
            -glBufferData
*/
void OnResize(int width,int height)
{
    std::cout<<"OnResize"<<std::endl;
}
void OnMouse(int button, int action, int mod)
{
    std::cout<<"OnMouse"<<std::endl;
}
void OnKeyBoard(int key, int action, int mod)
{
    std::cout<<"OnKeyBoard"<<std::endl;
}


const int height = 600;
const int width = 800;

GLuint vao;
GLuint shaderProgram;
void prepareShader()
{
    GLuint posvbo,colorvbo;
    float vertices[] = {
        0.0f, 0.5f, 0.0f,
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f
    };
    float colors[] = {
        1.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 1.0f
    };
    //创建vao
    GL_CALL(glGenVertexArrays(1, &vao));
    GL_CALL(glBindVertexArray(vao));
    //创建vbo
    GL_CALL(glGenBuffers(1, &posvbo));
    GL_CALL(glBindBuffer(GL_ARRAY_BUFFER,posvbo));
    GL_CALL(glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW));

    GL_CALL(glGenBuffers(1, &colorvbo));
    GL_CALL(glBindBuffer(GL_ARRAY_BUFFER,colorvbo));
    GL_CALL(glBufferData(GL_ARRAY_BUFFER,sizeof(colors),colors,GL_STATIC_DRAW));

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

    glBindBuffer(GL_ARRAY_BUFFER,colorvbo);
    GL_CALL(glEnableVertexAttribArray(1));
    GL_CALL(glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0));

    //释放绑定
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glBindVertexArray(0);

}

void prepare()
{
    // 1、完成vs和fs
    const char* vertexShaderSource = 
    "#version 460 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "layout (location = 1) in vec3 aColor;\n"  // 接收颜色数据
    "out vec3 vertexColor;\n"  // 输出颜色数据给片段着色器
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos, 1.0);\n"
    "   vertexColor = aColor;\n"  // 将颜色传递给片段着色器
    "}\n\0";

    const char* fragmentShaderSource =
    "#version 460 core\n"
    "out vec4 FragColor;\n"
    "in vec3 vertexColor;\n"  // 接收传入的颜色数据
    "void main()\n"
    "{\n"
    "   FragColor = vec4(vertexColor, 1.0f);\n"  // 使用传入的颜色数据
    "}\n\0";

    // 2、创建shader程序(fs,vs)
    GLuint vertex,fragment;
    vertex = glCreateShader(GL_VERTEX_SHADER);
    fragment = glCreateShader(GL_FRAGMENT_SHADER);

    //3、编译shader程序
    glShaderSource(vertex,1,&vertexShaderSource,NULL);
    glCompileShader(vertex);
    glShaderSource(fragment,1,&fragmentShaderSource,NULL);
    glCompileShader(fragment);

    //4、创建shader程序对象
   
    shaderProgram = glCreateProgram();
    //5、将shader程序对象链接到shader程序
    glAttachShader(shaderProgram,vertex);
    glAttachShader(shaderProgram,fragment);
    glLinkProgram(shaderProgram);
    //6、使用shader程序
    // glUseProgram(shaderProgram);
    //7、释放shader程序
    glDeleteShader(vertex);
    glDeleteShader(fragment);
    
}

int main()
{
    if(!app->init(width, height))
    {
        return -1;
    }
    app->setResizeCallback(OnResize);
    app->setKeyBoardCallback(OnKeyBoard);
    app->setMouseButtonCallback(OnMouse);
    GL_CALL(glViewport(0, 0, width, height));
    //准备着色器
    prepareShader();
    prepare();



    GL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
    while(app->update())
    {
        GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
        //画三角形
        GL_CALL(glUseProgram(shaderProgram));
        GL_CALL(glad_glBindVertexArray(vao));
        GL_CALL(glDrawArrays(GL_TRIANGLES, 0, 3));
    }
    app->destroy();

    return 0;
}

实现效果:

第十四节绘制流程

第十四节总结绘制流程

第十五节EBO




第十六节彩色三角形分析


第十七节Shader封装

shader.h
#pragma once
#include "core.h"
#include<string>

class Shader
{
    public:
    Shader(const char* vertexPath, const char* fragmentPath);
    ~Shader();
    void begin();//开始使用当前shader
    void end(); //结束使用当前shader

    private:
    void checkShaderErrors(GLuint target,std::string type);


    private:
    GLuint mprogramID{0}; //shader程序id
};

shader.cpp
#include "shader.h"
#include "core.h"
#include <wrapper/checkError.h>
#include<iostream>
#include<fstream> //读取文件
#include <sstream>
#include <string>
Shader::Shader(const char* vertexPath, const char* fragmentPath)
{
    std::string vertexCode; //顶点着色器代码
    std::string fragmentCode; //片段着色器代码

    std::ifstream vShaderFile; //顶点着色器文件
    std::ifstream fShaderFile; //片段着色器文件

    vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);

    try
    {
        vShaderFile.open(vertexPath);
        fShaderFile.open(fragmentPath);

        std::stringstream vShaderStream,fShaderStream;

        vShaderStream << vShaderFile.rdbuf();//读取文件内容
        fShaderStream << fShaderFile.rdbuf();

        vShaderFile.close();
        fShaderFile.close();
        
        vertexCode = vShaderStream.str();
        fragmentCode = fShaderStream.str();
    }
    catch(const std::ifstream::failure e)
    {
        std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
    }
    const char*vertexShaderCode = vertexCode.c_str();
    const char*fragmentShaderCode = fragmentCode.c_str();

    GLuint vertex,fragment;
    vertex = glCreateShader(GL_VERTEX_SHADER);
    fragment = glCreateShader(GL_FRAGMENT_SHADER);

    //输入代码
    glShaderSource(vertex,1,&vertexShaderCode,NULL);
    glShaderSource(fragment,1,&fragmentShaderCode,NULL);

    //编译着色器
    glCompileShader(vertex);
    checkShaderErrors(vertex, "VERTEX");
    glCompileShader(fragment);
    checkShaderErrors(fragment, "FRAGMENT");

    //创建着色器程序
    mprogramID = glCreateProgram();
    glAttachShader(mprogramID,vertex);
    glAttachShader(mprogramID,fragment);

    glLinkProgram(mprogramID);
    checkShaderErrors(mprogramID, "PROGRAM");
    //销毁
    glDeleteShader(vertex);
    glDeleteShader(fragment);
}
Shader::~Shader()
{

}
void Shader::begin()//开始使用当前shader
{
    GL_CALL(glUseProgram(mprogramID)); //shader程序id
}
void Shader::end() //结束使用当前shader
{
    GL_CALL(glUseProgram(0));
}

void Shader::checkShaderErrors(GLuint target,std::string type)
{
    int success = 0;
    char infoLog[1024];
    if(type == "VERTEX"|| type == "FRAGMENT")
    {
        glGetShaderiv(target,GL_COMPILE_STATUS,&success);
        if(!success)
        {
            glGetShaderInfoLog(target,1024,NULL,infoLog);
            std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
        }
    }
    else if(type == "PROGRAM")
    {
        glGetProgramiv(target,GL_LINK_STATUS,&success);
        if(!success)
        {
            glGetProgramInfoLog(target,1024,NULL,infoLog);
            std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
        }
    }
    else {
        std::cout << "ERROR::SHADER::TYPE_NOT_SUPPORTED" << std::endl;
    }
}

第十九节:变量与向量






第二十节Uniform和Attribute的区别


第二十一节纹理















第二十一节Mipmap










第二十二节:数学部分

1、叉乘公式


2、三维向量


3、缩放

翻转









4、视图正交投影













视口变换











第二十三节:绘制球体





相关推荐
杨武博20 分钟前
音频格式转换
android·音视频
golitter.1 小时前
python正则表达式库及re学习01
python·学习·正则表达式
小齿轮lsl1 小时前
半波整流器原理
单片机·嵌入式硬件·学习·电力电子·电源·电源硬件
Rbeiyutc1 小时前
计算机网络(3)
学习
爱米的前端小笔记2 小时前
前端学习八股资料CSS(一)
前端·css·经验分享·学习·职场和发展
golitter.2 小时前
python正则表达式库及re学习02
python·学习·正则表达式
音视频牛哥2 小时前
Android音视频直播低延迟探究之:WLAN低延迟模式
android·音视频·实时音视频·大牛直播sdk·rtsp播放器·rtmp播放器·android rtmp
YYYYYY020203 小时前
C++中级学习笔记
jvm·笔记·学习
ChangYan.3 小时前
CondaError: Run ‘conda init‘ before ‘conda activate‘解决办法
android·conda
KeKe_L3 小时前
scikit-learn学习Day30
python·学习·scikit-learn