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.pswp.cn/pingmian/82701.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

动态防御新纪元:AI如何重构DDoS攻防成本格局

1. 传统高防IP的静态瓶颈与成本困境 传统高防IP依赖预定义规则库&#xff0c;面对SYN Flood、CC攻击等威胁时&#xff0c;常因规则更新滞后导致误封合法流量。例如&#xff0c;某电商平台曾因静态阈值过滤误封20%的订单接口流量&#xff0c;直接影响营收。以下代码模拟传统方案…

如何实现高性能超低延迟的RTSP或RTMP播放器

随着直播行业的快速发展&#xff0c;RTSP和RTMP协议成为了广泛使用的流媒体传输协议&#xff0c;尤其是在实时视频直播领域&#xff0c;如何构建一个高性能超低延迟的直播播放器&#xff0c;已经成为了决定直播平台成功与否的关键因素之一。作为音视频直播SDK技术老兵&#xff…

UE5 编辑器工具蓝图

文章目录 简述使用方法样例自动生成Actor&#xff0c;并根据模型的包围盒设置Actor的大小批量修改场景中Actor的属性&#xff0c;设置Actor的名字&#xff0c;设置Actor到指定的文件夹 简述 使用编辑器工具好处是可以在非运行时可以对资源或场景做一些操作&#xff0c;例如自动…

解锁5月游戏新体验 高速电脑配置推荐

很多玩家用户会发现一个规律&#xff0c;618大促前很多商家会提前解锁各种福利&#xff0c;5月选购各种电脑配件有时候会更划算&#xff01;并且&#xff0c;STEAM在5月还有几个年度主题促销&#xff0c;“生物收集游戏节”、“僵尸大战吸血鬼游戏节”等等&#xff0c;配件大促…

干货|VR全景是什么?

VR全景技术解析&#xff1a;概念、特点与用途 VR全景&#xff0c;全称为虚拟现实全景技术&#xff08;Virtual Reality Panorama Technology&#xff09;&#xff0c;是基于虚拟现实&#xff08;Virtual Reality,VR&#xff09;技术的创新展示方式。VR全景技术利用专业的拍摄设…

Nacos适配GaussDB超详细部署流程,通过二进制包、以及 Docker 打通用镜像包部署保姆级教程

1部署openGauss 官方文档下载 https://support.huaweicloud.com/download_gaussdb/index.html 社区地址 安装包下载 本文主要是以部署轻量级为主要教程,系统为openEuler,ip: 192.168.1.15 1.1系统环境准备 操作系统选择 系统AARCH64X86-64openEuler√√CentOS7√Docker…

MySQL 表内容的增删查改 -- CRUD操作,聚合函数,group by 子句

目录 1. Create 1.1 语法 1.2 单行数据 全列插入 1.3 多行数据 指定列插入 1.4 插入数据否则更新数据 1.5 替换 2. Retrieve 2.1 SELECT 列 2.1.1 全列查询 2.1.2 指定列查询 2.1.3 查询字段为表达式 2.1.4 为查询结果指定别名 2.1.5 结构去重 2.2 WHERE 条件 …

LabVIEW累加器标签通道

主要展示了 Accumulator Tag 通道的使用&#xff0c;通过三个并行运行的循环模拟不同数值的多个随机序列&#xff0c;分别以不同频率向累加器写入数值&#xff0c;右侧循环每秒读取累加器值&#xff0c;同时可切换查看每秒内每次事件的平均值&#xff0c;用于演示多线程数据交互…

【iOS】源码阅读(五)——类类的结构分析

文章目录 前言类的分析类的本质objc_class 、objc_object和NSObjectobjc_object&#xff1a;所有对象的基类型objc_class&#xff1a;类的底层结构NSObject&#xff1a;面向用户的根类 小结 指针内存偏移普通指针----值拷贝对象----指针拷贝或引用拷贝用数组指针引出----内存偏…

Baklib构建企业CMS高效协作与安全管控体系

企业CMS高效协作体系构建 基于智能工作流引擎的设计逻辑&#xff0c;现代企业内容管理系统通过预设多节点审核路径与自动化任务分配机制&#xff0c;有效串联市场、技术、法务等跨部门协作链路。系统支持多人同时编辑与版本追溯功能&#xff0c;结合细粒度权限管控模块&#x…

