【OpenGL手册12】 统一变量Uniform

2024-03-09 01:36

本文主要是介绍【OpenGL手册12】 统一变量Uniform,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

OpenGL基础 - 统一变量Uniform

目录

  • 一、说明
  • 二、 Uniform变量概念
    • 2.1 Uniform变量和特点
    • 2.2 Uniform变量定义方法
    • 2.3 Uniform变量赋值和传参
  • 三、如何在Shader中自定义Location
  • 四、赋值
  • 五、统一变量缓冲对象
  • 六、赋值函数

一、说明

   关于统一变量,也有一系列概念和方式,如果不加以梳理,迟早将陷入泥藻之中,本篇将梳理全套的有关Uniform的描述,汇集起来当作手册备用。

二、 Uniform变量概念

2.1 Uniform变量和特点

   OpenGL基础: Uniform变量 ,即统一变量。简单理解就是一个GLSL shader中的全局常量,特点是:

  •    可以随意在任意shader(vertex shader, geometry shader, or fragment shader)访问,不同的shader中uniform是一起链接的。
  •    初始化之后,不能修改其值,否则会引起编译错误。
  •    是CPU一侧直接赋值给GPU的变量。

2.2 Uniform变量定义方法

   1 定义以及使用Uniform变量的方法:
在着色器内定义接受变量

vertex shader#version 400
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;
out vec3 outColor;
uniform mat4 wmat;
void main()
{Color = color;gl_Position = wmat * vec4(position, 1.f);
}

2.3 Uniform变量赋值和传参

1 ) 值传
   使用Uniform的定义一个向量,可以通过location设置Unfirom值,外部CPU程序代码中写:

glm::mat amat; // define a mat, and give it any value you need.
...
GLuint loc = glGetUniformLocation(program, "wmat");
if (loc >= 0) // if fail, loc == -1
{glUniformMatrix4fv(loc, 1, GL_FALSE, &amat[0][0]);
}
  • “wmat”:是着色器的对应变量。
  • glUniformMatrix4fv:此为执行赋值函数。

2)数组传递
   如果是Uniform数组(由vecx元素组成)也可以直接这样获取location:

GLSL中定义:

uniform vec3 Array[10];

C++客户端程序获取指针:

GLuint loc = glGetUniformLocation(program, "Array[1]");

3)结构传递
   如果是Uniform Struct,也可以类似地直接获取

GLSL中定义:

struct aStruct
{vec3 lightPos;vec4 lightColor;mat4x3 otherMat;
}myStruct;

   C++客户端程序获取(注意前缀名字是myStruct,不是aStruct):

   GLuint loc = glGetUniformLocation(program, “myStruct.lightPos”)
这个名字变量的获取风格类C了,对于C程序员十分友好。

   其实就是定义在GLSL中的一个结构体Struct

例子:

uniform MyBlock // 定义在shader中
{vec4 color1;vec4 color2;float r1;float r2;
}myBlock;

三、如何在Shader中自定义Location

   就是在Shader中自定义一个uniform的location:

layout(location = 2) uniform mat4 worldMat;

   这样在C++客户端程序中就可以直接赋值,无需要寻址了

glUniformMatrix4fv(2, 1, GL_FALSE, &worldMat[0][0]);
不过这种自定义location,需要十分小心,如果赋予两个uniform同样的location,那就会产生链接错误。

   尤其是同时赋予多个uniform location的时候要注意:

layout(location = 2) uniform vec4 aVec[8];

   那么aVec的uniform location值范围是[2, 10)

   所以如果这样定义:

layout(location = 2) uniform vec4 aVec[8];
layout(location = 5) uniform mat4 aMat[2];

   那么就是非法的,会引起链接错误。因为,aVec占用了【2-10】,aMat只能从11开始。

四、赋值

   可以给uniform赋予默认值,如果C++客户端没有给uniform值得时候,GLSL会预先给出默认值,当客户端赋值时,默认值被冲掉:

