禁用顶点属性数组零时,为什么OpenGL绘制失败? [英] Why does OpenGL drawing fail when vertex attrib array zero is disabled?

查看:98
本文介绍了禁用顶点属性数组零时,为什么OpenGL绘制失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我的顶点着色器在ATI驱动程序上的OpenGL 3.3内核下运行时,我遇到了极大的麻烦:

I was having extreme trouble getting a vertex shader of mine to run under OpenGL 3.3 core on an ATI driver:

#version 150

uniform mat4 graph_matrix, view_matrix, proj_matrix;
uniform bool align_origin;

attribute vec2 graph_position;
attribute vec2 screen_position;
attribute vec2 texcoord0;
attribute vec4 color;
varying vec2 texcoord0_px;
varying vec4 color_px;

void main() {
    // Pick the position or the annotation position
    vec2 pos = graph_position;

    // Transform the coordinates
    pos = vec2(graph_matrix * vec4(pos, 0.0, 1.0));

    if( align_origin )
        pos = floor(pos + vec2(0.5, 0.5)) + vec2(0.5, 0.5);

    gl_Position = proj_matrix * view_matrix * vec4(pos + screen_position, 0.0, 1.0);
    texcoord0_px = texcoord0;
    color_px = color;
}

我使用glVertexAttrib4f指定了color属性,并关闭了属性数组.根据3.3核心规范的第33页,应该可以正常工作:

I used glVertexAttrib4f to specify the color attribute, and turned the attribute array off. According to page 33 of the 3.3 core spec, that should work:

如果未启用与顶点着色器所需的通用属性相对应的数组,则将从当前的通用属性状态中获取相应的元素(请参见2.7节).

If an array corresponding to a generic attribute required by a vertex shader is not enabled, then the corresponding element is taken from the current generic attribute state (see section 2.7).

但是(大多数情况下,取决于配置文件和驱动程序)如果我访问了禁用的color属性,则着色器要么根本不运行,要么不使用黑色.用常量替换它可以运行它.

But (most of the time, depending on the profile and driver) the shader either didn't run at all or used black if I accessed the disabled color attribute. Replacing it with a constant got it to run.

经过大量搜索后,产生了有关WebGL的提示页面,其中包含以下内容:

Much searching yielded this page of tips regarding WebGL, which had the following to say:

始终启用顶点属性0数组.如果在禁用顶点attrib 0数组的情况下进行绘制,则在桌面OpenGL(例如Mac OSX)上运行时,将强制浏览器进行复杂的仿真.这是因为在桌面OpenGL中,如果顶点属性0没有启用数组,则不会绘制任何内容.您可以使用bindAttribLocation()强制顶点属性使用位置0,并使用enableVertexAttribArray()使它启用数组.

Always have vertex attrib 0 array enabled. If you draw with vertex attrib 0 array disabled, you will force the browser to do complicated emulation when running on desktop OpenGL (e.g. on Mac OSX). This is because in desktop OpenGL, nothing gets drawn if vertex attrib 0 is not array-enabled. You can use bindAttribLocation() to force a vertex attribute to use location 0, and use enableVertexAttribArray() to make it array-enabled.

可以肯定的是,不仅将color属性分配给索引为零,而且如果我将绑定了数组的其他属性强制绑定为0,则代码将运行并产生正确的颜色.

Sure enough, not only was the color attribute assigned to index zero, but if I force-bound a different, array-enabled attribute to zero, the code ran and produced the right color.

我在任何地方都找不到此规则的任何其他提及,当然在ATI硬件上也找不到.有谁知道这个规则的来历?还是这是Mozilla员工注意到并警告过的实现中的错误?

I can't find any other mention of this rule anywhere, and certainly not on ATI hardware. Does anyone know where this rule comes from? Or is this a bug in the implementation that the Mozilla folks noticed and warned about?

推荐答案

tl; dr::这是一个驱动程序错误.核心OpenGL 3.3应该允许您不使用属性0,但不使用兼容性配置文件,并且某些驱动程序无法正确实现该开关.只需确保使用属性0即可避免任何问题.

tl;dr: this is a driver bug. Core OpenGL 3.3 should allow you to not use attribute 0, but the compatibility profile does not, and some drivers don't implement that switch correctly. Just make sure to use attribute 0 to avoid any problems.

实际内容:

让我们学习一下有关OpenGL规范如何发展的历史.

Let's have a little history lesson in how the OpenGL specification came to be.

在最古老的OpenGL时代,完全有一种渲染方式:即时模式(即:glBegin/glVertex/glColor/glEtc/glEnd).存在显示列表,但始终将它们定义为仅再次发送捕获的命令.因此,尽管实现实际上并没有进行所有这些函数调用,但实现仍然会像它们一样.

In the most ancient days of OpenGL, there was exactly one way to render: immediate mode (ie: glBegin/glVertex/glColor/glEtc/glEnd). Display lists existed, but they were always defined as simply sending the captured commands again. So while implementations didn't actually make all of those function calls, implementations would still behave as if they did.

在OpenGL 1.1中,客户端顶点数组已添加到规范中.现在请记住:规范是一个指定行为而不是实现的文档.因此,ARB只是简单地定义了客户端数组的工作原理,即使用对当前数组指针的适当访问来进行即时模式调用.显然,实现实际上并不能做到这一点,但是它们的行为就像是这样做的.

In OpenGL 1.1, client-side vertex arrays were added to the specification. Now remember: the specification is a document that specifies behavior, not implementation. Therefore, the ARB simply defined that client-side arrays worked exactly like making immediate mode calls, using the appropriate accesses to the current array pointers. Obviously implementations wouldn't actually do that, but they behaved as if they did.

