WebGL: Adding textures causes DrawElements error (attribute buffers insufficient space)

StackOverflow https://stackoverflow.com/questions/19350390

  •  30-06-2022
  •  | 
  •  

Domanda

I want to draw a 3d model (e.g. a house) from a model.json file. I have no problem drawing the house in a single color like blue. However, when I try to use textures instead of a color, I receive an error:

WebGL: DrawElements: bound vertex attribute buffers do not have sufficient size for given indices from the bound element array

I've searched the web, and tried hundreds of different alterations, and I simply can't get past this error - I'm not good enough at WebGL to see what's wrong. There is an images folder with multiple texture images, but at this point, if I can just draw one of the textures for the entire house, I'd be ecstatic.

The problem lies in renderable.js (attached) but you can access all files at http://tinyurl.com/mk9vbta. Any help would be greatly appreciated, don't know where else to go.

renderable.js

    "use strict";
function RenderableModel(gl,model){
    function Drawable(attribLocations, vArrays, nVertices, indexArray, drawMode){
      // Create a buffer object
      var vertexBuffers=[];
      var nElements=[];
      var nAttributes = attribLocations.length;

      for (var i=0; i<nAttributes; i++){
          if (vArrays[i]){
              vertexBuffers[i] = gl.createBuffer();
              if (!vertexBuffers[i]) {
                console.log('Failed to create the buffer object');
                return null;
              }
              // Bind the buffer object to an ARRAY_BUFFER target

              gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffers[i]);
              // Write date into the buffer object
              gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vArrays[i]), gl.STATIC_DRAW);
              // Texture coords must always be passed as last attribute location (a_Attribute)
              nElements[i] = (i == (nAttributes - 1))? 2: vArrays[i].length/nVertices;
          }
          else{
              vertexBuffers[i]=null;
          }
      }

      var indexBuffer=null;
      if (indexArray){
        indexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW);
      }

      var a_texture = createTexture("texture0.jpg");
      // Set the texture unit 0 to the sampler
      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, a_texture);

      this.draw = function (){
        nElements[1] = 2;
        for (var i=0; i<nAttributes; i++){
          if (vertexBuffers[i]){
              gl.enableVertexAttribArray(attribLocations[i]);
              // Bind the buffer object to target
              gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffers[i]);
              // Assign the buffer object to a_Position variable
              gl.vertexAttribPointer(attribLocations[i], nElements[i], gl.FLOAT, false, 24, 0);
          }
          else{
              gl.disableVertexAttribArray(attribLocations[i]); 
              gl.vertexAttrib3f(attribLocations[i],1,1,1);
              //console.log("Missing "+attribLocations[i])
          }
        }

        if (indexBuffer){
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
            gl.drawElements(drawMode, indexArray.length, gl.UNSIGNED_SHORT, 0);
        }
        else{
            gl.drawArrays(drawMode, 0, nVertices);
        }
      }
    }

    // Vertex shader program
    var VSHADER_SOURCE =
      'attribute vec2 textureCoord;\n' +    
      'attribute vec3 position;\n' +

      'uniform mat4 modelT, viewT, projT;\n'+

      //'varying vec4 v_Color;\n' +
      'varying highp vec2 vTextureCoord;\n' +
      'void main() {\n' +
      '  gl_Position = projT*viewT*modelT*vec4(position,1.0);\n' +
      //'  v_Color = vec4(0, 1.0, 0.0, 1.0);\n' +   // use instead of textures for now
      '  vTextureCoord = textureCoord;\n' +
      '}\n';


    // Fragment shader program
    var FSHADER_SOURCE =
      '#ifdef GL_ES\n' +
      'precision highp float;\n' +
      '#endif\n' +

      'uniform sampler2D uSampler;\n' +
      //'varying vec4 v_Color;\n' + // use instead of texture
      'varying highp vec2 vTextureCoord;\n' +
      'void main() {\n' +  
      // 'vec4 v_Color = vec4(texture2D(uSampler, vTextureCoord).rgb, 1.0);\n'+
      '  gl_FragColor = texture2D(uSampler, vTextureCoord);\n' +
      '}\n';


    // create program
    var program = createProgram(gl, VSHADER_SOURCE, FSHADER_SOURCE);
    if (!program) {
        console.log('Failed to create program');
        return false;
    }

    var a_Position = gl.getAttribLocation(program, 'position');       
    var a_TextureCoord = gl.getAttribLocation(program, 'textureCoord'); // for texture
    var a_Locations = [a_Position,a_TextureCoord];

    // Get the location/address of the uniform variable inside the shader program.
    var mmLoc = gl.getUniformLocation(program,"modelT");
    var vmLoc = gl.getUniformLocation(program,"viewT");
    var pmLoc = gl.getUniformLocation(program,"projT");
    // textures
    var textureLoc = gl.getUniformLocation(program,'uSampler');

    var drawables=[];
    var modelTransformations=[];
    var nDrawables=0;
    var nNodes = (model.nodes)? model.nodes.length:1;
    var drawMode=(model.drawMode)?gl[model.drawMode]:gl.TRIANGLES;

    for (var i= 0; i<nNodes; i++){
        var nMeshes = (model.nodes)?(model.nodes[i].meshIndices.length):(model.meshes.length);
        for (var j=0; j<nMeshes;j++){
            var index = (model.nodes)?model.nodes[i].meshIndices[j]:j;
            var mesh = model.meshes[index];
            drawables[nDrawables] = new Drawable(
                a_Locations,[mesh.vertexPositions, mesh.vertexTexCoordinates],
                mesh.vertexPositions.length/3,
                mesh.indices, drawMode
            );

            var m = new Matrix4();
            if (model.nodes)
                m.elements=new Float32Array(model.nodes[i].modelMatrix);
            modelTransformations[nDrawables] = m;

            nDrawables++;
        }
    }
    // Get the location/address of the vertex attribute inside the shader program.
    this.draw = function (cameraPosition,pMatrix,vMatrix,mMatrix)
    {
        gl.useProgram(program);
        gl.uniformMatrix4fv(pmLoc, false, pMatrix.elements);
        gl.uniformMatrix4fv(vmLoc, false, vMatrix.elements);
        gl.uniform1i(textureLoc, 0);

        // pass variables determined at runtime
        for (var i= 0; i<nDrawables; i++){
            // pass model matrix
            var mMatrix=modelTransformations[i];
            gl.uniformMatrix4fv(mmLoc, false, mMatrix.elements);                        
            drawables[i].draw();
        }
        gl.useProgram(null);
    }




    this.getBounds=function() // Computes Model bounding box
    {       
        var xmin, xmax, ymin, ymax, zmin, zmax;
        var firstvertex = true;
        var nNodes = (model.nodes)?model.nodes.length:1;
        for (var k=0; k<nNodes; k++){
            var m = new Matrix4();
            if (model.nodes)m.elements=new Float32Array(model.nodes[k].modelMatrix);
            //console.log(model.nodes[k].modelMatrix);
            var nMeshes = (model.nodes)?model.nodes[k].meshIndices.length:model.meshes.length;
            for (var n = 0; n < nMeshes; n++){
                var index = (model.nodes)?model.nodes[k].meshIndices[n]:n;
                var mesh = model.meshes[index];
                for(var i=0;i<mesh.vertexPositions.length; i+=3){
                    var vertex = m.multiplyVector4(new Vector4([mesh.vertexPositions[i],mesh.vertexPositions[i+1],mesh.vertexPositions[i+2],1])).elements;
                    //if (i==0){
                    //  console.log([mesh.vertexPositions[i],mesh.vertexPositions[i+1],mesh.vertexPositions[i+2]]);
                    //  console.log([vertex[0], vertex[1], vertex[2]]);
                    //}
                    if (firstvertex){
                        xmin = xmax = vertex[0];
                        ymin = ymax = vertex[1];
                        zmin = zmax = vertex[2];
                        firstvertex = false;
                    }
                    else{
                        if (vertex[0] < xmin) xmin = vertex[0];
                        else if (vertex[0] > xmax) xmax = vertex[0];
                        if (vertex[1] < ymin) ymin = vertex[1];
                        else if (vertex[1] > ymax) ymax = vertex[1];
                        if (vertex[2] < zmin) zmin = vertex[2];
                        else if (vertex[2] > zmax) zmax = vertex[2];
                    }
                }
            }
        }
        var dim= {};
        dim.min = [xmin,ymin,zmin];
        dim.max = [xmax,ymax,zmax];
        //console.log(dim);
        return dim;
    }

    // Load texture image and create/return texture object
    function createTexture(imageFileName)
    {
        var tex = gl.createTexture();
        var img = new Image();
        img.onload = function(){
            gl.bindTexture(gl.TEXTURE_2D, tex);
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,true);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
            gl.bindTexture(gl.TEXTURE_2D, null);
        }
        img.src = imageFileName;
        return tex;
    }
}
È stato utile?