uniform vec4 greenColor = vec4(0.0, 1.0, 0.0, 1.0);
uniform vec3 vers[4] = vec3[](vec3(0.3, -0.8, 0.1),vec3(0.2, 1.0, 0.2),vec3(0.6, -1.0, 0.3),vec3(0.9, 0.7, 0.4));

五、统一变量缓冲对象

   这是高级用法:统一变量缓冲对象 – Uniform buffer object
   这个用法稍微有点难,坑比较多的,所以,建议初学者可以暂时跳过,因为一开始学OpenGL,应该暂时不需要使用,使用前面的方法操作Uniform应该就足够了。

   这里先抛砖引玉,简单举例应用一下,一些小坑,小知识点不详细展开,会后续教程中补全的,还会专门讲这个用法。当然,看完下面这一段也足够可以使用这个知识点了。

   这个是OpenGL客户端程序和GLSL中的Uniform变量对应的对象,也可以是和变量块Uniform block, 变量数组Uniform array对应。

   目的是为了方便在OpenGL客户端操作(修改值)GLSL的Uniform对象,尤其是一组uniform值得时候,更加方便修改。

   例如在GLSL中定义:

layout (std140, binding = 0) uniform MATS
{mat4 mvMat;vec3 aPos;
};
layout (std140, binding = 1) uniform MAT_BLOCK
{mat4 matPool[120];
};
在C++客户端程序中修改:// 第一个(binding = 0):
struct ABlock
{glm::mat4     aMatrix;glm::vec3     pos;
};
glGenBuffers(1, &aMapBuffer);
glBindBuffer(GL_UNIFORM_BUFFER, aMapBuffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(ABlock), NULL, GL_DYNAMIC_DRAW);// Careful: The parameter 0: is correspondant to binding = 0; not location.
// 0 是对应 GLSL中的bingding = 0; 不是location = 0
glBindBufferBase(GL_UNIFORM_BUFFER, 0, aMapBuffer);ABlock* mapBlock = (ABlock*)glMapBufferRange(GL_UNIFORM_BUFFER,0,sizeof(ABlock),GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);mapBlock->aMatrix = glm::mat(1); // set any value you want here to GLSL
mapBlock->pos = glm::vec3(1); // set any value you want here to GLSL
glUnmapBuffer(GL_UNIFORM_BUFFER);// 第二个(binding = 1)
struct MatPool
{glm::mat4     viewMat;glm::mat4     worldMat;glm::mat4     modelMat
};glGenBuffers(1, &matBuffer);
glBindBuffer(GL_UNIFORM_BUFFER, matBuffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(MatPool), NULL, GL_DYNAMIC_DRAW);// Careful: The parameter 1: is correspondant to binding = 1; not location.
// 1 是对应 GLSL中的bingding = 1; 不是location = 1
glBindBufferBase(GL_UNIFORM_BUFFER, 1, uniforms_buffer);
MatPool* mBlock = (MatPool*)glMapBufferRange(GL_UNIFORM_BUFFER,0,sizeof(MatPool),GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
glm::mat4 modelMat = glm::mat(1);
glm::mat4 viewMat = glm::mat(1);
glm::mat4 worldMat = glm::mat(1);
mBlock->viewMat = viewMat;
mBlock->worldMat = worldMat;
mBlock->modelMat = modelMat;
glUnmapBuffer(GL_UNIFORM_BUFFER);

   第二个设置的时候,可以看到C++客户端的Struct结构和GLSL的结构体是不一样的,C++客户端是三个mat4的结构体,GLSL是一个结构体数组,我故意举这样的例子,是为了说明只要数据对应就行了,不一定要格式严格对应。

   GLSL中利用binding设置索引位置,可以使用多个Uniform block绑定到客户端使用,当然也可以使用下面函数取得这个索引位置,就可以不在GLSL中明显声明,即可以省略binding = 0;由GLSL自动分配索引位置。

GLuint glGetUniformBlockIndex( GLuint program, const char *uniformBlockName );

   还有其他各种用法,其实就没有那么实用了,这里就不贴出来,可以根据需要的时候,再进一步查阅。

六、赋值函数

   可以使用glUniform*这个函数来设置不同值类型的uniform,OpenGL的设计风格是使用不同类型的后缀变形函数来设置,参考All kinds of set up uniform value examples:

   GLAPI/glUniform - OpenGL Wiki
​www.khronos.org/opengl/wiki/GLAPI/glUniform
   这里摘录一些,摘录这些的原因是只要知道这些赋值方法,那么其他类值得赋值方法也能推演出来:

glUniform1i(loc, (int)value); // setup uniform one int value
void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
void glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2);void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);

