tl;dr:这是一个驱动程序错误。核心 OpenGL 3.3 应该允许您不使用属性 0,但兼容性配置文件不允许,并且某些驱动程序无法正确实现该开关。只需确保使用属性 0 即可避免出现任何问题。
实际内容:
让我们上一堂历史课,了解 OpenGL 规范是如何诞生的。
在 OpenGL 最古老的时代,只有一种渲染方式:立即模式(即:glBegin/glVertex/glColor/glEtc/glEnd
)。显示列表是存在的,但它们始终被定义为简单地再次发送捕获的命令。因此,虽然实现实际上并未进行所有这些函数调用,但实现的行为仍然就像它们进行了一样。
在 OpenGL 1.1 中,客户端顶点数组被添加到规范中。现在记住:规范是指定的文档behavior,而不是实施。因此,ARB 简单地定义客户端数组的工作方式与进行立即模式调用完全相同,使用对当前数组指针的适当访问。显然,实现实际上不会这样做,但它们的行为却好像这样做了。
基于缓冲区对象的顶点数组以相同的方式定义,但由于从服务器存储而不是客户端存储中提取,语言稍微复杂一些。
然后发生了一些事情:ARB_vertex_program(不是ARB_vertex_shader。我说的是汇编程序)。
看,一旦有了着色器,您就希望能够开始定义自己的属性,而不是使用内置属性。这一切都是有道理的。然而,有一个问题。
立即模式的工作原理如下:
glBegin(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glEnd();
每次你打电话glVertex
,这会导致所有当前属性状态都用于单个顶点。所有其他立即模式函数只是将值设置到上下文中;这个功能实际上sendsOpenGL 中要处理的顶点。这在即时模式下非常重要。由于每个顶点都必须在固定功能区域中拥有一个位置,因此使用此函数来决定何时应处理顶点是有意义的。
一旦不再使用 OpenGL 的固定功能顶点语义,立即模式就会出现问题。也就是说,你如何决定何时真正send顶点?
按照惯例,他们将其粘贴到属性 0 上。因此,所有立即模式渲染必须使用属性 0 或 glVertex 来发送顶点。
然而,因为所有其他渲染基于立即模式渲染的语言,所有其他渲染都有相同的局限性立即模式渲染。立即模式需要属性 0 或 glVertex,因此客户端数组等也是如此。尽管这对他们来说没有意义,但他们需要它,因为规范如何定义他们的行为。
然后 OpenGL 3.0 出现了。他们不赞成立即模式。弃用并不意味着removed;规范中仍然包含这些函数,并且所有顶点数组渲染仍然被定义in terms其中。
OpenGL 3.1 实际上删除了旧的东西。这带来了一些语言问题。毕竟,每个数组绘制命令总是根据立即模式定义的。但是一旦即时模式不再存在......你如何定义它?
因此他们必须为核心 OpenGL 3.1+ 开发新的语言。在这样做的同时,他们删除了需要使用属性 0 的毫无意义的限制。
但兼容性配置文件did not.
因此,OpenGL 3.2+的规则是这样的。如果您有核心 OpenGL 配置文件,则不必使用属性 0。如果您有兼容性 OpenGL 配置文件,则必须使用属性 0(或glVertex
)。规范就是这么说的。
但这不是实现所实现的。
一般来说,NVIDIA 从来不太关心“必须使用属性 0”规则,只是按照您的预期行事,即使在兼容性配置文件中也是如此。从而违反了规范的规定。 AMD 通常更有可能遵守该规范。然而,他们忘记了实施core行为正确。所以NVIDIA对兼容性太宽容,而AMD对核心太限制。
要解决这些驱动程序错误,只需始终使用属性 0。
顺便说一句,如果您想知道的话,NVIDIA 赢了。在 OpenGL 4.3 中,兼容性配置文件对其数组渲染命令使用与核心相同的措辞。因此,您可以在核心和兼容性上不使用属性 0。