OpenGL 入门 19:内建变量、接口块、Uniform缓冲

2023-11-07

一、内建变量

查询所有的内建变量的话,请查看OpenGL的wiki

顶点着色器

Input

变量名称

变量类型

变量语义

作用

gl_VertexID

int

索引

当使用glDrawElements,存储的是正在绘制顶点的当前索引。

当使用glDrawArrays,储存的是从渲染调用开始的已处理顶点数量。

gl_InstanceID

int

索引

实例化渲染中,当前实例的索引,下标从0开始。

Output

变量名称

变量类型

变量语义

作用

gl_Position

vec4

位置

当前顶点齐次裁剪空间的输出坐标

gl_PointSize

float

点的宽高(像素)

该功能默认关闭,需调用 glEnable(GL_PROGRAM_POINT_SIZE);

片元着色器

Input

变量名称

变量类型

变量语义

作用

gl_FragCoord

vec4

屏幕坐标

(x,y)为当前片元的屏幕坐标,

z分量等于对应片段的深度值(只读

gl_FrontFacing

bool

片元朝向

片段是正面则true,否则false。

Output

变量名称

变量类型

变量语义

作用

gl_FragColor

vec4

颜色

表示当前片元的颜色

gl_FragDepth

float

深度值

可修改片段的深度值

gl_FragDepth 详解

  1. 可设置为一个[0.0, 1.0] 之间的值。

  1. 如无修改,gl_FragDepth自动取gl_FragCoord.z的值。

  1. 若进行修改,会影响到提前深度测试,造成一定性能影响。可通过以下功能进行调和。

使用深度条件(Depth Condition)重新声明gl_FragDepth变量:

layout (depth_<condition>) out float gl_FragDepth;

条件

描述

any

默认值。提前深度测试是禁用的,你会损失很多性能

greater

你只能让深度值比gl_FragCoord.z更大

less

你只能让深度值比gl_FragCoord.z更小

unchanged

如果你要写入gl_FragDepth,你将只能写入gl_FragCoord.z的值

注意:使用 layout (depth_greater) 修饰 gl_FragDepth 时,深度缓冲区的比较函数应该设置为 GL_GREATER,否则就会导致深度测试不正确。如果深度缓冲区的比较函数设置为 GL_LESS 或者其他不匹配的比较函数,就会导致一些本应该被遮挡的物体显示在前面,从而影响渲染结果。

二、接口块

接口块是一种结构体类型,用于在着色器程序中定义输入输出变量的集合,并将这些变量打包成一个整体进行传递。

使用接口块可以方便地传递数据,避免了在着色器程序中单独定义大量的输入输出变量。同时,接口块也提高了程序的可读性可维护性,方便进行代码管理和调试。

定义语法如下:

in/out interface BlockName {
  DataType varName1;
  DataType varName2;
  ...
};
  • in/out 分别表示输入和输出

  • BlockName 表示接口块的名称

  • DataType 表示变量的数据类型

  • varName1、varName2 等表示变量名称。

三、Uniform缓冲对象

引入

在多个着色器中,我们会发现有些uniform变量是完全相同的,比如观察矩阵透视矩阵。因此在设置和修改时,需要一个一个手动设置,十分麻烦。并且相同的uniform变量,一定程度上造成了资源的浪费。

所以引入了Uniform缓冲对象(Uniform Buffer Object)的工具,它允许我们定义一系列在多个着色器中相同的全局Uniform变量。当使用Uniform缓冲对象的时候,我们只需要设置相关的uniform一次

好处如下:
1. 全局的Uniform进行设置和修改十分方便。
2. 突破了着色器中只能使用一定数量uniform的限制(可以通
GL_MAX_VERTEX_UNIFORM_COMPONENTS来查询上限)。

Uniform块布局

Uniform块的内容是储存在一个Uniform缓冲对象中的,它实际上只是一块预留内存。

由于这块内存并没有保存它具体存储的是什么类型的数据,因此需要通过布局限定符来告诉OpenGL如何解释这块内存。

布局方式

基本概念

变量的字节大小

适用场景

对比信息

std140

变量按照一定的规则对齐后被放入连续的内存空间中,对齐规则为变量占用空间的大小与4字节中的较大值,也可强制指定对齐方式。

4字节对齐

用于定义Uniform缓冲区中的变量布局,兼容性好。

std140布局与std430布局相比,在数组中间插入非vec4的变量时需要填充额外的空间。

std430

变量按照一定的规则对齐后被放入连续的内存空间中,对齐规则为变量占用空间的大小,也可强制指定对齐方式。

任意对齐

用于定义Uniform缓冲区中的变量布局,兼容性好。

std430布局与std140布局相比,在数组中间插入非vec4的变量不需要填充额外的空间。

packed

变量不需要对齐,可以紧凑排列在内存中,但可能导致访问变量时的性能问题。

任意大小

用于定义Uniform缓冲区中的变量布局,可以最大限度地压缩内存使用。

packed布局不支持结构体成员中嵌套数组或结构体成员。

shared

变量按照一定的规则对齐后被放入共享内存中,对齐规则与std140布局一致。

4字节对齐

用于定义着色器中共享内存的布局。

仅适用于Compute Shader中。

使用Uniform缓冲

创建Uniform缓冲对象,分配足够的内存,并添加相应数据:

// 创建Uniform缓冲对象
unsigned int uboExampleBlock;
glGenBuffers(1, &uboExampleBlock);
glBindBuffer(GL_UNIFORM_BUFFER, uboExampleBlock);
glBufferData(GL_UNIFORM_BUFFER, 152, NULL, GL_STATIC_DRAW); // 分配152字节的内存
glBindBuffer(GL_UNIFORM_BUFFER, 0);
// 填充数据
glBindBuffer(GL_UNIFORM_BUFFER, uboExampleBlock);
glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data);
glBindBuffer(GL_UNIFORM_BUFFER, 0);