Linux环境变量与地址空间

哈喽&#xff0c;各位Linux初学者们&#xff01;今天咱们来聊聊Linux中那两个看起来很高大上但实际上跟我们日常使用息息相关的概念&#xff1a;环境变量和地址空间。别被这些术语吓到&#xff0c;我会用最接地气的方式给你解释清楚&#xff01; 一、环境变量&#xff1a;Linu…

Oracle SHARED POOL的SUB POOL技术

从Oracle 9i开始&#xff0c;SHARED POOL可以分为多个SUB POOL&#xff0c;其数量受以下几个因素影响&#xff1a; 系统CPU的数量。默认情况下&#xff0c;在Oracle中每4个CPU分配一个SUB POOL&#xff0c;最多不能超过7个。 共享池的大小。SUB POOL的最小容量随着Oracle版…

Collection集合遍历的三种方法

1.foreach循环遍历 格式&#xff1a;for&#xff08;元素的数据类型 变量名&#xff1a;数组或集合&#xff09;{ } 2.使用迭代器遍历 方法名称&#xff1a;Iterator<E> iterator&#xff08;&#xff09; 说明&#xff1a;返回集合中的迭代器对象&#xff0c;该迭代…

头歌之动手学人工智能-Pytorch 之autograd

目录 第1关&#xff1a;Variable 任务描述 编程要求 测试说明 没有伟大的愿望&#xff0c;就没有伟大的天才。——巴尔扎克开始你的任务吧&#xff0c;祝你成功&#xff01; 第2关&#xff1a;Variable 属性 任务描述 编程要求 测试说明 真正的科学家应当是个幻想家&a…

篇章二 数据结构——前置知识(二)

目录 1. 包装类 1.1 包装类的概念 1.2 基本数据类型和对应的包装类 1.3 装箱和拆箱 1.4 自动装箱和自动拆箱 1.5 练习 —— 面试题 2. 泛型 2.1 如果没有泛型——会出现什么情况&#xff1f; 2.2 语法 2.3 裸类型 1.没有写<> 但是没有报错为什么&#xff1f; …

Git典型使用场景相关命令

Git典型使用场景相关命令 1 建立本地仓库与远程仓库的联系2 作为开发者参与项目的常用命令2-1 一般步骤2-2 **合并与同步主分支改动**2-3 **查看日志和差异**2-4 **提交后想修改或撤销**2-5 分支管理2-6 清除未被追踪的文件&#xff08;谨慎使用&#xff09; 3 作为远程仓库管理…

redis缓存-更新策略-三大缓存问题

缓存&#xff1a;数据交换的缓冲区&#xff0c;存储的数据的临时地方&#xff0c;读写性能较高。 步骤&#xff1a; 先从redis里面查询 缓存命中&#xff1a;直接返回结果缓存未命中 从数据库里面查询 没有数据&#xff1a;返回null有数据&#xff1a;存到redis里面&#xff…

[TriCore] 01.QEMU 虚拟化 TriCore 架构中的寄存器 指令

目录 1.寄存器宏 - FIELD() 2.寄存器操作 - FIELD_SETTER() & FIELD_GETTER() 3.指令辅助方法 - HELPER() 3.1.辅助宏 3.2.指令示例 3.3.函数调用 4.PSW 寄存器读写 - psw_read() & psw_write() 1.寄存器宏 - FIELD() FIELD() 宏定义寄存器 MASK // include/hw…

《软件工程》第 4 章 - 需求获取

在软件工程中&#xff0c;需求获取是挖掘用户真实需求的关键步骤&#xff0c;它为后续的设计、开发和测试提供坚实基础。本章将围绕需求获取的流程、方法及工具展开&#xff0c;结合实际案例与 Java 代码&#xff0c;深入讲解这一重要环节。 4.1 软件需求的初始表示 4.1.1 用例…

react diff 算法

diff 算法作为 Virtual DOM 的加速器&#xff0c;其算法的改进优化是 React 整个界面渲染的基础和性能的保障&#xff0c;同时也是 React 源码中最神秘的&#xff0c;最不可思议的部分 diff 算法会帮助我们就算出 VirtualDOM 中真正变化的部分&#xff0c;并只针对该部分进行原…