'glDrawArrays:尝试访问Emscripten / OpenGL代码中的属性1'中的范围顶点(在本机C ++中工作)

时间:2016-11-25 10:50:46

标签: opengl webgl texture-mapping emscripten

我已经将问题缩小到了这个范围。我有两个属性指向完全相同的数据。在使用本机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);

请注意,我已将第二个属性调整为指向与第一个属性相同的数据(以降低调试时的复杂性)。我在这里很难过,真的可以使用新鲜/有经验的观点。

编辑:这是BUFFER_OFFSET的样子:

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

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

编辑:对于它的价值,这里是等效的Emscripten生成的JS代码。如果需要,我会发布任何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));
 $30 = HEAP32[2300>>2]|0;
 _glBindBuffer(34962,($30|0));
 _glBufferData(34962,80,($rectangleData|0),35044);
 _glBindBuffer(34962,0);

$11 = HEAP32[2300>>2]|0;
 _glBindBuffer(34962,($11|0));
 $12 = (__ZN8platform6Shader16getParameterInfoEPKc(17356)|0);
 $13 = HEAP32[$12>>2]|0;
 $vertexPosition = $13;
 $14 = $vertexPosition;
 _glVertexAttribPointer(($14|0),2,5126,0,16,(0|0));
 $15 = $vertexPosition;
 _glEnableVertexAttribArray(($15|0));
 $16 = (__ZN8platform6Shader16getParameterInfoEPKc(17379)|0);
 $17 = HEAP32[$16>>2]|0;
 $vertexTexCoord = $17;
 $18 = $vertexTexCoord;
 _glVertexAttribPointer(($18|0),2,5126,0,16,(0|0));
 $19 = $vertexTexCoord;
 _glEnableVertexAttribArray(($19|0));
 _glDrawArrays(6,0,5);

编辑:更好的是,我将提供一个链接到github上运行的JS代码,以及C ++代码(它在“drawImage()”的底部附近):

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

4 个答案:

答案 0 :(得分:3)

问题是你有一个顶点着色器总是使用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不会抱怨未使用的属性,但它会抱怨使用过的属性。您应始终提供着色器所需的属性。

在您的情况下,您至少有两个选项

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

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

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

    gl.disableVertexAttribArray(...)
    

    表示该属性将使用

    提供的常量值
    gl.vertexAttribXXX
    
  3. 1可以说比2更好,因为您的顶点着色器不会浪费时间从属性读取并将其复制到变化而只是不在片段着色器中使用它。

答案 1 :(得分:1)

当我尝试重新创建this并犯了一个错误时,我看到了这个错误。可以找到教程代码here。但是,我得到了这个错误,因为我定义了颜色缓冲区AFTER在位置缓冲区中设置数据。我通过定义颜色缓冲区,然后定义位置缓冲区和绑定数据到缓冲区来修复它。这就是诀窍。总而言之,如果我们不按顺序定义属性,则会出现此错误。

答案 2 :(得分:0)

错误实际上来自不同的地方,形成来自drawCircle函数的绘制调用。通过它的外观你忘了禁用未使用的属性数组。 Here您只使用一个属性,该属性绑定为0,但错误是属性1.显然,您已在某处启用了属性1的顶点数组并忘记禁用它。现在,绘制调用验证它的绑定,发现它不正确并出现GL_INVALID_OPERATION错误。 The spec says应该仅对当前程序中使用的属性执行越界检查,但是通过它的外观at least Chromium只检查所有启用数组的属性。

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

答案 3 :(得分:0)

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