为了uniform块知道使用哪个uniform缓冲,因此定义了一些绑定点(Binding Point),以确定他们之间的连接关系。

Uniform块与绑定点的连接

方式一:

可通过调用glGetUniformBlockIndex获得着色器中Uniform块的位置值索引,接受一个程序对象和Uniform块的名称。然后再调用glUniformBlockBinding 将相应着色器中的Uniform块绑定到指定绑定点上。例子如下:

unsigned int lights_index = glGetUniformBlockIndex(shaderA.ID, "Lights");   
glUniformBlockBinding(shaderA.ID, lights_index, 2);

方式二:

从OpenGL 4.2版本起,你也可以添加一个布局标识符,显式地将Uniform块的绑定点储存在着色器中,这样就不用再调用glGetUniformBlockIndexglUniformBlockBinding了。

layout(std140, binding = 2) uniformLights { ... };

Uniform缓冲与绑定点的连接

glBindBufferBase(GL_UNIFORM_BUFFER, 2, uboExampleBlock); 
// 或
glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152);

glBindbufferBase需要一个目标,一个绑定点索引和一个Uniform缓冲对象作为它的参数。这个函数将uboExampleBlock链接到绑定点2上,自此,绑定点的两端都链接上了。

glBindBufferRange函数还需要一个附加的偏移量和大小参数,这样子你可以绑定Uniform缓冲的特定一部分到绑定点中。通过使用glBindBufferRange函数,你可以让多个不同的Uniform块绑定到同一个Uniform缓冲对象上。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenGL 入门 19:内建变量、接口块、Uniform缓冲 的相关文章

  • 从活动顶点数组生成平滑法线

    我正在尝试通过挂钩 OpenGl 调用来破解和修改旧版 opengl 固定管道游戏的多个渲染功能 而我当前的任务是实现着色器照明 我已经创建了一个适当的着色器程序 可以正确照亮大部分对象 但该游戏的地形是在没有提供正常数据的情况下绘制的 游
  • 着色器/矩阵问题 - 看不到对象

    我试图在屏幕上放置一个立方体并点亮它 我想要在立方体上添加 phong 阴影 当我运行代码时 我可以看到背景图像 但看不到立方体 我相当确定立方体本身是正确的 因为我已经设法用纯色着色器显示它 我已经设法编译着色器程序 但我根本看不到立方体
  • libgdx 中帧缓冲区的结果不明确

    我得到以下奇怪的结果帧缓冲区 http libgdx badlogicgames com nightlies docs api com badlogic gdx graphics glutils FrameBuffer htmllibgdx
  • OpenGL NURBS 曲面

    我正在学习 OpenGL 我想要一个中间有轻微驼峰的表面 我目前正在使用这段代码 但我不确定如何调整 ctrl 点以使其达到我想要的方式 它目前就像 我想要这样的 我不完全确定我应该使用哪些控制点 并且我对其工作原理感到困惑 include
  • 没有着色器的 OpenGL

    我已经阅读了一些教程来编写以下代码 唯一的区别是原始教程使用 SDL 而不是 GLEW 我不明白这段代码有什么问题 它可以编译 但我没有看到三角形 教程也没有使用着色器 include
  • 使用 Opengl 绘制立方体 3D

    我想使用 OpenGL 绘制 3D 立方体这是我的代码如何纠正错误 float ver 8 3 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
  • 纹理openGl。 C++、qt

    我试图用草纹理覆盖我的地形 由高度图制成 但它没有按预期工作 我什至无法在简单的 GL QUAD 上获取纹理 结果是多色网络 void GLWidget initializeGL glEnable GL TEXTURE 2D 在 QGLwi
  • 在 OpenGL 中,为什么 glVertexAttribPointer 要求“指针”参数以 void* 形式传入?

    规格为glVertexAttribPointer如下 void glVertexAttribPointer GLuint index GLint size GLenum type GLboolean normalized GLsizei s
  • glutPostRedisplay 不在循环内工作

    我试图让一个人在 y 轴上跳跃 所以我使用 2 秒的循环 第一秒它应该向下移动并弯曲膝盖 第二秒它应该向上移动 然后在起始位置完成 现在我刚刚开始让这个人在第一秒内跪下并弯曲膝盖 我还没有编写动画的其余部分 问题是 glutPostRedi
  • OpenGL z轴指向哪里?

    我正在尝试了解 OpenGL 坐标系 我到处都看到它被描述为右撇子 但这与我的经验不符 我尝试绘制一些形状和 3 d 对象 我发现 z 轴显然指向 屏幕 而 x 指向右侧 y 指向上方 这是左手坐标系的描述 我缺少什么 编辑 例如 http
  • 为什么我的 FPS 相机一劳永逸地滚动?

    如果我忽略四元数代数的肮脏细节 我想我理解了旋转和平移变换背后的数学 但仍然不明白我做错了什么 为什么我的相机一劳永逸地滚动 更具体地说 我应该如何从相机的方向 旋转矩阵 计算相机视图矩阵 我正在用 Python 编写一个简约的 3d 引擎
  • 如何安装适用于 Windows C++ 的最新版本 OpenGL?

    我正在使用 Visual Studio 2010 运行 Windows 7 包含的 OpenGL 版本 include 是版本 1 1 我希望使用合理的当前版本 某种版本 3 或 4 我需要做什么才能达到该状态 OpenGL SDK 页面位
  • 使用draw()而不是eventloop时的pyglet

    我正在尝试用 pyglet 画一个圆 但当我使用 draw 函数而不是 app run 循环时 它是不可见的 有什么建议我可以做什么吗 谢谢 from math import from pyglet gl import window pyg
  • 为什么 OpenGL 给对象提供句柄而不是指针?

    OpenGL 的传统是让用户使用 unsigned int 句柄来操作 OpenGL 对象 为什么不直接给出一个指针呢 与指针相比 唯一 ID 有何优点 TL DR OpenGL ID 不会双射映射到内存位置 单个 OpenGL ID 可能
  • OpenGL 与 Eclipse CDT + MinGW + GLEW + GLFW:未定义的参考

    Edit 与此同时 我已经弄清楚了这一点 并在下面写了详细的答案 我刚刚尝试在 Win7 上从 Express 版本的 MSVC 10 切换到 Eclipse CDT 在配置时遇到了以下简单 OpenGL 代码的问题 在 Visual St
  • 为什么拥有单独的投影矩阵但结合模型和视图矩阵会有好处?

    当您学习 3D 编程时 您会被告知用 3 个变换矩阵来思考是最简单的 模型矩阵 该矩阵对于每个模型都是独立的 它根据需要旋转和缩放对象 最后将其移动到 3D 世界中的最终位置 模型矩阵将模型坐标转换为世界坐标 视图矩阵 对于大量对象 如果不
  • 将带有 glut 的点击坐标添加到向量链接列表中

    我想创建一个向量链接列表 并在 GLUT 库的帮助下获取点击的位置并将它们附加到链接列表中 这些是我写的结构 typedef struct vector int x int y Vector typedef struct VectorLis
  • GLSL NVidia 方形神器

    当 GLSL 着色器在以下 GPU 上生成不正确的图像时 我遇到了问题 GT 430 GT 770 GTX 570显卡760 但在这些上正常工作 英特尔高清显卡 2500英特尔高清4000英特尔4400显卡740MRadeon HD 631
  • 更改 Qt OpenGL 窗口示例以使用 OpenGL 3.3

    我正在尝试更改 Qt OpenGL 示例以使用更现代的 opengl 版本 330 似乎合适 所以我做了 在 main cpp 上设置版本和配置文件 设置着色器版本 更改着色器以使用统一 它现在构建没有任何错误 但我只看到一个空白窗口 我错
  • 在 Linux 上运行我自己的程序的权限被拒绝? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有Ubuntu 9 4 我已经构建了程序 一些基本的 OpenGL 该程序只是制作一个旋转的正方形 然后运行它并 sh blabla p

