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

(第五章)OpenGL超级宝典学习:统一变量(uniform variable)

统一变量

前言
本篇在讲什么

本篇记录对glsl中的变量uniform的认知和学习
本篇适合什么

适合初学Open的小白
适合想要学习OpenGL中uniform的人

本篇需要什么

C++语法有简单认知
OpenGL有简单认知
最好是有OpenGL超级宝典蓝宝书
依赖Visual Studio编辑器
本篇的特色

具有全流程的图文教学
重实践,轻理论,快速上手
提供全流程的源码内容


★提高阅读体验★

👉 ♠ 一级标题 👈

👉 ♥ 二级标题 👈

👉 ♣ 三级标题 👈

👉 ♦ 四级标题 👈


目录

  • ♠ uniform
    • ♥ 什么是uniform
    • ♥ uniform的作用
    • ♥ 简单理解
    • ♥ 定义
      • ♣ 方式1
      • ♣ 方式2
      • ♣ 定义演示
    • ♥ 赋值
      • ♣ 获取位置赋值
      • ♣ 直接赋值
    • ♥ 实战演示
  • ♠ 一致区块
    • ♥ 定义
    • ♥ 数据布局
      • ♣ 标准布局
    • ♥ 数据缓冲
    • ♥ 完整示例
  • ♠ 推送
  • ♠ 结语


♠ uniform

♥ 什么是uniform

uniform在glsl是一种特殊变量的限定符,这种变量被称为统一变量


♥ uniform的作用

能够直接将数据从应有程序传递到着色器阶段


♥ 简单理解

简单理解,用uniform定义在着色器中的变量,类似代码中的静态变量


♥ 定义

♣ 方式1

uniform vec4 out_color;

可以直接通过uniform+类型+字段的方式定义在着色器内


♣ 方式2

layout(location = 0) uniform vec4 out_color;

可以在方式1的基础上加上layout位置限定符


♣ 定义演示

"#version 450 core                                                 \n"
"                                                                  \n"
"uniform vec4 out_color1;										   \n"
"                                                                  \n"
"layout(location = 0) uniform vec4 out_color2;					   \n"
"                                                                  \n"
"out vec4 color;                                                   \n"
"                                                                  \n"
"void main(void)                                                   \n"
"{                                                                 \n"
"    color = out_color1;										   \n"
"}                                                                 \n"

以上是一个片段着色器的代码,我们在其中按照方式1方式2定义了两个统一变量out_color1out_color2


♥ 赋值

定义uniform后,我们需要在外部给其赋值,根据不同的定义方式,赋值的方式也略有不同


♣ 获取位置赋值

第一种赋值方式针对根据方式1定义的变量,我们首先需要获取变量在程序中的位置,才可以通过接口赋值,看下述代码

int location = glGetUniformLocation(program, "out_color1");
glUniform4f(location, 1.0f, 1.0f, 1.0f, 1.0f)

要点1:glGetUniformLocation

该接口可以根据定义的变量名,来获取统一变量在程序中的位置,参数1是创建好的程序,参数2是自定义的变量名,out_color1是我们在上边定义代码中写的变量

要点2:glUniform4f

我们在获取到变量位置后,可以通过glUniform**类似的接口给不同类型的统一变量赋值,参数1是位置,后边是需要赋的值


♣ 直接赋值

在上述定义2的形式中,我们直接通过限定符layout给变量设定了位置,如此一来我们就不需要再获取位置了,可以直接赋值

glUniform4f(0, 1.0f, 1.0f, 1.0f, 1.0f)

类似的形式还有很多,比如直接定义数组的赋值方式

GLfloat outColor[4] = {1.0f, 1.0f, 1.0f, 1.0f };glUniform4fv(0, 1, outColor);

♥ 实战演示

我们已经知道了如何定义变量,还有如何赋值,下面我们就写一个简单的例子,画一个三角形,通过uniform变量给三角形上色