Soluzione

The error means one of your indices is too large for the buffers you currently have attached.

Example: Imagine you have a position buffer with 3 positions in it

 [0.123, 0.010, 0.233,
  0.423, 0.312, 0.344,
  0.933, 1.332, 0.101]

Now imagine you make an index buffer

 [0, 1, 3]

You've only got 3 positions so the only valid indices are 0, 1, and 2. 3 is out of range. That's the error your getting.

Some possibilities:

  1. Your data could just be bad. Check your indices

  2. You drew a model with less vertices but more attributes, then drew a different model with more vertices but less attributes. You left the attributes for the previous model on while drawing the 2nd model.

In other words

// setup first model with only 3 vertices, both positions and colors.
gl.enableVertexAttribArray(0);
gl.bindBuffer(gl.BUFFER_ARRAY, bufferWith3Positions);
gl.vertexAttribPointer(0, ....);
gl.enableVertexAttribArray(1);
gl.bindBuffer(gl.BUFFER_ARRAY, bufferWith3Colors);
gl.vertexAttribPointer(1, ....);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesForFirstModel);

// setup first model with 6 vertices but no colors
gl.bindBuffer(gl.BUFFER_ARRAY, bufferWith6Positions);
gl.vertexAttribPointer(0, ....);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesForSecondModel);

You'll get an error because attrib #1 is still referencing bufferWith3Colors. You need to turn that attribute off.

gl.disableVertexAttribArray(1);

Note: That assumes the shader is still using attribute #1. If it's not you shouldn't get an error even if bufferWith3Colors is still attached to attribute #1.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top