gl.enableVertexAttribArray() gotcha
Another post mainly in the hope that I might save someone else the wasted time and head-scratching I spent in fixing this...
I've been continuing playing with WebGL, and as well as experimenting with new (to me) functionality, in parallel I've started building up a library to tidy up the repetitious boilerplate that has been largely common to all my experiments to date. Until now, this has been a fairly mundane and trouble-free job, but I managed to cause myself a lot of pain and anguish last night, when some of my library code wasn't completely right.
I had a vertex buffer that contained 4 elements per vertex, a three-element (x,y,z) coordinate, and a single-element greyscale value. On initial run-through, the coordinates were rendered correctly, but the greyscale value was not at all how I expected. Rather than coming out in a shade of grey, my pixels were being rendered as white.
As far as I could tell, the code to push the vertex data through to OpenGL was fine, and not really any different to a number of earlier successful experiments:
gl.bindBuffer(gl.ARRAY_BUFFER, bottomFace.vertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.attributes["aVertexPosition"],
3, // vec3 - (x, y, z)
gl.FLOAT,
false,
(4*4), // total size of 'vertex-input' aka stride
0); // offset within 'vertex-input'
gl.vertexAttribPointer(shaderProgram.attributes["aVertexGreyness"],
1, // float
gl.FLOAT,
false,
(4*4), // total size of 'vertex-input' aka stride
12); // offset within 'vertex-input'
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bottomFace.vertexIndexBuffer);
gl.drawElements(gl.TRIANGLES,
bottomFace.vertexIndexBuffer.numItems,
gl.UNSIGNED_SHORT,
0);
I've had problems with this sort of code before, so started fiddling with the arguments to the second gl.vertexAttribPointer() to see if I could provoke it into doing something that would give some insight into what was going wrong, but it steadfastly refused to render anything differently.
One thing that was curious, was swapping the ordering of the two attribute declarations in the vertex shader. As expected, this caused the attribute index values to flip between 0 and 1, but also this seemed to be passed through to the shader, causing my pixels to render as either black or white.
Chrome's WebGL inspector didn't show anything unusual, and indicated that my vertex array had the expected values, so I was at a bit of a loss. Eventually I started hacking around with some older working code, to find out where things were going wrong, and stumbled across the cause.
It transpired that when I was initially getting my attribute index values, I wasn't also enabling them as vertex attribute arrays - or rather, this was happening for the (x,y,z) coordinate attribute (thanks to some legacy code that I thought wasn't getting called), but not for the greyscale attribute. Updating my attribute initialization code fixed the problem:
for (var i=0; i<attrNames.length; i++) {
attrDict[attrNames[i]] = gl.getAttribLocation(shaderProgram,
attrNames[i]);
gl.enableVertexAttribArray(attrDict[attrNames[i]]); // THIS LINE ADDED
}
No errors are caused by not calling gl.enableVertexAttribArray(), and I don't currently know of any reason why you wouldn't want an attribute enabled, but without this rather boring line, you get mysterious failures as I unfortunately found out :-(