更多的函数形式

函数参数1参数2参数3参数4参数5
void glUniform1f( GLint location,GLfloat v0);
void glUniform2f( GLint location,GLfloat v0,GLfloat v1);
void glUniform3f( GLint location,GLfloat v0,GLfloat v1,GLfloat v2);
void glUniform4f( GLint location,GLfloat v0,GLfloat v1,GLfloat v2,GLfloat v3);
void glUniform1i( GLint location,GLint v0);
void glUniform2i( GLint location,GLint v0,GLint v1);
void glUniform3i( GLint location,GLint v0,GLint v1,GLint v2);
void glUniform4i( GLint location,GLint v0,GLint v1,GLint v2,GLint v3);
void glUniform1ui( GLint location,GLuint v0);
void glUniform2ui( GLint location,GLuint v0,GLuint v1);
void glUniform3ui( GLint location,GLuint v0,GLuint v1,GLuint v2);
void glUniform4ui( GLint location,GLuint v0,GLuint v1,GLuint v2,GLuint v3);
void glUniform1fv( GLint location,GLsizei count,const GLfloat *value);
void glUniform2fv( GLint location,GLsizei count,const GLfloat *value);
void glUniform3fv( GLint location,GLsizei count,const GLfloat *value);
void glUniform4fv( GLint location,GLsizei count,const GLfloat *value);
void glUniform1iv( GLint location,GLsizei count,const GLint *value);
void glUniform2iv( GLint location,GLsizei count,const GLint *value);
void glUniform3iv( GLint location,GLsizei count,const GLint *value);
void glUniform4iv( GLint location,GLsizei count,const GLint *value);
void glUniform1uiv( GLint location,GLsizei count,const GLuint *value);
void glUniform2uiv( GLint location,GLsizei count,const GLuint *value);
void glUniform3uiv( GLint location,GLsizei count,const GLuint *value);
void glUniform4uiv( GLint location,GLsizei count,const GLuint *value);
void glUniformMatrix2fv( GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);
void glUniformMatrix3fv( GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);
void glUniformMatrix4fv( GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);
void glUniformMatrix2x3fv( GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);
void glUniformMatrix3x2fv( GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);
void glUniformMatrix2x4fv( GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);
void glUniformMatrix4x2fv( GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);
void glUniformMatrix3x4fv( GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);
void glUniformMatrix4x3fv( GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);
  1. 参考:

这篇关于【OpenGL手册12】 统一变量Uniform的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/789130

相关文章

java如何调用kettle设置变量和参数

《java如何调用kettle设置变量和参数》文章简要介绍了如何在Java中调用Kettle,并重点讨论了变量和参数的区别,以及在Java代码中如何正确设置和使用这些变量,避免覆盖Kettle中已设置... 目录Java调用kettle设置变量和参数java代码中变量会覆盖kettle里面设置的变量总结ja

Perl 特殊变量详解

《Perl特殊变量详解》Perl语言中包含了许多特殊变量,这些变量在Perl程序的执行过程中扮演着重要的角色,:本文主要介绍Perl特殊变量,需要的朋友可以参考下... perl 特殊变量Perl 语言中包含了许多特殊变量,这些变量在 Perl 程序的执行过程中扮演着重要的角色。特殊变量通常用于存储程序的

