在我的WebGL代码中找不到bug

时间:2017-05-21 12:29:44

标签: webgl

我尝试学习WebGL。我读了这篇教程https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL 但为了更好地学习,我编写自己的代码,而不是从教程中复制过去的代码。我在这里上传了我的代码https://github.com/Azaravicius/GLCanvas 文件glUtils.js和sylvester.js来自教程作为依赖项。 文件glcanvas.js和run.js都有我的代码。

代码应该像教程一样用四种颜色绘制正方形,但我在Firefox中使用红色正方形,在Chromium中使用黑色正方形。

<script id="shader-vs" type="x-shader/x-vertex">
     attribute vec3 aVertexPosition;
     attribute vec4 aVertexColor;
     uniform mat4 uMVMatrix;
     uniform mat4 uPMatrix;
     varying lowp vec4 vColor;

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

我认为vertext着色器不能获得aVertexColor的值,但是这里没有控制台中的错误。为了测试我已经将代码更改为vColor = vec4(aVertexPosition,1.0);它起作用了。因此片段着色器从片段着色器获取数据。 我不知道如何在代码中找到bug。

class GLCanvas {
  constructor(canvasID, clear = [1.0, 1.0, 1.0, 1.0], contextAttributes = {}) {
    // WebGLRenderingContext
    this.gl = null;
    // Object to hold all created programs. {programName:program}
    this.programs = {};
    // All variables of current program {variableName: variableLoction}
    this.variables = {};
    // Buffers in use
    this.buffers = {};
    // HTML5 canvas element
    this.canvas = document.getElementById(canvasID);

    if (!this.canvas) {
      console.log("ERROR: Can't find canvas with id", canvasID);
      return;
    }
    // contextAttributes = {alpha: true, depth: true, stencil: false, antialias: true, 
    //                      premultipliedAlpha: true, preserveDrawingBuffer: false, 
    //                      failIfMajorPerformanceCaveat: false }
    this.gl = this.canvas.getContext('webgl', contextAttributes) ||
      this.canvas.getContext('experimental-webgl', contextAttributes);
    if (!this.gl) {
      console.log("ERROR: Unable to get WebGL context. Your browser may not support it.");
      return;
    }
    this.gl.clearColor(clear[0], clear[1], clear[2], clear[3]);
    this.gl.clear(this.gl.COLOR_BUFFER_BIT);
  }

  initProgram(vShader, fShader, program) {
    var fragmentShader, vertexShader;
    vertexShader = this.initShader(vShader, this.gl.VERTEX_SHADER);
    if (!vertexShader) {
      console.log('Vertex shader not loaded.');
      return;
    }
    fragmentShader = this.initShader(fShader, this.gl.FRAGMENT_SHADER);
    if (!fragmentShader) {
      console.log('Fragment shader not loaded.');
      return;
    }

    this.programs[program] = this.gl.createProgram();
    this.gl.attachShader(this.programs[program], vertexShader);
    this.gl.attachShader(this.programs[program], fragmentShader);
    this.gl.linkProgram(this.programs[program]);
    if (!this.gl.getProgramParameter(this.programs[program], this.gl.LINK_STATUS)) {
      console.log('Unable to initialize the shader program: ' + this.gl.getProgramInfoLog(this.programs[program]));
      this.gl.deleteProgram(this.programs[program]);
      delete this.programs[program];
      return;
    }
  }

