为什么为一个属性指定不同的顶点格式?

时间:2015-03-19 11:17:40

标签: c++ opengl glsl

OpenGL函数glVertexAttribPointerglVertexAttribFormat允许用户指定在渲染时将绑定到着色器程序中给定属性变量的数据格式。顶点属性格式是数据类型(intfloatbyte等),属性变量中维度的数量(vec2,{{1}等等,是否应该对数据进行归一化,以及为数据数组的起始位置偏移到顶点数组中。这些函数指定构建顶点数组对象(VAO)时的格式,并且指定的格式是VAO状态的一部分。所以这是我的问题:

为什么与属性关联的数据格式是VAO状态的一部分,而不是属性状态的一部分?换句话说,为什么与VAO相关的数据格式而不是属性?在什么情况下,我会为同一属性使用不同格式的VAO?

为了更清楚,这里有一个例子可以说明为什么我感到困惑。想象一下,在我的顶点着色器中,我声明了变量:

vec3

现在我在OpenGL应用程序中获取属性位置:

in vec3 position;

现在,当我创建VAO时,我指定了这样的数据格式:

GLint positionAttribute = glGetAttribLocation(myProgram, "position");

由于格式与VAO相关联,因此每次创建VAO时都必须指定格式。 'position'属性为glVertexAttribFormat(positionAttribute​, 3, GL_FLOAT, GL_FALSE​, 0); ,因此我将始终指定3和vec3GL_FLOAT。那么为什么OpenGL以这种方式设计,所以每次创建VAO时我都可能需要调用glVertexAttribFormat,并指定一个保持不变的格式?在我看来,当我调用glVertexAttribFormat时我应该指定格式,所以我只做了一次。

4 个答案:

答案 0 :(得分:2)

问问自己,当他们不匹配时会发生什么。

这允许指定与着色器内使用本身不同的存储数据结构。所以说你存储打包的rgba8,你仍然可能想用它做浮点数学运算。所以你在着色器中将它声明为vec4,但是使用RGBA8作为顶点数据格式。 GL将为您完成2种格式之间的转换。

答案 1 :(得分:1)

嗯,每个API都会做出设计决策。大多数情况下,不仅有一种方法可以完成给定的任务,在某种程度上,这只是在这种情况下定义的方式。

我对此背后的决策没有任何直接的了解,但可以考虑一些为这一点提供有效动机的考虑因素。

  • 没有着色器的操作:OpenGL已经发展了很长时间。着色器最初不是API的一部分,并且仍然可以在没有着色器的情况下运行API的版本(兼容性配置文件)。如果没有着色器,那么从着色器属性中获取属性类型的想法根本不起作用。

  • 支持与GLSL类型不对应的数据类型:在着色器中使用vec4,在属性规范中使用GL_FLOAT时最常见,这不是唯一的选择。例如,属性可以指定为GL_HALF_FLOAT或疯狂格式,例如GL_INT_2_10_10_10_REV。如果您真的想为顶点数据保存内存,这些格式可能会有用。或者,如果您已经具有此格式的顶点,例如,因为您正在移植支持它们的Direct3D代码。这些格式不直接对应于GLSL中的类型,因此如果不明确指定属性类型,则无法支持它们。

  • 顶点设置状态和程序状态之间的依赖关系:这更具概念性。它现在的工作方式,顶点设置状态和程序状态是正交的。避免 依赖的概念之间的依赖关系始终是一个很好的设计目标。如果顶点属性格式取决于当前绑定的程序,则会破坏此独立性。例如,当绑定新程序时,顶点属性数据的解释可能会发生变化,这意味着必须更新顶点设置状态。由于产生的复杂性和低效率,这些类型的状态依赖性是非常不可取的。

答案 2 :(得分:0)

那么如果您有多个属性会发生什么?或者如果你想存储位置,颜色和法线怎么办?根据我的经验,这特别适用于UV坐标。

因为那时你的属性只有2而不是3.因为你的纹理只有2个坐标(忽略3D纹理的可能性)。如果你在2D工作怎么办? attrib指针允许您指定该属性的输入大小,而不是其他任何类型。它很有用,因为它允许您更改数据的格式。在任何情况下,您应该只创建一次VAO,除非您需要将新数据重新绑定到缓冲区。

答案 3 :(得分:0)

  在我看来,我应该指定格式

嗯不,你没有指定任何格式,你刚刚获取了一个属性位置。

选择它只是因为GL在

方面给你很大的灵活性
  1. 将其他数据类型转换为浮动
  2. 传递具有不同大小的向量
  3. 规范化非浮动类型
  4. 为属性使用交错的非零偏移缓冲区
  5. 这只能“部分”自动化。当然,你可以对着色器进行内省,并确定你的属性确实是vec3,所以有3个浮点数,但这仍然没有告诉GL顶点数组缓冲区对象中的数据是什么样的。值得注意的是,它允许包含

    • 其他兼容类型(请注意,glVertexAttribPointer / glVertexAttribFormat可以采用多种不同类型,而不仅仅是GL_FLOAT
    • 维度较低的数据(谁告诉GL?)
    • 交错数据(告诉GL什么是跨步?)
    • 非零偏移的数据(谁告诉GL什么是基本偏移?)
    • 可能需要或可能不需要规范化的数据(谁告诉GL?)

    回答“谁告诉”:您致电glVertexAttribFormat