2013-10-13 37 views
2

我想從model.json文件中繪製3d模型(例如房子)。我沒有問題像藍色一樣用一種顏色畫房子。然而,當我嘗試使用,而不是顏色紋理,我收到一個錯誤:WebGL:添加紋理會導致DrawElements錯誤(屬性緩衝區空間不足)

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

我在網上搜索,並嘗試數百種不同的變化,我根本無法突破這個錯誤 - 我沒有足夠的WebGL來看看有什麼不對。有一個包含多個紋理圖像的圖像文件夾,但在這一點上,如果我可以爲整個房子畫一個紋理,我會欣喜若狂。

問題在於renderable.js(附後),但你可以在http://tinyurl.com/mk9vbta訪問所有文件。任何幫助將不勝感激,不知道要去哪裏。

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; 
    } 
} 

回答

3

的錯誤意味着你的指標之一是您目前已附上緩衝區太大。

示例:假設你有3個位置的位置緩衝區它

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

現在想象一下,你做索引緩存

[0, 1, 3] 

你只得到了3個位置,因此只有有效索引是0,1和2. 3超出範圍。這是你得到的錯誤。

一些可能性:

  1. 你的數據可能僅僅是壞的。檢查你的索引

  2. 你畫了一個模型,用更少的頂點,但更多的屬性,然後畫了一個不同的模型,更多的頂點,但較少的屬性。在繪製第二個模型時,您將先前模型的屬性留下。

換句話說

// 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); 

因爲ATTRIB#1仍引用bufferWith3Colors你會得到一個錯誤。您需要關閉該屬性。

gl.disableVertexAttribArray(1); 

注意:假定着色器仍在使用屬性#1。如果不是,即使bufferWith3Colors仍附加到屬性#1,也不應該出現錯誤。

+0

** + 1 **:但值得一提的是,這種行爲特定於WebGL,這是一個額外的安全特性[here](http://www.khronos.org/registry/webgl/specs/latest /1.0/#4.5)。在OpenGL和OpenGL ES中,使用超出範圍的索引是未定義的行爲,即使使用調試輸出擴展,大多數驅動程序(我知道)都不會在發生這種情況時進行報告。 –

+0

如果我有足夠的可信度,我會+1!非常感謝。我回去檢查每個屬性數組的長度,並注意到textureCoordinate數組爲1。所以我看着模型文件,注意到我得到的vertexTextureCoordinates值是一個二維數組 - 我認爲這是因爲模型文件在同一個網格上考慮了多個紋理的可能性。謝謝gman。問題解決了。 –