您的位置:首页 > 运维架构

OpenGL核心理解:Uniform

2020-02-02 11:45 1871 查看

简介:

着色器的变量主要包含如下:

  • 顶点属性(Vertex Attributes): 顶点着色器:输入
  • 统一变量(Uniform Variables):
      所有着色器:输入
  • 采样器(Samplers):
      片段着色器:输入
  • Varying Variables:
      顶点着色器:输出
    • 片段着色器:输入

    这里我们要介绍的是统一变量

    一. Uniform 是什么

    统一变量是着色器程序(Program)特定的变量,在整个着色器程序的执行过程中(单次渲染:各种着色器),和多个物体执行中(多次渲染),都可以访问并可以保持一致(如果不主动设置,如多个物体的渲染中光源属性)。之所以叫统一,主要区别于其他变量:

    • 顶点属性:仅顶点着色器可以访问,每次渲染数据基本不同(每物体顶点不同)
    • Varying Variables:由顶点着色器创建,输出到片段着色器,每片段着色器不同
    • 采样器:属于 Uniform

    二. Uniform 有什么作用

    统一变量主要用于为各种渲染类型(着色器)提供控制与输入

    • 控制 开关:用于切换功能开启。比如gamma矫正,模糊效果的开关。。。
    • 摄像机: 用于控制镜头。比如模型,视图,投影矩阵。。。
  • 输入
      材质:用于表达材质的属性。比如粗糙度,金属度。。。
    • 光源属性:用于表述光源的性质。比如位置,强度,颜色。。。

    三. 什么时候使用?

    一般在场景的初始时需要使用uniform,用于光源设置。更新时需要设置的情况如下:

    • 操作摄像机时
    • 渲染物体,或动态材质变化时
    • 动态光源变化时

    四. 如何使用?

    • 单项设置
        获取位置:单项设置需要在着色器程序(Program)编译后,根据着色器中的变量名称获取相应位置,使用函数 glGetUniformLocation
      1. 同步数据(内存->显存):根据获取的位置,按照数据类型同步数据,使用函数 glUniform*,如 glUniform1f
    • 批量同步(使用 统一变量块:Uniform Block)
        获取位置:需要在着色器程序(Program)编译后,根据 统一变量块 在着色器中的名称获取索引,使用函数 glGetUniformBlockIndex
      1. 绑定到统一变量缓冲(类似于顶点缓冲,是显存中的一块数据),使用函数 glUniformBlockBinding 将着色器的 统一变量块 绑定到指定序号的统一变量缓冲中
      2. 同步数据:这里区别于单项设置,是将数据同步到缓冲中。由于是绑定,可以多个着色器绑定到同一缓冲中,所以只需要操作一次,并且可以整块数据同步。使用函数 glBufferSubData

    五. 实例

    • 单项设置
        先在着色器中添加变量
      uniform mat4 project;
      1. 根据添加的名称在代码中获取位置, program 是已编译的着色器程序
      int32_t location = glGetUniformLocation(program, "project");
      1. 同步数据,这里使用了 glm
      glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(project));
    • 批量同步 批量同步有些复杂,首先它需要在显存创建缓冲区,并且同步数据时需要选择数据的布局方式,不同的布局数据的对齐方式不同,这就导致了同步数据时方案的不同,这里我使用了std140 (内存中的变量对齐与显存中变量对齐存在差异) 它的每个成员变量都有一个基础偏移(距离结构体起始地址的偏移量),和一个基础对齐(变量占用的空间需要对齐)。
    • 根据基础偏移量计算基础对齐(就是说成员变量的顺序会影响每个变量占用的空间大小),方法是将基础偏移舍入到基础对齐的整数倍(下一个变量的偏移量等于当前变量基础对齐的N倍,细节请查询参考手册)。
    • 统一变量缓冲块的对齐,假如想使用一个缓冲存储多块(还可以创建多个缓冲,但都使用0号统一变量块),它也会产生一个对齐。可以通过查询系统信息获取对齐大小
    GLint BlockAlienment = 0;
    glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &BlockAlienment);
  • 项目链接
      Opengl教程 该项目需要使用 premake 生成VS项目, 如果不了解可以看下前文链接

    参考手册:OpenGL 官方手册

    前文链接:c++ 轻量跨平台构建系统 Premake

    • 点赞
    • 收藏
    • 分享
    • 文章举报
    五谷延年 发布了6 篇原创文章 · 获赞 0 · 访问量 687 私信 关注
  • 内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: