'glDrawArrays: attempt to access out of range vertices in attribute 1' 关于 Emscripten/OpenGL 代码(适用于本机 C++)

'glDrawArrays: attempt to access out of range vertices in attribute 1' on Emscripten/OpenGL code (works in native C++)

我已将问题范围缩小到此。我有两个属性指向完全相同的数据。在本机 C++ 中构建时,这工作正常。但是,当使用 emscripten 构建时,javascript 控制台在每一帧上显示以下错误:

'glDrawArrays: attempt to access out of range vertices in attribute 1'

当我注释掉 'glEnableVertexAttribArray' 行以启用第二个属性时,我没有收到此错误。

下面是我的代码。我将从创建数据缓冲区开始:

GLfloat rectangleData[] =
{
    -.5f, -.5f,     0,1,
    -.5f, .5f,      0,0,
    .5f, .5f,       1,0,
    .5f, -.5f,      1,1,
    -.5f, -.5f,     0,1
};
glGenBuffers(1, &rectangleBuffer);
glBindBuffer(GL_ARRAY_BUFFER, rectangleBuffer);
glBufferData(
        GL_ARRAY_BUFFER, sizeof(rectangleData),
        rectangleData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

这是我的带纹理的四边形绘图代码的相关摘录:

glBindBuffer(GL_ARRAY_BUFFER, rectangleBuffer);

int vertexPosition = Shader::getParameterInfo("vertexPosition")->id;
glVertexAttribPointer(
        vertexPosition, 2, GL_FLOAT,
        GL_FALSE, 16, BUFFER_OFFSET(0));
glEnableVertexAttribArray(vertexPosition);

int vertexTexCoord = Shader::getParameterInfo("vertexTexCoord")->id;
glVertexAttribPointer(
        vertexTexCoord, 2, GL_FLOAT,
        GL_FALSE, 16, BUFFER_OFFSET(0));
glEnableVertexAttribArray(vertexTexCoord);

glDrawArrays(GL_TRIANGLE_FAN, 0, 5);

请注意,我已将第二个属性调整为指向与第一个属性相同的数据(以降低调试时的复杂性)。我在这里很困惑,真的可以使用 fresh/experienced 视角。

编辑:BUFFER_OFFSET 看起来像这样:

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

来源:How to cast int to const GLvoid*?

编辑:就其价值而言,这是等效的 Emscripten 生成的 JS 代码。如果需要,我将 post 引用任何 JS 代码。

dest=$rectangleData; src=2328; stop=dest+80|0; do {
HEAP32[dest>>2]=HEAP32[src>>2]|0; dest=dest+4|0; src=src+4|0; } while
((dest|0) < (stop|0));
 _glGenBuffers(1,(2300|0));
  = HEAP32[2300>>2]|0;
 _glBindBuffer(34962,(|0));
 _glBufferData(34962,80,($rectangleData|0),35044);
 _glBindBuffer(34962,0);

 = HEAP32[2300>>2]|0;
 _glBindBuffer(34962,(|0));
  = (__ZN8platform6Shader16getParameterInfoEPKc(17356)|0);
  = HEAP32[>>2]|0;
 $vertexPosition = ;
  = $vertexPosition;
 _glVertexAttribPointer((|0),2,5126,0,16,(0|0));
  = $vertexPosition;
 _glEnableVertexAttribArray((|0));
  = (__ZN8platform6Shader16getParameterInfoEPKc(17379)|0);
  = HEAP32[>>2]|0;
 $vertexTexCoord = ;
  = $vertexTexCoord;
 _glVertexAttribPointer((|0),2,5126,0,16,(0|0));
  = $vertexTexCoord;
 _glEnableVertexAttribArray((|0));
 _glDrawArrays(6,0,5);

编辑:更好的是,我将在 github 上为 JS 代码 运行 和 C++ 代码提供 link(它在 [=43 的底部附近) =]):

