当前位置: 首页 > news >正文

OpenGL Chan视频学习-8 How I Deal with Shaders in OpenGL

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);//设置返回着色器的对象IDint 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:错误处理ingreturn 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;//初始化glfwif (!glfwInit())return -1;//创建一个窗口模式的窗口并设置OpenGL上下文window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);if (!window)//如果窗口创建失败,则终止程序{glfwTerminate();//释放glfw资源return -1;}//设置当前窗口的上下文,之后所有的OpenGL调用都会在这个上下文中进行glfwMakeContextCurrent(window);//初始化GLEWif (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);//设置返回着色器的对象IDint 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:错误处理ingreturn 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;//初始化glfwif (!glfwInit())return -1;//创建一个窗口模式的窗口并设置OpenGL上下文window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);if (!window)//如果窗口创建失败,则终止程序{glfwTerminate();//释放glfw资源return -1;}//设置当前窗口的上下文,之后所有的OpenGL调用都会在这个上下文中进行glfwMakeContextCurrent(window);//初始化GLEWif (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.3运行结果

http://www.xdnf.cn/news/670303.html

相关文章:

  • 深入理解设计模式之状态模式
  • kubernetes网络详解(内部网络、Pod IP分配、CNI)
  • 操作系统期中考试
  • 如何彻底禁用WordPress中的评论
  • 三、web安全-信息收集
  • 网络:华为S5720-52X-SI交换机重置console密码
  • 从0开始学习R语言--Day11--主成分分析
  • opencv(C++) 变换图像与形态学操作
  • NFS 挂载配置与优化最佳实践指南
  • openpi π₀ 项目部署运行逻辑(四)——机器人主控程序 main.py — aloha_real
  • 探索C++标准模板库(STL):从容器到底层奥秘-全面解析String类高效技巧(上篇)
  • [Vue] ref及其底层原理
  • UE5 Mat HLSL - Load
  • LeetCodeHot100_0x09
  • 纯C++ 与欧姆龙PLC使用 FINS TCP通讯源码
  • NSSCTF-[闽盾杯 2021]DNS协议分析
  • 为什么单张表索引数量建议控制在 6 个以内
  • InvokeAI 笔记, 简单了解一下 (生成图片,text2img )
  • MQTT over SSL/TLS:工业网关如何构建端到端加密的数据传输通道
  • MySQL 只知道表名不知道具体库?如何查询?information_schema入手
  • ssh 测试 是否可以连通docker 容器
  • Excel常用公式全解析(1):从基础计算到高级应用
  • 如何理解UDP 和 TCP 区别 应用场景
  • 笔记: 在WPF中ContentElement 和 UIElement 的主要区别
  • 2025年土建施工员备考考试真题及答案
  • 数据库MySQL学习——day13(索引与查询优化)
  • gcc clang
  • FastMoss 国际电商Tiktok数据分析 JS 逆向 | MD5加密
  • 安全监测预警系统的核心价值
  • Jmeter一些元件使用的详细记录