变量与命名

引言         在前两个课时中,我们已经了解了 Python 程序的基本结构,学习了如何正确地使用缩进来组织代码,并且知道了注释的重要性。现在我们将进一步深入到 Python 编程的核心——变量与命名。变量是我们存储数据的主要方式,而合理的命名则有助于提高代码的可读性和可维护性。 变量的概念与使用         在 Python 中,变量是一种用来存储数据值的标识符。创建变量很简单,

华为OD机试真题-学生方阵-2024年OD统一考试(E卷)

题目描述 学校组织活动,将学生排成一个矩形方阵。 请在矩形方阵中找到最大的位置相连的男生数量。这个相连位置在一个直线上,方向可以是水平的,垂直的,成对角线的或者呈反对角线的。 注:学生个数不会超过10000 输入描述 输入的第一行为矩阵的行数和列数, 接下来的 n行为矩阵元素,元素间用""分隔。 输出描述 输出一个整数,表示矩阵中最长的位

UML- 统一建模语言(Unified Modeling Language)创建项目的序列图及类图

陈科肇 ============= 1.主要模型 在UML系统开发中有三个主要的模型: 功能模型:从用户的角度展示系统的功能,包括用例图。 对象模型:采用对象、属性、操作、关联等概念展示系统的结构和基础,包括类图、对象图、包图。 动态模型:展现系统的内部行为。 包括序列图、活动图、状态图。 因为要创建个人空间项目并不是一个很大的项目,我这里只须关注两种图的创建就可以了,而在开始创建UML图

JS_变量

二、JS的变量 JS中的变量具有如下特征 1 弱类型变量,可以统一声明成var 2 var声明的变量可以再次声明 3 变量可以使用不同的数据类型多次赋值 4 JS的语句可以以; 结尾,也可以不用;结尾 5 变量标识符严格区分大小写 6 标识符的命名规则参照JAVA 7 如果使用了 一个没有声明的变量,那么运行时会报uncaught ReferenceError: *** is not de

使用条件变量实现线程同步:C++实战指南

使用条件变量实现线程同步:C++实战指南 在多线程编程中,线程同步是确保程序正确性和稳定性的关键。条件变量(condition variable)是一种强大的同步原语,用于在线程之间进行协调,避免数据竞争和死锁。本文将详细介绍如何在C++中使用条件变量实现线程同步,并提供完整的代码示例和详细的解释。 什么是条件变量? 条件变量是一种同步机制,允许线程在某个条件满足之前进入等待状态,并在条件满

linux dlopen手册翻译

名称 dlclose, dlopen, dlmopen 打开和关闭一个共享对象 简介 #include <dlfcn.h>void *dlopen(const char*filename, int flags);int dlclose(void *handle);#define _GNU_SOURCE#include <dlfcn.h>void *dlmoopen(Lmid_t lm

OPENGL顶点数组, glDrawArrays,glDrawElements

顶点数组, glDrawArrays,glDrawElements  前两天接触OpenGL ES的时候发现里面没有了熟悉的glBegin(), glEnd(),glVertex3f()函数,取而代之的是glDrawArrays()。有问题问google,终于找到答案:因为OpenGL ES是针对嵌入式设备这些对性能要求比较高的平台,因此把很多影响性能的函数都去掉了,上述的几个函数都被移除了。接

OpenGL ES学习总结:基础知识简介

什么是OpenGL ES? OpenGL ES (为OpenGL for Embedded System的缩写) 为适用于嵌入式系统的一个免费二维和三维图形库。 为桌面版本OpenGL 的一个子集。 OpenGL ES管道(Pipeline) OpenGL ES 1.x 的工序是固定的,称为Fix-Function Pipeline,可以想象一个带有很多控制开关的机器,尽管加工