  initShader(shaderScript, type) {
    var shader = this.gl.createShader(type);
    this.gl.shaderSource(shader, shaderScript);
    this.gl.compileShader(shader);
    if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
      console.log('An error occurred compiling the shaders: ' + this.gl.getShaderInfoLog(shader));
      this.gl.deleteShader(shader);
      return null;
    }
    return shader;
  }

  useProgram(program, variables) {
    var attr;
    this.gl.useProgram(this.programs[program]);
    for (attr in variables["attributes"]) {
      this.variables[variables["attributes"][attr]] = this.gl.getAttribLocation(this.programs[program], variables["attributes"][attr]);
      if (this.variables[variables["attributes"][attr]] == -1) {
        console.log(variables["attributes"][attr], " vertex position attribut not found.");
        continue;
      }
      this.gl.enableVertexAttribArray(this.variables[attr]);
    }
    for (attr in variables["uniforms"]) {
      this.variables[variables["uniforms"][attr]] = this.gl.getUniformLocation(this.programs[program], variables["uniforms"][attr]);
      if (!this.variables[variables["uniforms"][attr]]) {
        console.log(variables["uniforms"][attr], " uniform attribut not found.");
        continue;
      }
    }
  }

  // Create and bind buffer and initializes and creates the buffer object's data store.
  // Parameters:
  // name - buffer name
  // data - An ArrayBuffer that will be copied into the data store.
  // target - A GLenum specifying the binding point (target). Default ARRAY_BUFFER.
  // usage - A GLenum specifying the usage pattern of the data store. Default STATIC_DRAW
  initBuffer(name, data, target = this.gl.ARRAY_BUFFER, usage = this.gl.STATIC_DRAW) {
    this.buffers[name] = this.gl.createBuffer();
    this.gl.bindBuffer(target, this.buffers[name]);
    this.gl.bufferData(target, new Float32Array(data), usage);
  }

  //resize canvas and viewport.
  // Parameters:
  // width - width to resize. Default window.innerWidth.
  // height - height to resize. Default window.innerHeight.
  // return value - None.
  resize(width = window.innerWidth, height = window.innerHeight) {
    this.canvas.width = width;
    this.canvas.height = height;
    this.gl.viewport(0, 0, width, height);
  }

  // Clear COLOR_BUFFER_BIT and DEPTH_BUFFER_BIT.
  // return value - None.
  clear() {
    // COLOR_BUFFER_BIT; STENCIL_BUFFER_BIT; DEPTH_BUFFER_BIT
    this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
  }

  // Parameters:
  // name - buffer name
  // location - string, name of the vertex attribute that is to be modified.
  // size - A GLint specifying the number of components per vertex attribute. Default 3.
  // type - A GLenum specifying the data type of each component in the array. Default FLOAT.
  // normalized - A GLboolean specifying whether integer data values should be normalized when being casted to a float. Default false.
  // stride - A GLsizei specifying the offset in bytes between the beginning of consecutive vertex attributes. Cannot be larger than 255. Default 0.
  // offset - A GLintptr specifying an offset in bytes of the first component in the vertex attribute array. Must be a multiple of type. Default 0.
  // return value - None.
  useBuffer(location, size = 3, target = this.gl.ARRAY_BUFFER, type = this.gl.FLOAT, normalized = false, stride = 0, offset = 0) {
    this.gl.bindBuffer(target, this.buffers[location]);
    this.gl.vertexAttribPointer(this.variables[location], size, type, normalized, stride, offset);
  }

  // Parameters:
  // location - string, name of the uniform attribute to modify.
  // value - A Float32Array of float values.
  // transpose - A GLboolean specifying whether to transpose the matrix. Default false.
  // return value - None.
  uniformMatrix4fv(location, value, transpose = false) {
    this.gl.uniformMatrix4fv(this.variables[location], transpose, new Float32Array(value));
  }

  // Returns canvas aspect ratio of width and height.
  aspect() {
    return this.canvas.width / this.canvas.height;
  }

}

var canvas;
var programs = ["first"];
var para = {
  "first": {
    "var": {
      "attributes": ["aVertexPosition", "aVertexColor"],
      "uniforms": ["uPMatrix", "uMVMatrix"]
    },
    "shaders": {
      "vs": "shader-vs",
      "fs": "shader-fs"
    }
  }
};
var vertices = [
  0.9, 0.9, 0.0, -0.9, 0.9, 0.0,
  0.9, -0.9, 0.0, -0.9, -0.9, 0.0
];
var colors = [
  1.0, 1.0, 1.0, 1.0, // white
  1.0, 0.0, 0.0, 1.0, // red
  0.0, 1.0, 0.0, 1.0, // green
  0.0, 0.0, 1.0, 1.0 // blue
];