https://rawgit.com/jon-heard/Native-WebGL-framework/c134e35ac94fdf3243a9662353ad2227f8c84b43/Native-WebGL-framework/web/index.html

https://github.com/jon-heard/Native-WebGL-framework/blob/c134e35ac94fdf3243a9662353ad2227f8c84b43/Native-WebGL-framework/src/platform/draw.cpp

错误实际上来自不同的地方,从 drawCircle 函数形成绘图调用。从它的外观来看,您忘记禁用未使用的属性数组。 Here you use just one attribute, which's bound to 0, but the error is for attribute 1. Evidently, you've enabled vertex array for attribute 1 somewhere and forgot to disable it. Now draw call verifies it's binding, founds that it's incorrect and arises GL_INVALID_OPERATION error. The spec says that out-of-bounds check should be performed only for attributes used in current program, but by the looks of it at least Chromium 简单地检查所有启用数组的。

UPD. 我误解了 Chromium 的代码。正如@gman 所指出的,它确实只检查当前程序使用的越界访问属性。

问题是您有一个顶点着色器总是使用 2 个属性

var gl = document.createElement("canvas").getContext("webgl");
var program = twgl.createProgramFromScripts(gl, ["vs", "fs"]);

log("list of used attributes");
log("-----------------------");

var numAttribs = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
for (var ii = 0; ii < numAttribs; ++ii) {
  var attribInfo = gl.getActiveAttrib(program, ii);
  if (!attribInfo) {
    break;
  }
  log(gl.getAttribLocation(program, attribInfo.name), attribInfo.name);
}

function log(...args) {
   var div = document.createElement("div");
   div.textContent = [...args].join(" ");
   document.body.appendChild(div);
}
<script src="https://twgljs.org/dist/2.x/twgl.min.js"></script>
<script type="foo" id="vs">
uniform mat4 sceneTransform;
uniform mat4 rotationTransform;
uniform vec2 objectPosition;
uniform vec2 objectScale;
attribute vec2 vertexPosition;
attribute vec2 vertexTexCoord;
varying vec2 UVs;
void main()
{
  UVs = vertexTexCoord;
  gl_Position = 
    sceneTransform *
    vec4( vertexPosition * objectScale + objectPosition, 0, 1);
}
</script>
<script type="foo" id="fs">
precision mediump float;

uniform vec3 objectColor;
uniform float objectOpacity;

void main()
{
 gl_FragColor = vec4(objectColor, objectOpacity);
}
</script>

当您调用 drawCircle 时,您将这两个属性分配给缓冲区,然后在上面的代码中,如果您不对第二个属性做任何事情,它仍然指向前一个缓冲区。该缓冲区对于您的绘图调用来说太小,您会收到错误消息。

WebGL 不会抱怨未使用的属性,但会抱怨已使用的属性。您应该始终提供着色器需要的属性。

在你的情况下,你至少有 2 个选择

  1. 更改您的代码,使您的着色器仅使用一个属性

    如果我没看错代码,你只有一个顶点着色器。对于片段着色器不打算使用纹理坐标的情况,请使用不提供它们的不同顶点着色器。

  2. 禁用该属性,使其使用常量值

    gl.disableVertexAttribArray(...)
    

    表示该属性将使用

    提供的常量值
    gl.vertexAttribXXX
    

1 可以说比 2 好,因为您的顶点着色器不会浪费时间从属性中读取并将其复制到变量中,而不会在片段着色器中使用它。

我在尝试重新创建 this and made a mistake. The tutorial code can be found here 时看到了这个错误。但是,我收到此错误是因为我在位置缓冲区中设置数据后定义了颜色缓冲区。我通过定义颜色缓冲区来修复它,然后定义位置缓冲区并将数据绑定到缓冲区。成功了。所以综上所述,如果我们不按顺序定义属性,就会出现这个错误。

我遇到这个错误是因为我传递给着色器的 vec2 属性不包含我的每个顶点的数据...