【问题标题】:OpenGL Uniform Functions - Why so many?OpenGL 统一函数 - 为什么这么多?
【发布时间】:2016-07-19 11:01:57
【问题描述】:

为什么有这么多设置制服的功能?

glUniform1f    glUniform2f    glUniform3f    glUniform4f
glUniform1fv   glUniform2fv   glUniform3fv   glUniform4fv
glUniform1i    glUniform2i    glUniform3i    glUniform4i
glUniform1iv   glUniform2iv   glUniform3iv   glUniform4iv
glUniform1ui   glUniform2ui   glUniform3ui   glUniform4ui
glUniform1uiv  glUniform2uiv  glUniform3uiv  glUniform4uiv

glUniformMatrix2fv  glUniformMatrix2x3fv  glUniformMatrix2x4fv
glUniformMatrix3fv  glUniformMatrix3x2fv  glUniformMatrix3x4fv
glUniformMatrix4fv  glUniformMatrix4x2fv  glUniformMatrix4x3fv

我认为数据上传到顶点和元素缓冲区的方式更好,因为我不必为不同的类型调用不同的函数。 为什么制服会出现这种情况?有没有可能只使用一个函数,我可以只传递一个指针?

【问题讨论】:

  • 因为C不支持函数重载。
  • @LogicStuff 我认为 OP 在问为什么它不像 glUniform_(location, GL_FVEC4, 1, pointer),而是 glUniform4fv(location, 1, pointer)。实现这一点不需要函数重载。
  • @HolyBlackCat 完全正确!
  • @HolyBlackCat:但它有这个功能glUniform4fv 可以做你所做的。它只需要一个值:一个数组计数,对于非数组类型(或长度为 1 的数组)必须为 1。所以目前还不清楚 OP 在抱怨什么。
  • @NicolBolas:不只有一个glUniform(GLint location, GLenum datatype, GLsizei count, const GLvoid *data) 调用基于datatype 执行“正确的事情”。因此,如果您想加载一个包含两个 vec4 的数组,您可以执行 glUniform(loc, GL_FLOAT_VEC4, 2, ptr); 之类的操作(其中 ptr 指向 8 个浮点数)。

标签: c++ opengl glsl shader uniform


【解决方案1】:

事后诸葛亮总是 20/20,并且选择与其他采用各种类型和维度的矢量数据的函数保持一致。我指的是 glVertex ……当然。现在,按值传递的最初原因是,在某些架构上,周围有足够的寄存器,这样在寄存器中按值传递会更有效。编译器还可以优化前面的操作,以在正确的寄存器中结束正确的值。

