文章目录
- 第一节
- 第二节
- 第三节渲染管线
- 第四节GLAD配置流程
- 第五节创建窗体
- 第六节事件回调
- 第七节GLAD函数加载
- 第七节封装
- 第八节封装Application以及回调函数
- 第9节CPU与GPU
- 第十节标准化设备坐标(NDC)
- 第十一节VBO
- 第十一节VAO
- 第十二节Shader
- 第十三节绘制一个三角形
- 第十四节绘制流程
- 第十四节总结绘制流程
- 第十五节EBO
- 第十六节彩色三角形分析
- 第十七节Shader封装
- 第十九节:变量与向量
- 第二十节Uniform和Attribute的区别
- 第二十一节纹理
- 第二十一节Mipmap
- 第二十二节:数学部分
- 第二十三节:绘制球体
第一节
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、导入函数
第五节创建窗体
如图所示:
#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、视图正交投影
视口变换
第二十三节:绘制球体