文章目录
- 第一节
- 1、概念
- 立即模式vs核心模式
- 2、问题
- 第二节
- 1、三维坐标系![三维坐标系](https://i-blog.csdnimg.cn/direct/0703ba6b68914b08b1d14b936ccd862d.png)
- 2、什么是模型?
- 3、什么是颜色?
- 4、材质
- 第三节渲染管线
- 第四节GLAD配置流程
- 1、为什么需要GLAD?
- 2、导入函数
- 第五节创建窗体
- 第六节事件回调
- 第七节GLAD函数加载
- 2、OpenGL状态机
- 第七节封装
- 第八节封装Application以及回调函数
- 第9节CPU与GPU
- 第十节标准化设备坐标(NDC)
- 1、为什么要NDC
- 第十一节VBO
- 1、什么是VBO
- 第十一节VAO
- 1、准备VBO
- 第十二节Shader
- 1、GLSL语言
- 2、shader的编译
- 第十三节绘制一个三角形
- 第十四节绘制流程
- 第十四节总结绘制流程
- 第十五节EBO
- 第十六节彩色三角形分析
- 第十七节Shader封装
- 第十九节:变量与向量
- 第二十节Uniform和Attribute的区别
- 第二十一节纹理
- 第二十一节Mipmap
- 第二十二节:数学部分
- 1、叉乘公式
- 2、三维向量
- 3、缩放
- 4、视图正交投影
- 视口变换
- 第二十三节:绘制球体
第一节
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、退出GLFWglfwTerminate();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、退出GLFWglfwTerminate();
}
//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};//创建vaoGL_CALL(glGenVertexArrays(1, &vao));GL_CALL(glBindVertexArray(vao));//创建vboGL_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 声明一个函数指针ResizeCallback3.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};//创建vaoGL_CALL(glGenVertexArrays(1, &vao));GL_CALL(glBindVertexArray(vao));//创建vboGL_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和fsconst 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();//开始使用当前shadervoid end(); //结束使用当前shaderprivate: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、视图正交投影
视口变换
第二十三节:绘制球体