OpenGL 是 SGI 为其图形工作站和 Irix 操作系统开发的 IrixGL 的后代。这些工作站使用 MIPS 架构。 MIPS 的调用约定是 (https://en.wikipedia.org/wiki/Calling_convention#MIPS)

32 位 MIPS 最常用的[5] 调用约定是 O32[6] ABI,它将前四个参数传递给寄存器 $a0-$a3 中的函数; …

N32 和 N64 ABI 将前八个参数传递给寄存器 $a0-$a7 中的函数; …

所以你有它:在 MIPS 上,每个值传递 vec4 元素实际上是一个非常明智的选择。尤其是在没有顶点数组的 IrixGL 和 OpenGL-1.0 中,您必须进行大量 glVertex 调用。

【讨论】:

    【解决方案2】:

    如果您使用的是现代 OpenGL,则可以使用自 OpenGL 3.1 起就可用的Uniform Buffer Objects

    但是,需要更多涉及的“设置”。具体来说,它们要求您以特定方式创作着色器(定义统一块)。您还需要为块定义内存布局(std140 是一种流行的布局),或者查询布局,以确定应如何格式化统一缓冲区数据,以便绑定与预期的格式相匹配GPU。

    完成所有设置后,通过调用glBindBuffer(GL_UNIFORM_BUFFER, <name>) 完成绑定,就像顶点和索引流一样。

    【讨论】:

    • 这似乎是一个可能的解决方案,它可能比迭代大约 20 个 if 语句更有效。我会调查一下。谢谢。
    【解决方案3】:

    在讨论GL_ARB_shader_objects时注意到了这一点:

    15) 负载均匀性可能会出现巨大的爆炸式增长 命令,怎么办?

    讨论:我们需要能够加载 vec1、vec2、vec3 或 vec4,或者 vec1 数组、vec2 数组、vec3 数组或 vec4 数组。 此外,还需要加载 2x2、3x3 和 4x4 矩阵, 和 2x2 的数组、3x3 的数组和 4x4 矩阵的数组。输入 加载制服命令的值可以(传统的 OpenGL)进来 字节,短裤,整数,浮点数,双精度和无符号字节,无符号短裤 和无符号整数。

    解决方案:建议的子集在新过程和函数中 下面的部分。

    有问题的子集是获得批准的子集:

    void Uniform1fARB(int location, float v0)
    void Uniform2fARB(int location, float v0, float v1)
    void Uniform3fARB(int location, float v0, float v1, float v2)
    void Uniform4fARB(int location, float v0, float v1, float v2, float v3)
    
    void Uniform1iARB(int location, int v0)
    void Uniform2iARB(int location, int v0, int v1)
    void Uniform3iARB(int location, int v0, int v1, int v2)
    void Uniform4iARB(int location, int v0, int v1, int v2, int v3)
    
    void Uniform1fvARB(int location, sizei count, const float *value)
    void Uniform2fvARB(int location, sizei count, const float *value)
    void Uniform3fvARB(int location, sizei count, const float *value)
    void Uniform4fvARB(int location, sizei count, const float *value)
    
    void Uniform1ivARB(int location, sizei count, const int *value)
    void Uniform2ivARB(int location, sizei count, const int *value)
    void Uniform3ivARB(int location, sizei count, const int *value)
    void Uniform4ivARB(int location, sizei count, const int *value)
    
    void UniformMatrix2fvARB(int location, sizei count, boolean transpose, const float *value)
    void UniformMatrix3fvARB(int location, sizei count, boolean transpose, const float *value)
    void UniformMatrix4fvARB(int location, sizei count, boolean transpose, const float *value)
    

    后来添加了对无符号整数和非方阵的调用。

    我认为@datenwolf 的说法是正确的,即glVertex 系列调用具有许多功能以优化寄存器中的值传递,另一方面,设置制服应该少几个数量级通常比传递顶点,所以我不认为这里的性能是一个真正的问题。

    “遵循已经建立的 API”听起来像是一个更明智的解释。


    此外,您真的喜欢通过void * 接口传递数据类型吗?你要问的是一个类似于

    的API
    glUniform(GLint location, GLenum datatype, GLsizei count, const GLvoid *data)
    

    GL 已经充满了这种级别的中断和类型不安全(你好,无类型的GLenums!),我更喜欢不添加更多这些的 API。

    【讨论】:

    • 我更喜欢你最后提到的 API 类型。要记住的函数更少,我可以将下一个绘制调用的所有制服设置在一个缓冲区中,并且我不必将类型与函数相关联(更少的 if 语句)
    • “要记住的函数更少”是没有问题的。没有人会通过 glGetError 检查的编译时错误而不是运行时(静默)错误,以及检查您传递的参数是否有意义的相对成本肯定会更大。如果你想要更少的函数,使用 C++ 和重载?
    【解决方案4】:

    硬件需要做什么取决于统一的数据格式可能会有所不同。

    您要问的是潜在的 switch/if 系列是在 GL 驱动程序中实现的。然后,您必须为每次使用 API 支付费用,即使应用程序已经确切知道它将设置哪种类型的制服。这不会是一种高效的 API 设计(尽管实际上传递制服缓冲区的效率现在要高得多。设计该 API 时并非如此)。

    这就是 glVertex3f 等人的原因。也有那个 API 设计。但至少那些没有产生glErrors。 Uniforms 有点脆弱,因为它们肯定会产生错误,因此代码不能真正完全最小化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-11
      • 1970-01-01
      • 2023-04-05
      • 2011-04-15
      相关资源
      最近更新 更多