First, the short answer: replace the last 10 lines of your code with the following, and I think it should work.
gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texturen[1]); gl.vertexAttribPointer(textureCoordAttribute, cubeVertexTextureCoordBuffer1.itemSize, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer1); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,cubeVertexPositionBuffer1.itemSize, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
Key changes are:
activeTexture is still TEXTURE0 (you only use one texture at a time)- Using
cubeVertexIndexBuffer instead of cubeVertexIndexBuffer1 , which contains pointers out of range
For a better explanation of what used actual indices, I refer you to this issue of SO , as I would rather not repeat it all here.
Now, to a more general answer.
There are two main ways to solve the problem of using different textures on different faces. The first and simpler method is to do exactly what you are doing here: visualize the object in parts, linking different textures for each part. Although this is not the most effective way to achieve the effect, it is the most common way to handle this in high-performance applications such as games, simply because it offers more flexibility, especially when your materials are more complex than a simple diffuse texture.
There is an easy way to improve the performance of code like yours for this case. Vertices / indices should not be split into separate buffers per texture. You could combine them all into one buffer and make them with different offsets like this:
// On Init var vertBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer); var vertices = [ // Vertex values for all 6 faces ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); var indexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); var indices = [ // Index values for all 6 faces ]; gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); // On Draw // Setup the shader and uniforms and all that jazz gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); gl.vertexAttribPointer(// Blah blah blah...); // Draw face 0 gl.bindTexture(gl.TEXTURE_2D, texture[0]); gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); // Draw face 1 gl.bindTexture(gl.TEXTURE_2D, texture[1]); gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 12); // Draw face 2 gl.bindTexture(gl.TEXTURE_2D, texture[2]); gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 24); // .. And so on to face 5 // Draw face 2 gl.bindTexture(gl.TEXTURE_2D, texture[5]); gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 60);
What happens here is that each drawElements call only draws 2 triangles (6 vertices, the second call parameter), but each call is shifted to the index buffer, so it starts from a different face. (the fourth call parameter, which indicates the byte offset, each index is Uint16, so 2 bytes per index 12 == "start on index [6]") Thus, all binding and configuration occurs only once and each call to the call should only change the state that is really needed (texture).
Another way to deal with this, which is faster, but harder to generalize, is to bind the texture array to the shader uniform and use another vertex attribute to index into the array in the shader. I am not going to describe the code in detail for this approach, but it should be relatively easy to configure when it is convenient for you to use the WebGL shader. If you have additional questions about this particular approach, it is best to ask in another SO question so as not to overload this one.