WebGL错误:vertexAttribPointer必须具有有效的GL_ARRAY_BUFFER绑定

时间:2016-04-01 15:22:32

标签: binding webgl

我参加了一个网络演示并尝试创建一个javascript平面图对象。

失败并出现以下错误:

vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding

我尝试创建一个MWE(或更准确地说,一个MNonEW),但演示代码包含两个库。我会把它们排除在外,但如果错误不明显,而且你需要工作代码,我也可以粘贴它们。我现在将提供文件的链接。

MWE.html

<!doctype html>
<html>
  <head>
    <title>WebGL Demo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" href="../webgl.css" type="text/css">
    <script src="../sylvester.js" type="text/javascript"></script>
    <script src="../glUtils.js" type="text/javascript"></script>
    <script src="mwe.js" type="text/javascript"></script>

    <script id="shader-fs" type="x-shader/x-fragment">
      varying highp vec2 vTextureCoord;

      uniform sampler2D uSampler;

      void main(void) {
        gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
      }
    </script>

    <!-- Vertex shader program -->
    <script id="shader-vs" type="x-shader/x-vertex">
      attribute vec3 aVertexPosition;
      attribute vec2 aTextureCoord;

      uniform mat4 uMVMatrix;
      uniform mat4 uPMatrix;

      varying highp vec2 vTextureCoord;

      void main(void) {
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
        vTextureCoord = aTextureCoord;
      }
    </script>
  </head>

  <body onload="start()">
    <canvas id="glcanvas" width="640" height="480">
      Your browser doesn't appear to support the <code>&lt;canvas&gt;</code> element.
    </canvas>
  </body>
</html>

MWE.js

var canvas;
var gl;

var mvMatrix;
var shaderProgram;
var vertexPositionAttribute;
var textureCoordAttribute;
var perspectiveMatrix;

var floorplan;
var mvMatrixStack = [];

function mvPushMatrix(m) {
  if (m) {
    mvMatrixStack.push(m.dup());
    mvMatrix = m.dup();
  } else {
    mvMatrixStack.push(mvMatrix.dup());
  }
}

function mvPopMatrix() {
  if (!mvMatrixStack.length) {
    throw("Can't pop from an empty matrix stack.");
  }

  mvMatrix = mvMatrixStack.pop();
  return mvMatrix;
}

function mvRotate(angle, v) {
  var inRadians = angle * Math.PI / 180.0;
  var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4();
  multMatrix(m);
}

function start() {
  canvas = document.getElementById("glcanvas");
  initWebGL(canvas);      // Initialize the GL context
  if (gl) {
    gl.clearColor(0.0, 0.0, 0.0, 1.0);  // Clear to black, fully opaque
    gl.clearDepth(1.0);                 // Clear everything
    gl.enable(gl.DEPTH_TEST);           // Enable depth testing
    gl.depthFunc(gl.LEQUAL);            // Near things obscure far things
    initShaders();
    initBuffers();
    setInterval(drawScene, 15);
  }
}

function initWebGL() {
  gl = null;

  try {
    gl = canvas.getContext("experimental-webgl");
  }
  catch(e) {
  }

  // If we don't have a GL context, give up now

  if (!gl) {
    alert("Unable to initialize WebGL. Your browser may not support it.");
  }
}


function initBuffers() {
    var floorcoords = [
    [0, 0, 10,0, 10, 10, 0, 10],
    [-5,0, -5,5, -10,-5, -10,0]
    ];
    var wallColor = [1,0,0,0];
    floorplan = new Floorplan(floorcoords, 8, wallColor);
}

function createVertexBuffer(vertices) {
    var b = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, b);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    return b;
}

function Floorplan(coords, height, color) {
    var walls = [];
    var colors = [];
    var index = [0, 1, 2,      0, 2, 3];
    var indices = [];
    for (var i = 0; i < coords.length; i++) {
    for (var j = 0; j < coords[i].length; j+=4) {
        walls.push(coords[j], coords[j+1], 0);
        walls.push(coords[j+2], coords[j+3], 0);
        walls.push(coords[j+2], coords[j+3], height);
        walls.push(coords[j], coords[j+1], height);
        indices = indices.concat(index);
        for (var j = 0; j < 6; j++)
        colors = colors.concat(color);
    }
    }
    this.colorBuf = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuf);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

    this.walls = createVertexBuffer(walls);
    this.indices = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indices);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
          new Uint16Array(indices), gl.STATIC_DRAW);
    console.log(indices.length + "," + colors.length);
}

