C++ With OpenGL学习随记-uniform block

OpenGL对于Uniform block有两种布局方式:

1、标准布局

2、共享布局

        标准布局是由开发者在着色器中定义Uniform block的位置值,需要C++程序使用glMapBuffer来向该Uniform block缓存中写入数据,这个布局成员之间会“留空”,会导致失去一些性能和存储空间。使用标准布局好处就是易实现,c++程序不需要做较多的工作就可以刷数据到着色器缓存中,但是会损失一些性能。

        共享布局是就是由OpenGL自己安排uniform block的位置值,c++程序需要去明确uniform block的各个成员位置值才能从着色器中读取数据,并且需要向OpenGL指定数据的存储位置,让OpenGL去读取数据并且布置数据到uniform block中,共享布局还可以让各个着色器程序共享同个uniform block。使用共享布局的好处是高性能,但是使用起来较为复杂。

        标准布局的一个例子就是使用std140布局,先出例子:

layout(std140) uniform TransformBlock
{
    float scale;         //缩放因子
    vec3 translation;     //平移向量
    float rotation[3];     // 旋转轴
    mat4 projection_matrix; // 投影矩阵(在缩放、平移旋转变换之后应用)
} transform;

        语法就是布局限定符layout(标准布局版本),前面说标准布局会留空这是为啥呢,这主要是由于标准布局规定的对齐规则导致的:

        1、在uniform类型中vec2是八字节对齐的但总的uniform类型还是按16字节对齐

        2、除了vec4或者N*4的矩阵外其他数据类型都是按照16字节对齐

        上述例子对齐规则后偏移量就是:

scale                0
translation          16
rotation             16+16
projection_matrix    16+16+16*3

        标准布局也可以使用布局限定符offset自定义偏移量,但是这个自定义的偏移量还是要遵守上述的对齐规则,继续直接上例子:

layout(std140) uniform ManuallyLaidOutBlock
{
    layout (offset = 32) vec4 foo; // At offset 32 bytes
    layout (offset = 8) vec2 bar; // At offset 8 bytes
    layout (offset = 48) vec3 baz; // At offset 48 bytes
} myBlock;

        这里主要是第二个成员bar,vec2八字节对齐符合规则一,则没啥问题,但是它在内存中所处的起始是在foo变量前了,bar在内存的8字节处,foo在内存的32字节处,也就是说offset能让成员变量在内存所在的位置顺序和uniform块类型声明的顺序不同。

        接着还有另一个对齐限定符要讲,就是align,这个限定符主要是用来调整整个uniform块各个成员的对齐方式,上例子:

layout (std140, align = 16) uniform ManuallyLaidOutBlock
{
    layout (offset = 32) vec4 foo; // At offset 32 bytes
    layout (offset = 8) vec2 bar; // At offset 16 bytes
    layout (offset = 48) vec3 baz; // At offset 48 bytes
} myBlock;

        这里已经确定了整块的成员对齐方式都是16字节,offset对各个成员的偏移再进一步调整,可是此时bar指定的是八字节偏移,并不是16字节的倍数,所以bar的起始会在16字节处偏移。同样的bar在内存中是在foo变量前的。

        接着再聊聊共享布局,共享布局uniform block声明是比较简单的,因为是OpenGL的默认布局,只需要直接声明:

uniform block
{
	float scale;
    ...
}sharedBlock;

        共享布局是让OpenGL自动为uniform block进行布局,OpenGL自动设计的布局会相比标准布局会稍微高效,但是需要的操作却会比较多,主要集中在外部程序向uniform block变量赋值的过程。

        首先,需要获取uniform block中各个成员的索引,再根据索引去获取各个成员在内存布局中的信息,比如偏移量、数组步长、矩阵步长等。

        获取uniform block中各个成员的索引的OpenGLAPI是

void glGetUniformIndices(GLuint program,
                         GLsizei uniformCount,
                         const GLchar ** uniformNames,
                         GLuint * uniformIndices);

        第一个参数是GLSL的程序对象,第二个是uniform成员变量的个数,第三个是要获取的uniform成员变量字符串数组,第四个是用于获取uniform成员变量的索引数组。

        接着使用获取到 索引数组再调用glGetActiveUniformsiv获取uniform变量信息:

void glGetActiveUniformsiv(GLuint program,
                           GLsizei uniformCount,
                           const GLuint * uniformIndices,
                           GLenum pname,
                           GLint * params);

        首先是GLSL的程序对象,接着是uniform成员变量的个数,第三个是uniform成员变量的索引数组,第四个是要获取的信息类型,如偏移量是GL_UNIFORM_OFFSET,数组步长是GL_UNIFORM_ARRAY_STRIDE,矩阵步长是GL_UNIFORM_MATRIX_STRIDE,最后一个是用于接收所需值的数组。

        关于OpenGL的布局就先到这,下一篇继续一起学习共享布局吧

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值