注:该例子直接修改OpenGl超级宝典官方示例singletri.cpp,只需修改片段着色器和render方法

  • 片段着色器
static const char * fs_source[] =
{"#version 450 core                                                 \n""                                                                  \n""uniform vec4 out_color1;										   \n""                                                                  \n""layout(location = 0) uniform vec4 out_color2;					   \n""                                                                  \n""out vec4 color;                                                   \n""                                                                  \n""void main(void)                                                   \n""{                                                                 \n""    color = out_color2;										   \n""}                                                                 \n"
};
  • render
virtual void render(double currentTime)
{static const GLfloat green[] = { 0.0f, 0.25f, 0.0f, 1.0f };glClearBufferfv(GL_COLOR, 0, green);// 赋值方式1//int  location = glGetUniformLocation(program, "out_color1");//glUniform4f(location, 1.0f, 1.0f, 1.0f, 1.0f);// 赋值方式2//glUniform4f(0, 1.0f, 1.0f, 1.0f, 1.0f);// 赋值数组GLfloat outColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };glUniform4fv(0, 1, outColor);glUseProgram(program);glDrawArrays(GL_TRIANGLES, 0, 3);
}

在这里插入图片描述

很简单的一个例子,我们通过glUniform4fglUniform4fv方法,给outColor赋值,得以给三角形绘制指定颜色


♠ 一致区块

我们已经了解到统一变量的定义、赋值和使用,但是仅仅是单一变量,还有种高级点的用法,可以将很多的统一变量组合成一个区块,称之为一致区块


♥ 定义

以下声明了一个名为TransformBlock的一致区块

uniform TransformBlock{float scale;vec3 translation;float rotation[3];mat4 projection_matrix;
};			

♥ 数据布局

命名好的区块会被写入到缓冲当中,在缓冲中,区块的数据布局可能不同,有两种数据布局

  • 标准的、共识的数据布局(标准布局)

由于区块中的数据不同,占用的空间不同,该布局会根据每个统一变量的空间占用去存储

  • OpenGL自己决定数据的布局方式(shared布局)

OpenGL自己决定存储方式,用之前并不知道各个数据位置,运行的时候需要先查询数据布局格式


♣ 标准布局

推荐使用标准布局,以下是标准布局的声明方式,需要用到限定符std140去声明一致区块

layout uniform (std140) TransformBlock{	float scale;vec4 color;
};							

使用标准布局最重要的一点是我们需要知道区块内的统一变量,在缓存中的数据位置,我们简单理解一下数据的分布规则

  • 每个类型都有固定长度
  • 数据的起始点必须是其固定长度的倍数

我们以上边声明的TransformBlock为例来简单介绍一下

  • 类型float的长度是4,起始点是0,scale需要四个字节,所以结束位置4
  • 类型vec4的长度是16,因为前4位已被占用,并且4不是16的倍数,所以translation在缓冲的起始点只能是16,需要16个字节,在32结束

♥ 数据缓冲

区块的缓冲和我们之前学习的缓冲类似,结构基本一致,分为以下几个步骤

  • 创建和绑定缓冲
unsigned int ubo;
glGenBuffers(1, &ubo);
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
  • 分配内存
glBufferData(GL_UNIFORM_BUFFER, 4*8, NULL, GL_STATIC_DRAW);
  • 将缓冲区对象内的范围绑定到索引的缓冲区目标
glBindBufferRange(GL_UNIFORM_BUFFER, 0, ubo, 0, 4 * 8);
  • 更新数据
glBufferSubData(GL_UNIFORM_BUFFER, 0, 4 * 4, sColor);

♥ 完整示例

我们来看一个完整的演示示例吧,很简单,我们只通过区块内的统一变量去给三角形上色

注:该例子直接修改OpenGl超级宝典官方示例singletri.cpp,只需修改startup方法即可

