着色器流程

上一章里我们用WebGL绘制了一个10像素的红色正方形。 在绘制过程中我们使用到一个新的概念,着色器。对着色器的概念我们也做了解释。
在三维场景中,仅仅用线条和颜色把图形画出来是远远不够的,你必须考虑光照射上去之后,或者观察者视角发生了变化, 对场景会有什么影响。 类型我们现实中看待物体一样。着色器可以高度灵活的完成这些工作,提供各种渲染效果。
js读取了着色器的相关信息,然后在WebGL系统中可以调用。

image.png

这就是整个流程,菱形部分为说明,矩形为具体流程。
简化之后就是

  1. 执行加载的js程序
  2. 顶点着色器,片元着色器
  3. 颜色缓存区

着色器代码解析

结合刚才的知识,我们再来看下上一章说着色器部分的代码

  1. //顶点着色器程序
  2. var VSHADER_SOURCE="" +
  3. "void main(){\n" +
  4. " gl_Position = vec4(0.0,0.0,0.0,1.0);\n" +//设置坐标
  5. " gl_PointSize = 10.0;\n" +//设置尺寸
  6. "}\n";
  7. //片元着色器程序
  8. var FSHADER_SOURCE = "" +
  9. "void main(){\n" +
  10. " gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n" +//设置颜色
  11. "}\n";
  12. function main() {
  13. //首先获取到canvas的dom对象
  14. var canvas = document.getElementById("canvas");
  15. //获取到WebGL的上下文
  16. var gl = getWebGLContext(canvas);
  17. //不支持WebGL的浏览器将打印一个错误,并结束代码运行
  18. if (!gl) {
  19. console.log("浏览器不支持WebGL");
  20. return;
  21. }
  22. //初始化着色器
  23. if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
  24. console.log("初始化着色器失败");
  25. return;
  26. }
  27. //指定一个覆盖(清空)canvas的颜色
  28. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  29. //执行清空
  30. gl.clear(gl.COLOR_BUFFER_BIT);
  31. //绘制一个点
  32. gl.drawArrays(gl.POINTS,0,1);
  33. }

顶点着色器代码位于第2到6行, 片元着色器位于第10到13行,实际上,它们是以js字符串形式编写的着色器语言程序。
这样主程序就可以将它们传给WebGL系统。
在前面说到过,着色器是类似于c的OpenGL ES着色器语言(GLSL ES)来编写。着色器的语言很简单,稍微懂一点c或者js就可以理解。

初始化着色器

在研究着色器内部细节之前我们先看一下main函数的执行流程。

获取canvas元素 => 获取webGL绘图上下文 => 初始化着色器 => 设置canvas背景色 => 清楚canvas => 绘图

第三步初始化着色器, 调用了辅助函数initShaders()对字符串形式的着色器进行了初始化。该辅助函数定义在cuon.util.js中

  1. /**
  2. * Create a program object and make current
  3. * @param gl GL context
  4. * @param vshader a vertex shader program (string)
  5. * @param fshader a fragment shader program (string)
  6. * @return true, if the program object was created and successfully made current
  7. */
  8. function initShaders(gl, vshader, fshader) {
  9. var program = createProgram(gl, vshader, fshader);
  10. if (!program) {
  11. console.log('Failed to create program');
  12. return false;
  13. }
  14. gl.useProgram(program);
  15. gl.program = program;
  16. return true;
  17. }
  18. /**
  19. * Create the linked program object
  20. * @param gl GL context
  21. * @param vshader a vertex shader program (string)
  22. * @param fshader a fragment shader program (string)
  23. * @return created program object, or null if the creation has failed
  24. */
  25. function createProgram(gl, vshader, fshader) {
  26. // Create shader object
  27. var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
  28. var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
  29. if (!vertexShader || !fragmentShader) {
  30. return null;
  31. }
  32. // Create a program object
  33. var program = gl.createProgram();
  34. if (!program) {
  35. return null;
  36. }
  37. // Attach the shader objects
  38. gl.attachShader(program, vertexShader);
  39. gl.attachShader(program, fragmentShader);
  40. // Link the program object
  41. gl.linkProgram(program);
  42. // Check the result of linking
  43. var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
  44. if (!linked) {
  45. var error = gl.getProgramInfoLog(program);
  46. console.log('Failed to link program: ' + error);
  47. gl.deleteProgram(program);
  48. gl.deleteShader(fragmentShader);
  49. gl.deleteShader(vertexShader);
  50. return null;
  51. }
  52. return program;
  53. }
  54. /**
  55. * Create a shader object
  56. * @param gl GL context
  57. * @param type the type of the shader object to be created
  58. * @param source shader program (string)
  59. * @return created shader object, or null if the creation has failed.
  60. */
  61. function loadShader(gl, type, source) {
  62. // Create shader object
  63. var shader = gl.createShader(type);
  64. if (shader == null) {
  65. console.log('unable to create shader');
  66. return null;
  67. }
  68. // Set the shader program
  69. gl.shaderSource(shader, source);
  70. // Compile the shader
  71. gl.compileShader(shader);
  72. // Check the result of compilation
  73. var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  74. if (!compiled) {
  75. var error = gl.getShaderInfoLog(shader);
  76. console.log('Failed to compile shader: ' + error);
  77. gl.deleteShader(shader);
  78. return null;
  79. }
  80. return shader;
  81. }

参数
gl: 指定渲染上线文
vshader: 指定顶点着色器程序代码
fshader: 指定片元着色器程序代码

返回值
true 初始化着色器成功
false 初始化着色器失败

后面我们会研究这个函数的内部细节, 现在只需要知道这个函数初始化了着色器。供我们使用即可。

WebGL系统由两部分组成, 顶点着色器和片元着色器。 这是简化之后的。初始化着色器之前, 顶点着色器和片元着色器都是空白的,我们需要将字符串形式的着色器代码从js传给WebGL系统, 并建立着色器, 这就是initShaders()所做的事情。 注意,着色器是运行在WebGL系统中,而不是js中。