1

我正在通过这个网站的课程学习 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;
}

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

检索和编译着色器的最佳实践是什么?这是标准方式吗?我希望能够将着色器存储在其他文件中。

4

1 回答 1

3

我在 webGL 方面不是很好,但我做了一些事情。我也在问自己这个问题。我知道有3种常见的方法。第一个是您在此处介绍的基本内容。是的,它很乱,很复杂,但它有一些优点。着色器代码易于维护。

我发现的第二种方法是将着色器代码放入数组中,然后立即加入数组,使其成为一个字符串。之后,您可以将字符串传递给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 文件将能够编译着色器(也许他们已经是,我不确定)。

于 2013-08-07T21:34:49.223 回答