virtual void startup()
{static const char * vs_source[] ={"#version 450 core                                                 \n""                                                                  \n"" 																   \n""void main(void)                                                   \n""{                                                                 \n""    const vec4 vertices[] = vec4[](vec4( 0.25, -0.25, 0.5, 1.0),  \n""                                   vec4(-0.25, -0.25, 0.5, 1.0),  \n""                                   vec4( 0.25,  0.25, 0.5, 1.0)); \n""                                                                  \n""    gl_Position = vertices[gl_VertexID];                          \n""}                                                                 \n"};static const char * fs_source[] ={"#version 450 core                                                 \n""                                                                  \n""layout (std140) uniform color_block							   \n""{                                                                 \n""    vec4 out_color;                                               \n""};                                                                \n""                                                                  \n""out vec4 color;                                                   \n""                                                                  \n""void main(void)                                                   \n""{                                                                 \n""    color = out_color;										       \n""}                                                                 \n"};program = glCreateProgram();GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fs, 1, fs_source, NULL);glCompileShader(fs);GLuint vs = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vs, 1, vs_source, NULL);glCompileShader(vs);glAttachShader(program, vs);glAttachShader(program, fs);glLinkProgram(program);glGenVertexArrays(1, &vao);glBindVertexArray(vao);GLfloat sColor[] = { 1.0f, 0.5f, 0.0f, 1.0f };unsigned int ubo;glGenBuffers(1, &ubo);glBindBuffer(GL_UNIFORM_BUFFER, ubo);glBufferData(GL_UNIFORM_BUFFER, 4*8, NULL, GL_STATIC_DRAW);glBindBufferRange(GL_UNIFORM_BUFFER, 0, ubo, 0, 4 * 8);glBufferSubData(GL_UNIFORM_BUFFER, 0, 4 * 4, sColor);
}

要点1:在该片段着色器中我们声明了一个标准区块color_block,其存有唯一变量out_color,该变量会作为三角形颜色被赋值

要点2:自定义颜色sColor,作为数值通过glBufferSubData接口更新到了区块内,以下是最终显示效果

在这里插入图片描述


♠ 推送

  • Github
https://github.com/KingSun5

♠ 结语

若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。

👉 本文属于原创文章,转载请评论留言,并在转载文章头部著名作者出处👈
http://www.lryc.cn/news/1638.html

相关文章:

  • 数据存储技术复习(四)未完
  • Rust编码的信息窃取恶意软件源代码公布,专家警告已被利用
  • diffusers编写自己的推理管道
  • 计算机操作系统 左万利 第二章课后习题答案
  • CODESYS开发教程10-文件读写(SysFile库)
  • Linux安装redis
  • 计算机组成与体系结构 性能设计 William Stallings 第2章 性能问题
  • anaconda详细介绍、安装及使用(python)
  • 雅思经验(6)
  • CentOS9源码编译libvirtd工具
  • 搭建内网穿透
  • vue3组件库项目学习笔记(八):Git 使用总结
  • ISO7320FCQDRQ1数字隔离器LMG1025QDEETQ1半桥GaN驱动器
  • openmmlab 语义分割算法基础
  • 2023年深圳/东莞/惠州CPDA数据分析师认证报名入口
  • RabbitMQ-客户端源码之AMQChannel
  • 注意力机制(SE,ECA,CBAM) Pytorch代码
  • Vue2笔记03 脚手架(项目结构),常用属性配置,ToDoList(本地存储,组件通信)
  • Java程序的执行顺序、简述对线程池的理解
  • 【前言】嵌入式系统简介
  • React设计原理—1框架原理
  • (C00034)基于Springboot+html前后端分离技术的宿舍管理系统-有文档
  • Flink面试题
  • Python学习笔记
  • 最适合入门的100个深度学习实战项目
  • AssertionError: 618 columns passed, passed data had 508 columns【已解决】
  • 166_技巧_Power BI 窗口函数处理连续发生业务问题
  • 电子科技大学人工智能期末复习笔记(五):机器学习
  • 使用DDD指导业务设计的总结思考
  • 面试官问:如何确保缓存和数据库的一致性?