Floorplan.prototype.draw = function() {
    gl.bindBuffer(gl.ARRAY_BUFFER, this.walls);
    gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);    
    gl.bindBuffer(gl.ARRAY_BUFFER, this.colors);
    gl.vertexAttribPointer(this.colorBuf, 4, gl.FLOAT, false, 0, 0);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indices);
    setMatrixUniforms();
    gl.drawElements(gl.TRIANGLES, 24, gl.UNSIGNED_SHORT, 0);
}

var z = -6;
function drawScene() {
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0);
    loadIdentity();
    mvTranslate([0.0, 0.0, z]);
    floorplan.draw();
}

function initShaders() {
  var fragmentShader = getShader(gl, "shader-fs");
  var vertexShader = getShader(gl, "shader-vs");

  // Create the shader program

  shaderProgram = gl.createProgram();
  gl.attachShader(shaderProgram, vertexShader);
  gl.attachShader(shaderProgram, fragmentShader);
  gl.linkProgram(shaderProgram);

  // If creating the shader program failed, alert

  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    alert("Unable to initialize the shader program.");
  }

  gl.useProgram(shaderProgram);

  vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
  gl.enableVertexAttribArray(vertexPositionAttribute);

  textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
  gl.enableVertexAttribArray(textureCoordAttribute);
}

//
// getShader
//
// Loads a shader program by scouring the current document,
// looking for a script with the specified ID.
//
function getShader(gl, id) {
  var shaderScript = document.getElementById(id);

  // Didn't find an element with the specified ID; abort.

  if (!shaderScript) {
    return null;
  }

  // Walk through the source element's children, building the
  // shader source string.

  var theSource = "";
  var currentChild = shaderScript.firstChild;

  while(currentChild) {
    if (currentChild.nodeType == 3) {
      theSource += currentChild.textContent;
    }

    currentChild = currentChild.nextSibling;
  }

  // Now figure out what type of shader script we have,
  // based on its MIME type.

  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;  // Unknown shader type
  }

  gl.shaderSource(shader, theSource);  // Send the source to the shader object
  gl.compileShader(shader);            // Compile the shader program

  // See if it compiled successfully

  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
    return null;
  }

  return shader;
}

//
// Matrix utility functions
//

function loadIdentity() {
  mvMatrix = Matrix.I(4);
}

function multMatrix(m) {
  mvMatrix = mvMatrix.x(m);
}

function mvTranslate(v) {
  multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());
}

function setMatrixUniforms() {
  var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
  gl.uniformMatrix4fv(pUniform, false, new Float32Array(perspectiveMatrix.flatten()));

  var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
  gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten()));
}

此演示代码中使用的库来自: https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial

2 个答案:

答案 0 :(得分:0)

gl.vertexAttribPointer()将着色器中定义的顶点属性的索引作为其第一个参数。

例如,您对gl.vertexAttribPointer()的第一次调用是这样的:

// In initShaders()...
vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(vertexPositionAttribute);
// vertexPositionAttribute now contains an index to the attribute
// "aVertexPosition" in the vertex shader
// ...
// Later, in Floorplan.draw():
gl.bindBuffer(gl.ARRAY_BUFFER, this.walls);  // Data from this.walls is bound to gl.ARRAY_BUFFER
gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
// The current gl.ARRAY_BUFFER is bound to "aVertexPosition"

但在你的第二次电话中:

gl.bindBuffer(this.colorBuf, 4, gl.FLOAT, false, 0, 0);

这里的问题是this.colorBuf不是顶点属性的索引。如果我不得不猜测,我会说你的代码最初有一个per-vertex颜色属性,它已被丢弃,有利于纹理坐标。

所以可能只是摆脱那些colorBuf的东西,并将一些数据绑定到aTextureCoord,你可能正在做生意。

答案 1 :(得分:0)

在不查看代码的情况下,特定错误意味着您在调用gl.bindBuffer(gl.ARRAY_BUFFER, someBuffer)之前从未调用gl.vertexBufferPointer

gl.vertexBufferPointer将对gl.ARRAY_BUFFER绑定的最后一个缓冲区的引用复制到属性的缓冲区引用中。

看到这个答案: What is the logic of binding buffers in webgl?