基于缓冲区对象的顶点数组的定义方式相同,但是通过从服务器存储(而不是客户端存储)中提取语言,其语言变得有些复杂.

Buffer-object-based vertex arrays were defined in the same way, though with language slightly complicated by pulling from server storage instead of client storage.

然后发生了一些事情:ARB_vertex_program(不是ARB_vertex_shader.我说的是汇编程序).

Then something happened: ARB_vertex_program (not ARB_vertex_shader. I'm talking about assembly programs).

看到,一旦有了着色器,就希望能够开始定义自己的属性,而不是使用内置属性.一切都说得通.但是,有一个问题.

See, once you have shaders, you want to start being able to define your own attributes instead of using the built-in ones. And that all made sense. However, there was one problem.

即时模式的工作方式如下:

Immedate mode works like this:

glBegin(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glEnd();

每次调用glVertex时,这都会导致所有当前属性状态都用于单个顶点.所有其他即时模式功能都将值简单地设置到上下文中.此功能实际上是将顶点发送到OpenGL进行处理.这在即时模式下非常重要.而且由于每个顶点都必须在固定功能区中具有位置,因此使用此功能来决定何时处理顶点是很有意义的.

Every time you call glVertex, this causes all of the current attribute state to be used for a single vertex. All of the other immediate mode functions simply set values into the context; this function actually sends the vertex to OpenGL to be processed. That's very important in immediate mode. And since every vertex must have a position in fixed-function land, it made sense to use this function to decide when a vertex should be processed.

一旦不再使用OpenGL的固定功能顶点语义,立即模式就会出现问题.即,您如何确定何时真正发送顶点?

Once you're no longer using OpenGL's fixed-function vertex semantics, you have a problem in immediate mode. Namely, how do you decide when to actually send the vertex?

按照惯例,他们将其粘贴到属性0上.因此,所有即时模式渲染都必须使用属性0或glVertex来发送顶点.

By convention, they stuck this onto attribute 0. Therefore, all immediate mode rendering must use either attribute 0 or glVertex to send a vertex.

但是,由于所有其他渲染是基于即时模式渲染的语言,因此所有其他渲染都具有与即时模式渲染相同的限制.即时模式需要属性0或glVertex,因此客户端数组等也是如此.即使对他们来说没有意义,但由于规范如何定义其行为,他们仍然需要它.

However, because all other rendering is based on the language of immediate mode rendering, all other rendering has the same limitations of immediate mode rendering. Immediate mode requires attribute 0 or glVertex, and therefore so too do client-side arrays and so forth. Even though it doesn't make sense for them to, they need it because of how the specification defines their behavior.

然后OpenGL 3.0出现了.他们不建议使用即时模式.已弃用并不意味着已删除;规范中仍然包含这些功能,并且所有顶点数组渲染仍是根据其中的 定义的.

Then OpenGL 3.0 came around. They deprecated immediate mode. Deprecated does not mean removed; the specification still had those functions in it, and all vertex array rendering was still defined in terms of them.

OpenGL 3.1实际上已经淘汰了旧的东西.这带来了一些语言问题.毕竟,每个数组绘制命令总是以即时模式定义的.但是一旦立即模式不再存在,您将如何定义它?

OpenGL 3.1 actually ripped out the old stuff. And that posed a bit of a language problem. After all, every array drawing command was always defined in terms of immediate mode. But once immediate mode no longer exists... how do you define it?

因此,他们不得不为核心OpenGL 3.1+提出新的语言.这样做时,他们消除了对使用属性0的毫无意义的限制.

So they had to come up with new language for core OpenGL 3.1+. While doing so, they removed the pointless restriction on needing to use attribute 0.

但是兼容性配置文件没有.

因此,OpenGL 3.2+的规则是这样.如果您具有核心OpenGL配置文件,则不必使用属性0.如果您具有兼容的OpenGL配置文件,则必须使用属性0(或glVertex).规范就是这么说的.

Therefore, the rules for OpenGL 3.2+ is this. If you have a core OpenGL profile, then you do not have to use attribute 0. If you have a compatibility OpenGL profile, you must use attribute 0 (or glVertex). That's what the specification says.

但这不是实现所实现的.

But that's not what implementations implement.

通常,NVIDIA从来都不关心必须使用属性0"规则,并且按照您的期望进行操作,即使在兼容性配置文件中也是如此.从而违反了规范的文字.通常,AMD更有可能坚持该规范.但是,他们忘记了正确实现 core 行为.因此,NVIDIA在兼容性方面过于宽容,而AMD在内核方面过于严格.

In general, NVIDIA never cared much for the "must use attribute 0" rule and just does it how you would expect, even in compatibility profiles. Thus violating the letter of the specification. AMD is generally more likely to stick to the specification. However, they forgot to implement the core behavior correctly. So NVIDIA's too permissive on compatibility, and AMD is too restrictive on core.

要解决这些驱动程序错误,只需始终使用属性0.

To work around these driver bugs, simply always use attribute 0.

顺便说一句,如果您想知道,NVIDIA赢了.在OpenGL 4.3中,兼容性配置文件对其数组渲染命令使用与核心相同的措辞.因此,不允许在核心和兼容性上都使用属性0.

BTW, if you're wondering, NVIDIA won. In OpenGL 4.3, the compatibility profile uses the same wording for its array rendering commands as core. Thus, you're allowed to not use attribute 0 on both core and compatibility.

这篇关于禁用顶点属性数组零时,为什么OpenGL绘制失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