function start() {
  canvas = new GLCanvas("canvasGL");
  if (canvas.gl) {
    canvas.initProgram(getShader(para[programs[0]]["shaders"]["vs"]), getShader(para[programs[0]]["shaders"]["fs"]), programs[0]);
    canvas.useProgram(programs[0], para[programs[0]]["var"]);
    canvas.initBuffer(para[programs[0]]["var"]["attributes"][0], vertices);
    canvas.initBuffer(para[programs[0]]["var"]["attributes"][1], colors);

    window.addEventListener('resize', draw, false);
    draw();
  }
}

function getShader(id) {
  var shaderScript = document.getElementById(id);
  if (!shaderScript) {
    console.log('ERROR: Shader not loaded.');
    return null;
  }
  return shaderScript.text;
}

function draw() {
  canvas.resize();
  var perspective = makePerspective(30, canvas.aspect(), 0.1, 100);
  canvas.clear();
  loadIdentity();
  mvTranslate([0.0, 0.0, -3.5]);

  canvas.useBuffer(para[programs[0]]["var"]["attributes"][0]);
  canvas.useBuffer(para[programs[0]]["var"]["attributes"][1], 4);

  canvas.uniformMatrix4fv(para[programs[0]]["var"]["uniforms"][0], perspective.flatten());
  canvas.uniformMatrix4fv(para[programs[0]]["var"]["uniforms"][1], mvMatrix.flatten());

  canvas.gl.drawArrays(canvas.gl.TRIANGLE_STRIP, 0, 4);
}

// augment Sylvester some
Matrix.Translation = function(v) {
  if (v.elements.length == 2) {
    var r = Matrix.I(3);
    r.elements[2][0] = v.elements[0];
    r.elements[2][1] = v.elements[1];
    return r;
  }

  if (v.elements.length == 3) {
    var r = Matrix.I(4);
    r.elements[0][3] = v.elements[0];
    r.elements[1][3] = v.elements[1];
    r.elements[2][3] = v.elements[2];
    return r;
  }

  throw "Invalid length for Translation";
}

Matrix.prototype.flatten = function() {
  var result = [];
  if (this.elements.length == 0)
    return [];


  for (var j = 0; j < this.elements[0].length; j++)
    for (var i = 0; i < this.elements.length; i++)
      result.push(this.elements[i][j]);
  return result;
}

Matrix.prototype.ensure4x4 = function() {
  if (this.elements.length == 4 &&
    this.elements[0].length == 4)
    return this;

  if (this.elements.length > 4 ||
    this.elements[0].length > 4)
    return null;

  for (var i = 0; i < this.elements.length; i++) {
    for (var j = this.elements[i].length; j < 4; j++) {
      if (i == j)
        this.elements[i].push(1);
      else
        this.elements[i].push(0);
    }
  }

  for (var i = this.elements.length; i < 4; i++) {
    if (i == 0)
      this.elements.push([1, 0, 0, 0]);
    else if (i == 1)
      this.elements.push([0, 1, 0, 0]);
    else if (i == 2)
      this.elements.push([0, 0, 1, 0]);
    else if (i == 3)
      this.elements.push([0, 0, 0, 1]);
  }

  return this;
};

Matrix.prototype.make3x3 = function() {
  if (this.elements.length != 4 ||
    this.elements[0].length != 4)
    return null;

  return Matrix.create([
    [this.elements[0][0], this.elements[0][1], this.elements[0][2]],
    [this.elements[1][0], this.elements[1][1], this.elements[1][2]],
    [this.elements[2][0], this.elements[2][1], this.elements[2][2]]
  ]);
};

Vector.prototype.flatten = function() {
  return this.elements;
};

function mht(m) {
  var s = "";
  if (m.length == 16) {
    for (var i = 0; i < 4; i++) {
      s += "<span style='font-family: monospace'>[" + m[i * 4 + 0].toFixed(4) + "," + m[i * 4 + 1].toFixed(4) + "," + m[i * 4 + 2].toFixed(4) + "," + m[i * 4 + 3].toFixed(4) + "]</span><br>";
    }
  } else if (m.length == 9) {
    for (var i = 0; i < 3; i++) {
      s += "<span style='font-family: monospace'>[" + m[i * 3 + 0].toFixed(4) + "," + m[i * 3 + 1].toFixed(4) + "," + m[i * 3 + 2].toFixed(4) + "]</font><br>";
    }
  } else {
    return m.toString();
  }
  return s;
}