随机推荐

  • Qt简易闹钟

    配置文件 QT core gui texttospeech greaterThan QT MAJOR VERSION 4 QT widgets CONFIG c 11 The following define makes your comp
  • Leetcode 632最小区间

    632 最小区间 难度 困难 标签 哈希表 双指针 字符串 Description 你有 k 个 非递减排列 的整数列表 找到一个 最小 区间 使得 k 个列表中的每个列表至少有一个数包含在其中 我们定义如果 b a lt d c 或者在
  • linux top详解

    语法 root incloudos logs top h procps ng version 3 3 10 Usage top hv bcHiOSs d secs n max u U user p pid s o field w cols
  • nginx服务器

    一 介绍 Nginx engine x 是一个高性能的HTTP和反向代理服务器 也是一个IMAP POP3 SMTP服务 Nginx是由伊戈尔 赛索耶夫为俄罗斯访问量第二的Rambler ru站点 俄文 开发的 第一个公开版本0 1 0发布
  • 【算法/剑指Offer】如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。

    题目描述 如何得到一个数据流中的中位数 如果从数据流中读出奇数个数值 那么中位数就是所有数值排序之后位于中间的数值 如果从数据流中读出偶数个数值 那么中位数就是所有数值排序之后中间两个数的平均值 我们使用Insert 方法读取数据流 使用G
  • Angular4.0_数据绑定和管道

    单向数据绑定 使用插值表达式将一个表达式的值显示在模板上 h1 productTitle h1 事件绑定 使用小括号将组建控制器的一个方法绑定为模板上一个事件的处理器
  • ROS机器人语音模块

    ROS机器人语音模块 文章目录 ROS机器人语音模块 零 乘骐骥以驰骋兮 来吾道夫先路 壹 路漫漫其修远兮 吾将上下而求索 贰 苟余情其信姱以练要兮 长顑颔亦何伤 叁 不吾知其亦已兮 苟余情其信芳 肆 虽体解吾犹未变兮 岂余心之可惩 末 亦
  • 【仿真】Carla介绍与使用 [1] (附代码手把手讲解)

    0 参考与前言 主要介绍无人驾驶的仿真环境CARLA 开源社区维护 以下为相关参考链接 Carla官方文档 建议后续找的时候 先按好版本号 有些功能 api 是新版本里有的 Carla官方github Youtube Python Wind
  • vue css >>> , /deep/ 深度选择器

    vue引用了第三方组件 有时候我们需要改写第三方组件的样式 而又不想去除scoped属性造成组件之间的样式污染 此时只能通过 gt gt gt 穿透scoped 有些Sass 之类的预处理器无法正确解析 gt gt gt 这时可以使用 de
  • stm32 利用链表和定时器动态实现led等器件周期性控制

    stm32 esp8266 ota系列文章 stm32 esp8266 ota 快速搭建web服务器之docker安装openresty stm32 esp8266 ota升级 tcp模拟http stm32 esp8266 ota升级 h
  • 初探 ModBus4j -简单使用指南

    目录 前言 开发环境 工具准备 具体实现 下载Modbus4j 解决空指针异常 解决数组越界 测试 测试环境准备 正式测试 前言 之前提到过 由于项目需求 需要封装 ModBus协议 ModBus协议较早 网上开源开源库也不少 可参见 Mo
  • STM32驱动8266-----8266AP模式

    找了很久 一直没有找到驱动的程序 查一些资料 字写了一个简单程序 记录分享一下 void esp8266 inittcp void printf AT CIPMODE 2 r n 设置AP模式 delay ms 10000 延时函数 pri
  • vue3.0教程——搭建Vue脚手架【简化版】

    目录 哈喽 大家好丫 你们的小郭子又来啦 一 环境要求 1 node安装 前端开发环境 2 vue cli脚手架安装 二 安装依赖 1 使用命令行安装以下依赖 2 通过 vue ui 命令以图形化界面来管理项目依赖 3 导入你刚刚项目的地址
  • 装系统使用默认administrator用户

    在设置键盘布局界面按下Ctrl Shift F4重启 进入系统后 见到一个 系统准备工具 3 14 开始 运行 输入 XCOPY windir System32 svchost exe windir System32 oobe audit
  • MyBatis框架( 项目构建笔记 )

    MyBatis框架 项目构建笔记 一 框架 二 获取参数 三 查询 四 模糊查询 批量删除 五 resultMap和映射关系 五 动态SQL 基本功能实现的项目结构 将SqlSessionFactory 使用工具类进行封装 映射文件的名称要
  • 牛客 AB28 快速幂 JAVA

    描述 请你计算 ab mod p 的值 一共有 q 次询问 输入描述 第一行输入一个正整数 q 代表询问次数 接下来每行输入三个正整数 a b p 代表一次询问 数据范围 1 1051 q 105 1 1071 a b p 107 输出描述
  • BatchNormalization、LayerNormalization、InstanceNorm、GroupNorm、SwitchableNorm总结

    本篇博客总结几种归一化办法 并给出相应计算公式和代码 1 综述 1 1 论文链接 1 Batch Normalization https arxiv org pdf 1502 03167 pdf 2 Layer Normalizaiton
  • 解决git分支切换时遇到的问题

    Please commit your changes or stash them before you switch branches问题的解决 在项目开发的过程中 有时候会遇到一个分支上的BUG还没解决 另一个分支上的BUG又急需解决 这
  • docker 安装mysql总是报错

    完全卸载mysql 把所有的mysql 相关的文件全部删除 find name mysql 查到文件全部删除
  • OpenGL 入门 19:内建变量、接口块、Uniform缓冲

    一 内建变量 查询所有的内建变量的话 请查看OpenGL的wiki 顶点着色器 Input 变量名称 变量类型 变量语义 作用 gl VertexID int 索引 当使用glDrawElements 存储的是正在绘制顶点的当前索引 当使用