LearnOpenGL-入门-着色器
本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正
我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject
LearnOpenGL中文官网:https://learnopengl-cn.github.io/
文章目录
- 着色器
- GLSL
- 数据类型
- 输入与输出
- Uniform
- 更多属性
- 我们自己的着色器类
着色器
- 简介
- 着色器(Shader)是运行在GPU上的小程序,分别对应渲染管理不同阶段。
- 着色器是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。
GLSL
-
简介
- 着色器是GLSL的类C语言写成的
- 着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。每个着色器的入口点都是main函数。
- main函数:在这个函数中我们处理所有的输入变量,并将结果输出到输出变量中
-
结构
#version version_number in type in_variable_name; in type in_variable_name;out type out_variable_name;uniform type uniform_name;int main() {// 处理输入并进行一些图形操作...// 输出处理过的结果到输出变量out_variable_name = weird_stuff_we_processed; }
说明:
-
当我们特别谈论到顶点着色器的时候,每个输入变量也叫顶点属性。
-
我们能声明的顶点属性是有上限的,它一般由硬件来决定。
-
OpenGL确保至少有16个包含4分量的顶点属性可用,但是有些硬件或许允许更多的顶点属性,你可以查询GL_MAX_VERTEX_ATTRIBS来获取具体的上限
xint nrAttributes;glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
-
数据类型
类型 | 含义 |
---|---|
vecn | 包含n 个float分量的默认向量 |
bvecn | 包含n 个bool分量的向量 |
ivecn | 包含n 个int分量的向量 |
uvecn | 包含n 个unsigned int分量的向量 |
dvecn | 包含n 个double分量的向量 |
输入与输出
-
输入与输出
in和out:类型和名称要对得上
-
特殊的顶点着色器阶段
需要用
layout (location = 0)
指定输入变量,来源于顶点数据(疑问:这个顶点数据在cpu还是gpu,应该是GPU,因为用了glBufferData从CPU拷贝到GPU上了) -
例子
顶点着色器
#version 330 core layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为0out vec4 vertexColor; // 为片段着色器指定一个颜色输出void main() {gl_Position = vec4(aPos, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // 把输出变量设置为暗红色 }
片段着色器
#version 330 core out vec4 FragColor;in vec4 vertexColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)void main() {FragColor = vertexColor; }
Uniform
-
简介
是一种从CPU中的应用向GPU中的着色器发送数据的方式
-
与顶点属性不同
- uniform是全局的(Global),可以被着色器程序的任意着色器在任意阶段访问
- 无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新
-
使用例子
#version 330 core out vec4 FragColor;uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量void main() {FragColor = ourColor; }
float timeValue = glfwGetTime(); float greenValue = (sin(timeValue) / 2.0f) + 0.5f; int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor"); glUseProgram(shaderProgram); // 发送数据 glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
关键代码
glGetUniformLocation(); 通过名称查询uniform ourColor的位置值
-
细节
OpenGL在其核心是一个C库,所以无法重载,所以每个上传数据给Uniform的函数都不一样
f
函数需要一个float作为它的值 i
函数需要一个int作为它的值 ui
函数需要一个unsigned int作为它的值 3f
函数需要3个float作为它的值 fv
函数需要一个float向量/数组作为它的值 glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
在vertexColorLocation位置上上传4个float
更多属性
-
顶点数据
float vertices[] = {// 位置 // 颜色0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部 };
-
glsl
#version 330 core layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为 0 layout (location = 1) in vec3 aColor; // 颜色变量的属性位置值为 1out vec3 ourColor; // 向片段着色器输出一个颜色void main() {gl_Position = vec4(aPos, 1.0);ourColor = aColor; // 将ourColor设置为我们从顶点数据那里得到的输入颜色 }
#version 330 core out vec4 FragColor; in vec3 ourColor;void main() {FragColor = vec4(ourColor, 1.0); }
-
告诉OpenGL如何解读顶点缓冲中的顶点数据
// 位置属性 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // 颜色属性 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float))); glEnableVertexAttribArray(1);
-
图示
我们自己的着色器类
我只关心读取这段代码
Shader(const char* vertexPath, const char* fragmentPath)
{// 1. 从文件路径中获取顶点/片段着色器std::string vertexCode;std::string fragmentCode;std::ifstream vShaderFile;std::ifstream fShaderFile;// 保证ifstream对象可以抛出异常: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();// 转换数据流到stringvertexCode = vShaderStream.str();fragmentCode = fShaderStream.str(); }catch(std::ifstream::failure e){std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;}const char* vShaderCode = vertexCode.c_str();const char* fShaderCode = fragmentCode.c_str();[...]
- 代码流程
- 用了文件输入流:ifstream
- 打开文件读取数据vShaderStream << vShaderFile.rdbuf();
- 保存在stringstream类型对象中
- 然后再转为string,再转为字符数组
相关文章:

LearnOpenGL-入门-着色器
本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正 我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject LearnOpenGL中文官网:https://learnopengl-cn.github.io/ 文章目录着色器GLSL数据类型输入与输…...

【谷粒学院】vue、axios、element-ui、node.js(44~58)
44.前端技术-vue入门 🧨Vue.js 是什么 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。 Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具…...

【一些回忆】2022.02.26-2023.02.26 一个普通男孩的365天
💃🏼 本人简介:男 👶🏼 年龄:18 🤞 作者:那就叫我亮亮叭 📕 专栏:一些回忆 为什么选择在这个时间节点回忆一下呢? 一是因为今天距离2023高考仅剩1…...

OSPF的多区域特性 (电子科技大学TCP/IP实验三)
一.实验目的 1、掌握OSPF 协议中区域的类型、特征和作用 2、掌握OSPF 路由器的类型、特征和作用 3、掌握OSPF LSA 分组的类型、特征和作用 4、理解OSPF 区域类型、路由器类型和OSPF LSA 分组类型间的相互关系 二.预备知识 1、静态路由选择和动态路…...

(四十四)多个事务更新同一行数据时,是如何加锁避免脏写的?
之前我们已经用很多篇幅给大家讲解了多个事务并发运行的时候,如果同时要读写一批数据,此时读和写时间的关系是如何协调的,毕竟要是你不协调好的话,可能就会有脏读、不可重复读、幻读等一系列的问题。 简单来说,脏读、…...

【数据库】第十二章 数据库管理
第12章 数据库管理 数据库的物理存储 关于内存、外存、磁盘、硬盘、软盘、光盘的区别_Allenzyg的博客-CSDN博客_磁盘和硬盘的区别 数据库记录在磁盘上的存储 定长,变长跨块,非跨快 文件的组织方方法: 无序记录文件(堆文件heap或pile file…...

Redis源码---整体架构
目录 前言 Redis目录结构 前言 deps目录 src 目录 tests 目录 utils 目录 重要的配置文件 Redis 功能模块与源码对应 前言 服务器实例 数据库数据类型与操作 高可靠性和高可扩展性 辅助功能 前言 以先面后点的方法推进无特殊说明,都是基于 Redis 5.0.…...

基于springboot+vue的校园招聘系统
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...

SAP MM学习笔记1-SAP中扩张的概念,如何将一个物料从工厂A扩张到工厂B
MM中在创建物料的时候,最低也得创建如下5个view。 基本数据1 基本数据2 购买管理 会计1 会计2 1,扩张是什么 有时候,你想增加其他的View,比如保管场所 等,你不能用MM02来做编辑,要用MM01来做扩张。这就是扩…...

【Python】Numpy数组的切片、索引详解:取数组的特定行列
【Python】Numpy数组的切片、索引详解:取数组的特定行列 文章目录【Python】Numpy数组的切片、索引详解:取数组的特定行列1. 介绍2. 切片索引2.1 切片索引先验知识2.1 一维数组的切片索引2.3 多维数组的切片索引3. 数组索引(副本)…...
2023年全国最新交安安全员精选真题及答案6
百分百题库提供交安安全员考试试题、交安安全员考试预测题、交安安全员考试真题、交安安全员证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 51.安全生产资金保障制度建立后关键在于落实,各施工企业在落实安全生…...

JavaScript 闭包【自留】
闭包的概念理解 闭包的定义 ✅ 这里先来看一下闭包的定义,分成两个:在计算机科学中和在JavaScript中。 ✅ 在计算机科学中对闭包的定义(维基百科): 闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures);是在支持头等函数…...

【MySQL】什么是意向锁 IS IX 及值得学习的思想
文章目录前言行锁和表锁使用意向锁意向锁的算法意向锁的思想JDK 中相似的思想前言 之前看 MySQL 都刻意忽略掉了 IS 和 IX 锁,今天看 《MySQL 是怎样运行的》,把意向锁讲的很通透,本篇博文提炼一下思想。 I: Intention Lock(意向…...
python多线程实现
用于线程实现的Python模块 Python线程有时称为轻量级进程,因为线程比进程占用的内存少得多。 线程允许一次执行多个任务。 在Python中,以下两个模块在一个程序中实现线程 - _thread模块threading模块 这两个模块之间的主要区别在于_thread模块将线程视…...

macOS使用CodeRunner快速配置fortran环境
个人网站:xzajyjs.cn 由于一些项目的缘故,需要有fortran的需求,但由于是M1 mac的缘故,不能像windows那样直接使用vsivf这种经典配置。搜了一下网上主流的跨平台方案,主要是gfortran,最近用Coderunner(主要…...

【云原生】k8s 离线部署讲解和实战操作
文章目录一、概述二、前期准备1)节点信息2)修改主机名和配置hosts3)配置ssh互信4)时间同步5)关闭防火墙6)关闭 swap7)禁用SELinux8)允许 iptables 检查桥接流量三、开始部署1&#x…...
【Kubernetes】第十一篇 - 滚动发布的介绍与实现
一,前言 上一篇,介绍了灰度发布和流量切分的集中方式,以及如何实现 k8s 的灰度发布; 本篇,介绍滚动发布的实现; 二,滚动发布简介 滚动发布 滚动发布,则是我们一般所说的无宕机发…...
【尊享版】如何系统构建你的思维认知模型?
超友们,早上好,国庆节快乐~ 今天为你带来的分享是《如何系统构建你的思维认知模型?》,主要分为三个部分: 第一部分:【实现爆发式成长的 10 个思维模型】 第二部分:【6 个不可不知的…...
urho3D编码约定
缩进样式类似于Allman(BSD),即在控制语句的下一行使用大括号,在同一级别缩进。在switch-case语句中,case与switch语句处于相同的缩进级别。 缩进使用4个空格而不是制表符。不应保留空行上的缩进。 类和结构名称以大写…...

Overleaf推广奖励:增加合作者的数量、解锁Dropbox同步和项目修改历史
Overleaf推广奖励 Overleaf是一个LaTeX\LaTeXLATEX在线编译器,它可以让你与合作者共同在线编辑文档。但是默认的免费账号仅能邀请一个合作者。那么如何增加合作者的数量呢? Overleaf推出了一个奖励计划,你邀请其他人注册Overleaf…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...