bilibili视频链接:
【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p=5&vd_source=44b77bde056381262ee55e448b9b1973
函数网站:
docs.gl
说明:
1.之后就不再整理具体函数了,网站直接翻译会更直观也会有更多注意点。直接通过csdn索引查找反而会慢。
2.代码区域会单独注释功能参数返回值和相关注意事项。
3.课程学习从4-本节,如果有些函数没有注释可以看专栏里面的前面发表的文章,一般会有解释。 4.如果觉得代码注释白色字体不太直观可以直接copy到相应软件看。
5.有两种版本的可供查看:注释全面的和注释简洁版的,可以在索引里面找到相关代码查看。
6.希望能帮到你。
7.有错误请跟我说明一下,可能整理的时候没有检查好。
一、知识点整理
1.1 ShaderProgramSource结构体
//功能:定义ShaderProgramSource结构体,用于存储着色器代码
//方便ParseShader函数返回多个着色器代码
struct ShaderProgramSource
{
std::string VertexSource;
std::string FragmentSource;
};
1.2ParseShader函数
//功能:解析着色器代码文件。
//参数:filepath:着色器代码文件路径
//返回值:ShaderProgramSource结构体,包含着色器代码字符串
static ShaderProgramSource ParseShader(const std::string& filepath)
{
//功能:打开文件流
//参数:filepath:着色器代码文件路径
std::ifstream stream(filepath);
//定义着色器类型
enum class ShaderType
{
NONE=-1,VERTEX=0,FRAGMENT=1
};
//该变量用于存储着色器代码
std::string line;
//该变量用于存储着色器类型
std::stringstream ss[2];
//该变量是当前着色器类型
ShaderType type = ShaderType::NONE;
//功能:读取文件中的每一行内容,直到文件结束
while (getline(stream, line))
{
//如果当前行包含#shader,则说明接下来是着色器代码
//nposstd::string::npos 是 C++ 标准库中 std::string 类的一个静态成员。
//它代表了一个无效的位置值,通常用于表示在字符串中未找到子字符串的情况。
if (line.find("#shader") != std::string::npos)
{
//如果当前行包含vertex,则说明接下来是顶点着色器代码
if (line.find("vertex") != std::string::npos)
{
type = ShaderType::VERTEX;
}
else if (line.find("fragment") != std::string::npos)
{
type = ShaderType::FRAGMENT;
}
}
else
{
//否则,将当前行添加到对应着色器代码的stringstream中
//ss[]是一个数组,用于存储着色器代码,通过ss[]<<line<<'\n'将当前行添加到对应着色器代码的stringstream中
ss[(int)type] << line << '\n';
std::cout << line << " hhh" << std::endl;
}
}
//返回ShaderProgramSource结构体
return { ss[0].str(), ss[1].str() };
}
1.3int main函数补充
//解析着色器代码文件
ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
std::string vertexShader = source.VertexSource;
std::string fragmentShader = source.FragmentSource;
std::cout << "VERTEX" << std::endl << vertexShader << std::endl;
std::cout << "FRAGMENT" << std::endl << fragmentShader << std::endl;
二、完整代码
1.1完全注释代码
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
//功能:定义ShaderProgramSource结构体,用于存储着色器代码
//方便ParseShader函数返回多个着色器代码
struct ShaderProgramSource
{
std::string VertexSource;
std::string FragmentSource;
};
//功能:解析着色器代码文件。
//参数:filepath:着色器代码文件路径
//返回值:ShaderProgramSource结构体,包含着色器代码字符串
static ShaderProgramSource ParseShader(const std::string& filepath)
{
//功能:打开文件流
//参数:filepath:着色器代码文件路径
std::ifstream stream(filepath);
//定义着色器类型
enum class ShaderType
{
NONE=-1,VERTEX=0,FRAGMENT=1
};
//该变量用于存储着色器代码
std::string line;
//该变量用于存储着色器类型
std::stringstream ss[2];
//该变量是当前着色器类型
ShaderType type = ShaderType::NONE;
//功能:读取文件中的每一行内容,直到文件结束
while (getline(stream, line))
{
//如果当前行包含#shader,则说明接下来是着色器代码
//nposstd::string::npos 是 C++ 标准库中 std::string 类的一个静态成员。
//它代表了一个无效的位置值,通常用于表示在字符串中未找到子字符串的情况。
if (line.find("#shader") != std::string::npos)
{
//如果当前行包含vertex,则说明接下来是顶点着色器代码
if (line.find("vertex") != std::string::npos)
{
type = ShaderType::VERTEX;
}
else if (line.find("fragment") != std::string::npos)
{
type = ShaderType::FRAGMENT;
}
}
else
{
//否则,将当前行添加到对应着色器代码的stringstream中
//ss[]是一个数组,用于存储着色器代码,通过ss[]<<line<<'\n'将当前行添加到对应着色器代码的stringstream中
ss[(int)type] << line << '\n';
}
}
//返回ShaderProgramSource结构体
return { ss[0].str(), ss[1].str() };
}
//功能:编译着色器代码
static unsigned int CompilesShader(unsigned int type, const std::string& source)
{
//功能:创建着色器对象
unsigned int id = glCreateShader(type);
//功能:设置着色器源代码.
const char* src = source.c_str();
//功能:替换着色器对象中的源代码。将该id的指定着色器的源代码设置为src指针指向的字符串
glShaderSource(id, 1, &src, nullptr);
//功能:编译着色器对象的源代码
glCompileShader(id);
//设置返回着色器的对象ID
int result;
//功能:从着色器对象返回一个参数,表示编译是否成功。
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
//如果编译失败,则输出错误信息
if (result == GL_FALSE)
{
int length;
//功能:获取编译错误信息的长度
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
//分配内存,用于存储编译错误信息
char* message = (char*)alloca(length*sizeof(char));
//功能:获取编译错误信息
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;
std::cout << message << std::endl;
//删除着色器对象
glDeleteShader(id);
return 0;
}
//TODO:错误处理ing
return id;
}
//功能:创建着色器程序
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
//创建程序对象
unsigned int program = glCreateProgram();
//编译顶点着色器对象
unsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);
//编译片段着色器对象
unsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);
//功能:将编译好的着色器对象附加到程序对象中
glAttachShader(program, vs);
glAttachShader(program, fs);
//功能:链接程序对象
glLinkProgram(program);
//功能:验证着色器程序对象是否可以在当前OpenGL状态中执行。检查着色器程序的完整性和可执行性。
glValidateProgram(program);
//删除着色器对象,因为它们已经被链接到程序对象中
glDeleteShader(vs);
glDeleteShader(fs);
//返回着色器程序
return program;
}
int main(void)
{
GLFWwindow* window;
//初始化glfw
if (!glfwInit())
return -1;
//创建一个窗口模式的窗口并设置OpenGL上下文
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)//如果窗口创建失败,则终止程序
{
glfwTerminate();//释放glfw资源
return -1;
}
//设置当前窗口的上下文,之后所有的OpenGL调用都会在这个上下文中进行
glfwMakeContextCurrent(window);
//初始化GLEW
if (glewInit() != GLEW_OK)
std::cout << "Error!" << std::endl;
//打印OpenGL版本信息
std::cout << glGetString(GL_VERSION) << std::endl;
//准备数据
float position[6] = {
0.0f, 0.5f,
-0.5f, -0.5f,
0.5f, -0.5f
};
//定义缓冲区对象
unsigned int buffer;
//功能:生成缓冲区对象,并将数据写入缓冲区
glGenBuffers(1, &buffer);
//功能:将缓冲区对象绑定到目标
glBindBuffer(GL_ARRAY_BUFFER, buffer);
//功能:将数据写入缓冲区
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), position, GL_STATIC_DRAW);
//功能:配置顶点属性指针
glEnableVertexAttribArray(0);
//功能:指定顶点属性数组的索引、大小、数据类型、是否归一化、偏移量、数据指针
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
//解析着色器代码文件
ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
std::string vertexShader = source.VertexSource;
std::string fragmentShader = source.FragmentSource;
std::cout << "VERTEX" << std::endl << vertexShader << std::endl;
std::cout << "FRAGMENT" << std::endl << fragmentShader << std::endl;
//创建着色器程序
unsigned int shader = CreateShader(vertexShader, fragmentShader);
//使用着色器程序
glUseProgram(shader);
//渲染循环,直到窗口被关闭
while (!glfwWindowShouldClose(window))
{
//清除颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//功能:绘制三角形
glDrawArrays(GL_TRIANGLES, 0, 3);
//刷新缓冲区并交换窗口
glfwSwapBuffers(window);
//处理窗口事件,如键盘输入、鼠标移动等
glfwPollEvents();
}
//删除着色器程序
//glDeleteProgram(shader);
//释放 GLFW 库占用的所有资源。
glfwTerminate();
return 0;
}
2.2简洁注释代码
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
//功能:定义ShaderProgramSource结构体,用于存储着色器代码
struct ShaderProgramSource
{
std::string VertexSource;
std::string FragmentSource;
};
//功能:解析着色器代码文件。
static ShaderProgramSource ParseShader(const std::string& filepath)
{
//功能:打开文件流
std::ifstream stream(filepath);
//定义着色器类型
enum class ShaderType
{
NONE=-1,VERTEX=0,FRAGMENT=1
};
//该变量用于存储着色器代码
std::string line;
//该变量用于存储着色器类型
std::stringstream ss[2];
//该变量是当前着色器类型
ShaderType type = ShaderType::NONE;
//功能:读取文件中的每一行内容,直到文件结束
while (getline(stream, line))
{
//如果当前行包含#shader,则说明接下来是着色器代码
if (line.find("#shader") != std::string::npos)
{
//如果当前行包含vertex,则说明接下来是顶点着色器代码
if (line.find("vertex") != std::string::npos)
{
type = ShaderType::VERTEX;
}
else if (line.find("fragment") != std::string::npos)
{
type = ShaderType::FRAGMENT;
}
}
else
{
//否则,将当前行添加到对应着色器代码的stringstream中
ss[(int)type] << line << '\n';
}
}
//返回ShaderProgramSource结构体
return { ss[0].str(), ss[1].str() };
}
//功能:编译着色器代码
static unsigned int CompilesShader(unsigned int type, const std::string& source)
{
//功能:创建着色器对象
unsigned int id = glCreateShader(type);
//功能:设置着色器源代码.
const char* src = source.c_str();
//功能:替换着色器对象中的源代码。将该id的指定着色器的源代码设置为src指针指向的字符串
glShaderSource(id, 1, &src, nullptr);
//功能:编译着色器对象的源代码
glCompileShader(id);
//设置返回着色器的对象ID
int result;
//功能:从着色器对象返回一个参数,表示编译是否成功。
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
//如果编译失败,则输出错误信息
if (result == GL_FALSE)
{
int length;
//功能:获取编译错误信息的长度
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
//分配内存,用于存储编译错误信息
char* message = (char*)alloca(length*sizeof(char));
//功能:获取编译错误信息
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;
std::cout << message << std::endl;
//删除着色器对象
glDeleteShader(id);
return 0;
}
//TODO:错误处理ing
return id;
}
//功能:创建着色器程序
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
//创建程序对象
unsigned int program = glCreateProgram();
//编译顶点着色器对象
unsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);
//编译片段着色器对象
unsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);
//功能:将编译好的着色器对象附加到程序对象中
glAttachShader(program, vs);
glAttachShader(program, fs);
//功能:链接程序对象
glLinkProgram(program);
//功能:验证着色器程序对象是否可以在当前OpenGL状态中执行。检查着色器程序的完整性和可执行性。
glValidateProgram(program);
//删除着色器对象,因为它们已经被链接到程序对象中
glDeleteShader(vs);
glDeleteShader(fs);
//返回着色器程序
return program;
}
int main(void)
{
GLFWwindow* window;
//初始化glfw
if (!glfwInit())
return -1;
//创建一个窗口模式的窗口并设置OpenGL上下文
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)//如果窗口创建失败,则终止程序
{
glfwTerminate();//释放glfw资源
return -1;
}
//设置当前窗口的上下文,之后所有的OpenGL调用都会在这个上下文中进行
glfwMakeContextCurrent(window);
//初始化GLEW
if (glewInit() != GLEW_OK)
std::cout << "Error!" << std::endl;
//打印OpenGL版本信息
std::cout << glGetString(GL_VERSION) << std::endl;
//准备数据
float position[6] = {
0.0f, 0.5f,
-0.5f, -0.5f,
0.5f, -0.5f
};
//定义缓冲区对象
unsigned int buffer;
//功能:生成缓冲区对象,并将数据写入缓冲区
glGenBuffers(1, &buffer);
//功能:将缓冲区对象绑定到目标
glBindBuffer(GL_ARRAY_BUFFER, buffer);
//功能:将数据写入缓冲区
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), position, GL_STATIC_DRAW);
//功能:配置顶点属性指针
glEnableVertexAttribArray(0);
//功能:指定顶点属性数组的索引、大小、数据类型、是否归一化、偏移量、数据指针
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
//解析着色器代码文件
ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
std::string vertexShader = source.VertexSource;
std::string fragmentShader = source.FragmentSource;
std::cout << "VERTEX" << std::endl << vertexShader << std::endl;
std::cout << "FRAGMENT" << std::endl << fragmentShader << std::endl;
//创建着色器程序
unsigned int shader = CreateShader(vertexShader, fragmentShader);
//使用着色器程序
glUseProgram(shader);
//渲染循环,直到窗口被关闭
while (!glfwWindowShouldClose(window))
{
//清除颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//功能:绘制三角形
glDrawArrays(GL_TRIANGLES, 0, 3);
//刷新缓冲区并交换窗口
glfwSwapBuffers(window);
//处理窗口事件,如键盘输入、鼠标移动等
glfwPollEvents();
}
//删除着色器程序
//glDeleteProgram(shader);
//释放 GLFW 库占用的所有资源。
glfwTerminate();
return 0;
}