//
// gluLookAt
//
function makeLookAt(ex, ey, ez,
  cx, cy, cz,
  ux, uy, uz) {
  var eye = $V([ex, ey, ez]);
  var center = $V([cx, cy, cz]);
  var up = $V([ux, uy, uz]);

  var mag;

  var z = eye.subtract(center).toUnitVector();
  var x = up.cross(z).toUnitVector();
  var y = z.cross(x).toUnitVector();

  var m = $M([
    [x.e(1), x.e(2), x.e(3), 0],
    [y.e(1), y.e(2), y.e(3), 0],
    [z.e(1), z.e(2), z.e(3), 0],
    [0, 0, 0, 1]
  ]);

  var t = $M([
    [1, 0, 0, -ex],
    [0, 1, 0, -ey],
    [0, 0, 1, -ez],
    [0, 0, 0, 1]
  ]);
  return m.x(t);
}

//
// glOrtho
//
function makeOrtho(left, right,
  bottom, top,
  znear, zfar) {
  var tx = -(right + left) / (right - left);
  var ty = -(top + bottom) / (top - bottom);
  var tz = -(zfar + znear) / (zfar - znear);

  return $M([
    [2 / (right - left), 0, 0, tx],
    [0, 2 / (top - bottom), 0, ty],
    [0, 0, -2 / (zfar - znear), tz],
    [0, 0, 0, 1]
  ]);
}

//
// gluPerspective
//
function makePerspective(fovy, aspect, znear, zfar) {
  var ymax = znear * Math.tan(fovy * Math.PI / 360.0);
  var ymin = -ymax;
  var xmin = ymin * aspect;
  var xmax = ymax * aspect;

  return makeFrustum(xmin, xmax, ymin, ymax, znear, zfar);
}

//
// glFrustum
//
function makeFrustum(left, right,
  bottom, top,
  znear, zfar) {
  var X = 2 * znear / (right - left);
  var Y = 2 * znear / (top - bottom);
  var A = (right + left) / (right - left);
  var B = (top + bottom) / (top - bottom);
  var C = -(zfar + znear) / (zfar - znear);
  var D = -2 * zfar * znear / (zfar - znear);

  return $M([
    [X, 0, A, 0],
    [0, Y, B, 0],
    [0, 0, C, D],
    [0, 0, -1, 0]
  ]);
}

//
// glOrtho
//
function makeOrtho(left, right, bottom, top, znear, zfar) {
  var tx = -(right + left) / (right - left);
  var ty = -(top + bottom) / (top - bottom);
  var tz = -(zfar + znear) / (zfar - znear);

  return $M([
    [2 / (right - left), 0, 0, tx],
    [0, 2 / (top - bottom), 0, ty],
    [0, 0, -2 / (zfar - znear), tz],
    [0, 0, 0, 1]
  ]);
}

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());
}
body {
  height: 100%;
  width: 100%;
  margin: 0px;
  padding: 0px;
  overflow: hidden;
  /*  Disable scrollbars */
  display: block;
  /* No floating content on sides */
  border: 0;
}

* {
  box-sizing: border-box;
}

canvas {
  position: absolute;
  left: 0px;
  top: 0px;
}
<!DOCTYPE html>
<html>

<head>
  <title>Geo</title>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <link rel="stylesheet" type="text/css" href="style.css" />
</head>

<body onload="start()">
  <canvas id="canvasGL">
            Your browser does not support the HTML5 canvas tag.
        </canvas>
  <script id="shader-vs" type="x-shader/x-vertex">
    attribute vec3 aVertexPosition; attribute vec4 aVertexColor; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; varying lowp vec4 vColor; void main(void) { gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); vColor = aVertexColor; }
  </script>
  <script id="shader-fs" type="x-shader/x-fragment">
    varying lowp vec4 vColor; void main(void) { gl_FragColor = vColor; }
  </script>
  <script src="https://mdn.github.io/webgl-examples/tutorial/sylvester.js"></script>
</body>

</html>

1 个答案:

答案 0 :(得分:0)

使用错误的索引在useProgram函数中获取属性位置引用。

unset x y ; seq 250 5 280 | grep "$x" | grep "$y" | grep "$z"
270
275

小心......