着色器:存储它们的最佳实践

时间:2013-08-07 19:20:47

标签: javascript webgl

我正在使用this site.

的课程学习webgl

要存储着色器,作者会在<script>标记中声明它们:

<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;

uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

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

然后使用一些javascript代码来检索它们:

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

我发现检索着色器非常复杂,所以问题很简单:

检索和编译着色器的最佳做法是什么?这是标准方法吗?我很高兴能够将着色器存储在其他文件中。

1 个答案:

答案 0 :(得分:2)

我对webGL不是很好,但我做了一些事情。我也问自己这个问题。 我知道有三种常见的方法。第一个是你在这里提出的基本一个。 是的,它很乱,很复杂,但它有一些优点。着色器代码易于维护。

我找到的第二种方法是将着色器代码放入数组中,然后立即加入数组,使其成为一个字符串。之后,您可以将字符串传递给gl.createShader函数。

这种技术在three.js javascript库中很常见,其中有很多着色器代码。它保持着色器的可读性,而不是像第一个那样凌乱,但维护着色器代码有点难,正如您可能看到的那样。重点是,它将允许您将所有内容保存在一个单独的javascript文件中,这是每个好库的理想行为。

小例子,这是我们的顶点着色器:

var vertexShader = [
    "attribute vec3 aVertexPosition;",

    "uniform mat4 uMVMatrix;",
    "uniform mat4 uPMatrix;",

    "void main(void) {",
        "gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);",
    "}"
].join( "\n" );

修改

有人发现了更好的方法!

var vertexShader = `attribute vec3 aVertexPosition;

uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

void main(void) {
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
}`;

编辑结束

可以处理着色器的函数

function getShader(gl, source, type) {

    var shader;
    if (type == "fragment") {
        shader = gl.createShader(gl.FRAGMENT_SHADER);
    } else if (type == "vertex") {
        shader = gl.createShader(gl.VERTEX_SHADER);
    } else {
        return null;
    }

    gl.shaderSource(shader, source);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert(gl.getShaderInfoLog(shader));
        return null;
    }

    return shader;
}

简单的函数调用

// var fragmentShader = getShader(gl, fragmentShader, "fragment");
var vertexShader = getShader(gl, vertexShader, "vertex");

但你可能正在寻找不同的东西。因此,最好的选择是将文件设置为“myvertexshader”,然后调用ajax将该文件加载到变量中。 Jquery是不错的选择。

jQuery.get('myvertexshader', callback);

function callback(source) {
    var shader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);

    ...
}

然后您的着色器代码与javascript分开。您还可以设置自己的文件扩展名,并在IDE中制作不同的规则以进行着色器开发,这对于富着色器很有用。

PS:我听到一些谣言说blob文件能够编译着色器(也许它们已经是,我不确定)。