title: Multiple Programs in WebGL doesn't work
body: <p>I'm trying to use multiple shader programs in webgl but continue to get issues.</p>
  
  <p>It seems that if i have a different number of vertex shader attributes in programs then i get nothing rendered with no errors. Is there some constraint that means that programs have to have the same number of attributes? Do i need to disable/enable attribute locations when changing programs? </p>
  
  <p>It seems that just creating multiple programs causes the issue ( i dont even have to use the second shader, just the fact that it is created causes the issue).</p>
  
  <p>To create the attributes i'm using the following snippet (works fine when number of attributes in all programs is the same):</p>
  
  <pre><code>for ( var i=0 ; i&lt;vertexAttributes.length ; i++ )
  {
     shaderProgram[vertexAttributes[i].name] = gl.getAttribLocation(shaderProgram,vertexAttributes[i].name);
     gl.enableVertexAttribArray(shaderProgram[vertexAttributes[i].name]);
  }
  </code></pre>
  
  <hr>
  
  <p>Sorry for posting such a large chunk of code, but this best illustrates the issue. this is code from one of the learningwebgl.com tutorials, all that i have done is add a second pair of shaders ("shader2-fs" and "shader2-vs") and a new function called initShaders2. if initShaders2 is called in webGLStart() (as it is in the code) then nothing is drawn??? i'm baffled!</p>
  
  <pre><code>&lt;script type="text/javascript" src="two_files/glMatrix-0.js"&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src="two_files/webgl-utils.js"&gt;&lt;/script&gt;
  
  &lt;script id="shader-fs" type="x-shader/x-fragment"&gt;
      precision mediump float;
  
      varying vec4 vColor;
  
      void main(void) {
          gl_FragColor = vColor;
      }
  &lt;/script&gt;
  
  &lt;script id="shader-vs" type="x-shader/x-vertex"&gt;
      attribute vec3 aVertexPosition;
      attribute vec4 aVertexColor;
  
      uniform mat4 uMVMatrix;
      uniform mat4 uPMatrix;
  
      varying vec4 vColor;
  
      void main(void) {
          gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
          vColor = aVertexColor;
      }
  &lt;/script&gt;
  
  &lt;script id="shader2-fs" type="x-shader/x-fragment"&gt;
      precision mediump float;
  
      varying vec2 vTextureCoord;
      varying vec3 vLightWeighting;
  
      uniform sampler2D uSampler;
  
      void main(void) {
          vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
          gl_FragColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a);
      }
  &lt;/script&gt;
  
  &lt;script id="shader2-vs" type="x-shader/x-vertex"&gt;
      attribute vec3 aVertexPosition;
      attribute vec3 aVertexNormal;
      attribute vec2 aTextureCoord;
  
      uniform mat4 uMVMatrix;
      uniform mat4 uPMatrix;
      uniform mat3 uNMatrix;
  
      uniform vec3 uAmbientColor;
  
      uniform vec3 uLightingDirection;
      uniform vec3 uDirectionalColor;
  
      uniform bool uUseLighting;
  
      varying vec2 vTextureCoord;
      varying vec3 vLightWeighting;
  
      void main(void) {
          gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
          vTextureCoord = aTextureCoord;
  
          if (!uUseLighting) {
              vLightWeighting = vec3(1.0, 1.0, 1.0);
          } else {
              vec3 transformedNormal = uNMatrix * aVertexNormal;
              float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0);
              vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;
          }
      }
  &lt;/script&gt;
  
  
  &lt;script type="text/javascript"&gt;
  
      var gl;
  
      function initGL(canvas) {
          try {
              gl = canvas.getContext("experimental-webgl");
              gl.viewportWidth = canvas.width;
              gl.viewportHeight = canvas.height;
          } catch (e) {
          }
          if (!gl) {
              alert("Could not initialise WebGL, sorry :-(");
          }
      }
  
  
      function getShader(gl, id) {
          var shaderScript = document.getElementById(id);
          if (!shaderScript) {
              return null;
          }
  
          var str = "";
          var k = shaderScript.firstChild;
          while (k) {
              if (k.nodeType == 3) {
                  str += k.textContent;
              }
              k = k.nextSibling;
          }
  
          var shader;
          if (shaderScript.type == "x-shader/x-fragment") {
              shader = gl.createShader(gl.FRAGMENT_SHADER);
          } else if (shaderScript.type == "x-shader/x-vertex") {
              shader = gl.createShader(gl.VERTEX_SHADER);
          } else {
              return null;
          }
  
          gl.shaderSource(shader, str);
          gl.compileShader(shader);
  
          if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
              alert(gl.getShaderInfoLog(shader));
              return null;
          }
  
          return shader;
      }
  
  
      var shaderProgram;
  
      function initShaders() {
          var fragmentShader = getShader(gl, "shader-fs");
          var vertexShader = getShader(gl, "shader-vs");
  
          shaderProgram = gl.createProgram();
          gl.attachShader(shaderProgram, vertexShader);
          gl.attachShader(shaderProgram, fragmentShader);
          gl.linkProgram(shaderProgram);
  
          if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
              alert("Could not initialise shaders");
          }
  
          gl.useProgram(shaderProgram);
  
          shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
          gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
  
          shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
          gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);
  
          shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
          shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
      }
  
  
      var shaderProgram2;
  
      function initShaders2() {
          var fragmentShader = getShader(gl, "shader2-fs");
          var vertexShader = getShader(gl, "shader2-vs");
  
          shaderProgram2 = gl.createProgram();
          gl.attachShader(shaderProgram2, vertexShader);
          gl.attachShader(shaderProgram2, fragmentShader);
          gl.linkProgram(shaderProgram2);
  
          if (!gl.getProgramParameter(shaderProgram2, gl.LINK_STATUS)) {
              alert("Could not initialise shaders");
          }
  
          gl.useProgram(shaderProgram2);
  
          shaderProgram2.vertexPositionAttribute = gl.getAttribLocation(shaderProgram2, "aVertexPosition");
          gl.enableVertexAttribArray(shaderProgram2.vertexPositionAttribute);
  
          shaderProgram2.vertexNormalAttribute = gl.getAttribLocation(shaderProgram2, "aVertexNormal");
          gl.enableVertexAttribArray(shaderProgram2.vertexNormalAttribute);
  
          shaderProgram2.textureCoordAttribute = gl.getAttribLocation(shaderProgram2, "aTextureCoord");
          gl.enableVertexAttribArray(shaderProgram2.textureCoordAttribute);
  
          shaderProgram2.pMatrixUniform = gl.getUniformLocation(shaderProgram2, "uPMatrix");
          shaderProgram2.mvMatrixUniform = gl.getUniformLocation(shaderProgram2, "uMVMatrix");
          shaderProgram2.nMatrixUniform = gl.getUniformLocation(shaderProgram2, "uNMatrix");
          shaderProgram2.samplerUniform = gl.getUniformLocation(shaderProgram2, "uSampler");
          shaderProgram2.useLightingUniform = gl.getUniformLocation(shaderProgram2, "uUseLighting");
          shaderProgram2.ambientColorUniform = gl.getUniformLocation(shaderProgram2, "uAmbientColor");
          shaderProgram2.lightingDirectionUniform = gl.getUniformLocation(shaderProgram2, "uLightingDirection");
          shaderProgram2.directionalColorUniform = gl.getUniformLocation(shaderProgram2, "uDirectionalColor");
      }
  
      var mvMatrix = mat4.create();
      var mvMatrixStack = [];
      var pMatrix = mat4.create();
  
      function mvPushMatrix() {
          var copy = mat4.create();
          mat4.set(mvMatrix, copy);
          mvMatrixStack.push(copy);
      }
  
      function mvPopMatrix() {
          if (mvMatrixStack.length == 0) {
              throw "Invalid popMatrix!";
          }
          mvMatrix = mvMatrixStack.pop();
      }
  
  
      function setMatrixUniforms() {
          gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
          gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
      }
  
  
      function degToRad(degrees) {
          return degrees * Math.PI / 180;
      }
  
  
      var pyramidVertexPositionBuffer;
      var pyramidVertexColorBuffer;
      var cubeVertexPositionBuffer;
      var cubeVertexColorBuffer;
      var cubeVertexIndexBuffer;
  
      function initBuffers() {
          pyramidVertexPositionBuffer = gl.createBuffer();
          gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
          var vertices = [
              // Front face
               0.0,  1.0,  0.0,
              -1.0, -1.0,  1.0,
               1.0, -1.0,  1.0,
  
              // Right face
               0.0,  1.0,  0.0,
               1.0, -1.0,  1.0,
               1.0, -1.0, -1.0,
  
              // Back face
               0.0,  1.0,  0.0,
               1.0, -1.0, -1.0,
              -1.0, -1.0, -1.0,
  
              // Left face
               0.0,  1.0,  0.0,
              -1.0, -1.0, -1.0,
              -1.0, -1.0,  1.0
          ];
          gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
          pyramidVertexPositionBuffer.itemSize = 3;
          pyramidVertexPositionBuffer.numItems = 12;
  
          pyramidVertexColorBuffer = gl.createBuffer();
          gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
          var colors = [
              // Front face
              1.0, 0.0, 0.0, 1.0,
              0.0, 1.0, 0.0, 1.0,
              0.0, 0.0, 1.0, 1.0,
  
              // Right face
              1.0, 0.0, 0.0, 1.0,
              0.0, 0.0, 1.0, 1.0,
              0.0, 1.0, 0.0, 1.0,
  
              // Back face
              1.0, 0.0, 0.0, 1.0,
              0.0, 1.0, 0.0, 1.0,
              0.0, 0.0, 1.0, 1.0,
  
              // Left face
              1.0, 0.0, 0.0, 1.0,
              0.0, 0.0, 1.0, 1.0,
              0.0, 1.0, 0.0, 1.0
          ];
          gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
          pyramidVertexColorBuffer.itemSize = 4;
          pyramidVertexColorBuffer.numItems = 12;
  
  
          cubeVertexPositionBuffer = gl.createBuffer();
          gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
          vertices = [
              // Front face
              -1.0, -1.0,  1.0,
               1.0, -1.0,  1.0,
               1.0,  1.0,  1.0,
              -1.0,  1.0,  1.0,
  
              // Back face
              -1.0, -1.0, -1.0,
              -1.0,  1.0, -1.0,
               1.0,  1.0, -1.0,
               1.0, -1.0, -1.0,
  
              // Top face
              -1.0,  1.0, -1.0,
              -1.0,  1.0,  1.0,
               1.0,  1.0,  1.0,
               1.0,  1.0, -1.0,
  
              // Bottom face
              -1.0, -1.0, -1.0,
               1.0, -1.0, -1.0,
               1.0, -1.0,  1.0,
              -1.0, -1.0,  1.0,
  
              // Right face
               1.0, -1.0, -1.0,
               1.0,  1.0, -1.0,
               1.0,  1.0,  1.0,
               1.0, -1.0,  1.0,
  
              // Left face
              -1.0, -1.0, -1.0,
              -1.0, -1.0,  1.0,
              -1.0,  1.0,  1.0,
              -1.0,  1.0, -1.0
          ];
          gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
          cubeVertexPositionBuffer.itemSize = 3;
          cubeVertexPositionBuffer.numItems = 24;
  
          cubeVertexColorBuffer = gl.createBuffer();
          gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
          colors = [
              [1.0, 0.0, 0.0, 1.0], // Front face
              [1.0, 1.0, 0.0, 1.0], // Back face
              [0.0, 1.0, 0.0, 1.0], // Top face
              [1.0, 0.5, 0.5, 1.0], // Bottom face
              [1.0, 0.0, 1.0, 1.0], // Right face
              [0.0, 0.0, 1.0, 1.0]  // Left face
          ];
          var unpackedColors = [];
          for (var i in colors) {
              var color = colors[i];
              for (var j=0; j &lt; 4; j++) {
                  unpackedColors = unpackedColors.concat(color);
              }
          }
          gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(unpackedColors), gl.STATIC_DRAW);
          cubeVertexColorBuffer.itemSize = 4;
          cubeVertexColorBuffer.numItems = 24;
  
          cubeVertexIndexBuffer = gl.createBuffer();
          gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
          var cubeVertexIndices = [
              0, 1, 2,      0, 2, 3,    // Front face
              4, 5, 6,      4, 6, 7,    // Back face
              8, 9, 10,     8, 10, 11,  // Top face
              12, 13, 14,   12, 14, 15, // Bottom face
              16, 17, 18,   16, 18, 19, // Right face
              20, 21, 22,   20, 22, 23  // Left face
          ];
          gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
          cubeVertexIndexBuffer.itemSize = 1;
          cubeVertexIndexBuffer.numItems = 36;
      }
  
  
      var rPyramid = 0;
      var rCube = 0;
  
      function drawScene() {
          gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
          gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  
          mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
  
          mat4.identity(mvMatrix);
  
          mat4.translate(mvMatrix, [-1.5, 0.0, -8.0]);
  
          mvPushMatrix();
          mat4.rotate(mvMatrix, degToRad(rPyramid), [0, 1, 0]);
  
          gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
          gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pyramidVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
  
          gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
          gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, pyramidVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
  
          setMatrixUniforms();
          gl.drawArrays(gl.TRIANGLES, 0, pyramidVertexPositionBuffer.numItems);
  
          mvPopMatrix();
  
  
          mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);
  
          mvPushMatrix();
          mat4.rotate(mvMatrix, degToRad(rCube), [1, 1, 1]);
  
          gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
          gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
  
          gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
          gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, cubeVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
  
          gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
          setMatrixUniforms();
          gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
  
          mvPopMatrix();
  
      }
  
  
      var lastTime = 0;
  
      function animate() {
          var timeNow = new Date().getTime();
          if (lastTime != 0) {
              var elapsed = timeNow - lastTime;
  
              rPyramid += (90 * elapsed) / 1000.0;
              rCube -= (75 * elapsed) / 1000.0;
          }
          lastTime = timeNow;
      }
  
  
      function tick() {
          requestAnimFrame(tick);
          drawScene();
          animate();
      }
  
  
      function webGLStart() {
          var canvas = document.getElementById("lesson04-canvas");
          initGL(canvas);
          initShaders2();  // !!!!!!!!!!!!!!!!!!!!!!!!!
          initShaders();
          initBuffers();
  
          gl.clearColor(0.0, 0.0, 0.0, 1.0);
          gl.enable(gl.DEPTH_TEST);
  
          tick();
      }
  
  &lt;/script&gt;
  
  
  &lt;/head&gt;
  
  
  &lt;body onload="webGLStart();"&gt;
      &lt;a href="http://learningwebgl.com/blog/?p=370"&gt;&amp;lt;&amp;lt; Back to Lesson 4&lt;/a&gt;&lt;br&gt;
  
      &lt;canvas id="lesson04-canvas" style="border: none;" width="500" height="500"&gt;&lt;/canvas&gt;
  
      &lt;br&gt;
      &lt;a href="http://learningwebgl.com/blog/?p=370"&gt;&amp;lt;&amp;lt; Back to Lesson 4&lt;/a&gt;&lt;br&gt;
  
  &lt;/body&gt;&lt;/html&gt;
  </code></pre>