如何绘制一个点?

上次讲到了如何清空绘图区,这次来讲解如何绘制一个点。我们将在位于远点(0.0, 0.0, 0.0)处绘制一个十个像素大的红色的点。因为WebGL绘制的是三维图行,所以我们需要指定这个点的三维坐标。

在canvas中,我们绘制一个矩形并填充颜色

  1. ctx.fillStyle = 'rgba(0,0,255, 1.0)';
  2. ctx.fillRect(120, 10, 150, 150);

你可能认为WebGL也差不多。 不幸的是,事情并没有这么简单。 WebGL依赖于一种新的称为着色器的绘图机制。
着色器提供了灵活且强大的绘图二维或三维图形的方法。 所有的WebGL程序必须使用它。着色器不仅强大,而且复杂。仅仅通过一条简单的指令是无法实现的。

什么是着色器?

GLSL 的中文意思是 OpenGL 着色语言,英文全称是 OpenGL Shading Language,它是用来在 OpenGL 编写着色器程序的语言。

我们知道了 GLSL 是用来编写着色器程序的语言,那么新的问题来了,着色器程序是用来做什么的呢? 简单地说,着色器程序是在显卡(GPU)上运行的简短程序,代替了 GPU 固定渲染管线的一部分,使 GPU 渲染过程中的某些部分允许开发者通过编程进行控制。

用一句话来说:着色器程序允许我们通过编程来控制 GPU 的渲染。

那么 GPU 渲染过程中的哪些部分允许开发者控制呢?下图是对 WebGL 渲染管线的简单演示:

image.png

上图简单演示了 WebGL 对一个红色三角形的渲染过程,绿色部分为开发者可以通过编程控制的部分:

  • JavaScript 程序
  • 处理着色器需要的顶点坐标法向量颜色纹理等信息,并负责为着色器提供这些数据,上图为了演示方便,只是提供了三角形顶点的位置数据。
  • 顶点着色器
  • 接收 JavaScript 传递过来的顶点信息,将顶点绘制到对应坐标。
  • 图元装配阶段
  • 将三个顶点装配成指定图元类型,上图采用的是三角形图元。
  • 光栅化阶段 将三角形内部区域用空像素进行填充。
  • 片元着色器 为三角形内部的像素填充颜色信息,上图为暗红色。

实际上,对顶点信息的变换操作既可以在 JavaScript 中进行,也可以在着色器程序中进行。通常我们都是在 JavaScript 中生成一个包含了所有变换的最终变换矩阵,然后将该矩阵传递给着色器,利用 GPU 并行计算优势对所有顶点执行变换。

开始绘制一个点

1. 准备着色器代码

我们从着色器程序开始入手,先用GLSL编写顶点着色器片元着色器

  • 顶点着色器

顶点着色器的主要任务是告诉 GPU 在裁剪坐标系的原点(也就是屏幕中心)画一个大小为 10 的点。

  1. void main(){
  2. //声明顶点位置
  3. gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
  4. //声明待绘制的点的大小。
  5. gl_PointSize = 10.0;
  6. }
  • 片元着色器 顶点着色器中的数据经过图元装配光栅化之后,来到了片元着色器,在本例中,片元着色器的任务是通知 GPU 将光栅化后的像素渲染成红色,所以片元着色器要对内置变量 gl_FragColor (代表像素要填充的颜色)进行赋值。
    1. void main(){
    2. //设置像素的填充颜色为红色。
    3. gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    4. }

这样,就写好了着色器的代码。
这些代码后续会进行解释,我们先来实现效果

2.绘制一个点

  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport"
  6. content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  8. <title>Document</title>
  9. </head>
  10. <body onload="main()">
  11. <canvas id="canvas" height="400" width="400">
  12. 你的浏览器不支持WebGL,请更换新的浏览器
  13. </canvas>
  14. </body>
  15. <script src="../lib/webgl-util.js" ></script>
  16. <script src="../lib/webgl-debug.js" ></script>
  17. <script src="../lib/cuon-utils.js" ></script>
  18. <script>
  19. //顶点着色器程序
  20. var VSHADER_SOURCE="" +
  21. "void main(){\n" +
  22. " gl_Position = vec4(0.0,0.0,0.0,1.0);\n" +//设置坐标
  23. " gl_PointSize = 10.0;\n" +//设置尺寸
  24. "}\n";
  25. //片元着色器程序
  26. var FSHADER_SOURCE = "" +
  27. "void main(){\n" +
  28. " gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n" +//设置颜色
  29. "}\n";
  30. function main() {
  31. //首先获取到canvas的dom对象
  32. var canvas = document.getElementById("canvas");
  33. //获取到WebGL的上下文
  34. var gl = getWebGLContext(canvas);
  35. //不支持WebGL的浏览器将打印一个错误,并结束代码运行
  36. if (!gl) {
  37. console.log("浏览器不支持WebGL");
  38. return;
  39. }
  40. //初始化着色器
  41. if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
  42. console.log("初始化着色器失败");
  43. return;
  44. }
  45. //指定一个覆盖(清空)canvas的颜色
  46. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  47. //执行清空
  48. gl.clear(gl.COLOR_BUFFER_BIT);
  49. //绘制一个点
  50. gl.drawArrays(gl.POINTS,0,1);
  51. }
  52. </script>
  53. </html>

image.png

看到这里是不是有点懵,为什么这么写,上面那些代码又是做什么的,下一章来仔细解释。