Shaders : Best practice to store them

2019-08-14 18:48发布

I am learning webgl with lessons from this site.

To store the shaders, the author declares them in a <script> tag :

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

Then uses some javascript code to retrieve them:

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

I find it quite complex to retrieve the shader, so the question is quite simple :

What is the best practice to retrieve and compile shaders? Is this the standard way? I would appreciate to be able to store shaders in other files.

1条回答
Anthone
2楼-- · 2019-08-14 19:55

Im not very good in webGL, but I did some stuff. I was asking myself that question too. There are 3 common ways, that I know. First one is the basic one that you presented here. Yeah, it is messy, it is complicated, but it have some advantages. Shader code is easy to maintain.

Second way that I found is put shader code into array, then join the array immediately, so it become a string. After that, you can pass string to gl.createShader function.

This technique is pretty common in three.js javascript library, where is plenty of shader code. It keeps shader human readable and not that messy as the first one, but maintaining shader code is a little bit harder, as you probably see. The main point is, that it will allows you to keep everything in one single javascript file, which is desired behavior of every good library.

Small example, this is our vertex shader:

var vertexShader = [
    "attribute vec3 aVertexPosition;",

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

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

EDIT

Someone has found a much better way of doing this!

var vertexShader = `attribute vec3 aVertexPosition;

uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

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

EDIT END

Function, that can handle shaders

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

Simple function call

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

But you are probably looking for something different. So the best option for you is to make file like "myvertexshader" and then call ajax to load that file into variable. Jquery is good option.

jQuery.get('myvertexshader', callback);

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

    ...
}

Then your shader code is separated from javascript. You can also setup your own file extension and make different rules in your IDE for shader development, which is good idea for rich shaders.

PS: I heard some rummors that blob files will be able to compile shaders (maybe they already are, Im not sure).

查看更多
登录 后发表回答