如何绘制一个点?
上次讲到了如何清空绘图区,这次来讲解如何绘制一个点。我们将在位于远点(0.0, 0.0, 0.0)处绘制一个十个像素大的红色的点。因为WebGL绘制的是三维图行,所以我们需要指定这个点的三维坐标。
在canvas中,我们绘制一个矩形并填充颜色
ctx.fillStyle = 'rgba(0,0,255, 1.0)';ctx.fillRect(120, 10, 150, 150);
你可能认为WebGL也差不多。 不幸的是,事情并没有这么简单。 WebGL依赖于一种新的称为着色器的绘图机制。
着色器提供了灵活且强大的绘图二维或三维图形的方法。 所有的WebGL程序必须使用它。着色器不仅强大,而且复杂。仅仅通过一条简单的指令是无法实现的。
什么是着色器?
GLSL 的中文意思是 OpenGL 着色语言,英文全称是 OpenGL Shading Language,它是用来在 OpenGL 编写着色器程序的语言。
我们知道了 GLSL 是用来编写着色器程序的语言,那么新的问题来了,着色器程序是用来做什么的呢? 简单地说,着色器程序是在显卡(GPU)上运行的简短程序,代替了 GPU 固定渲染管线的一部分,使 GPU 渲染过程中的某些部分允许开发者通过编程进行控制。
用一句话来说:着色器程序允许我们通过编程来控制 GPU 的渲染。
那么 GPU 渲染过程中的哪些部分允许开发者控制呢?下图是对 WebGL 渲染管线的简单演示:

上图简单演示了 WebGL 对一个红色三角形的渲染过程,绿色部分为开发者可以通过编程控制的部分:
- JavaScript 程序
- 处理着色器需要的
顶点坐标、法向量、颜色、纹理等信息,并负责为着色器提供这些数据,上图为了演示方便,只是提供了三角形顶点的位置数据。 - 顶点着色器
- 接收 JavaScript 传递过来的
顶点信息,将顶点绘制到对应坐标。 - 图元装配阶段
- 将三个顶点装配成指定
图元类型,上图采用的是三角形图元。 - 光栅化阶段 将三角形内部区域用空像素进行填充。
- 片元着色器 为三角形内部的像素填充颜色信息,上图为暗红色。
实际上,对顶点信息的变换操作既可以在 JavaScript 中进行,也可以在着色器程序中进行。通常我们都是在 JavaScript 中生成一个包含了所有变换的最终变换矩阵,然后将该矩阵传递给着色器,利用 GPU 并行计算优势对所有顶点执行变换。
开始绘制一个点
1. 准备着色器代码
我们从着色器程序开始入手,先用GLSL编写顶点着色器和片元着色器。
- 顶点着色器
顶点着色器的主要任务是告诉 GPU 在裁剪坐标系的原点(也就是屏幕中心)画一个大小为 10 的点。
void main(){//声明顶点位置gl_Position = vec4(0.0, 0.0, 0.0, 1.0);//声明待绘制的点的大小。gl_PointSize = 10.0;}
- 片元着色器
顶点着色器中的数据经过
图元装配和光栅化之后,来到了片元着色器,在本例中,片元着色器的任务是通知 GPU 将光栅化后的像素渲染成红色,所以片元着色器要对内置变量gl_FragColor(代表像素要填充的颜色)进行赋值。void main(){//设置像素的填充颜色为红色。gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}
这样,就写好了着色器的代码。
这些代码后续会进行解释,我们先来实现效果
2.绘制一个点
<!doctype html><html><head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title></head><body onload="main()"><canvas id="canvas" height="400" width="400">你的浏览器不支持WebGL,请更换新的浏览器</canvas></body><script src="../lib/webgl-util.js" ></script><script src="../lib/webgl-debug.js" ></script><script src="../lib/cuon-utils.js" ></script><script>//顶点着色器程序var VSHADER_SOURCE="" +"void main(){\n" +" gl_Position = vec4(0.0,0.0,0.0,1.0);\n" +//设置坐标" gl_PointSize = 10.0;\n" +//设置尺寸"}\n";//片元着色器程序var FSHADER_SOURCE = "" +"void main(){\n" +" gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n" +//设置颜色"}\n";function main() {//首先获取到canvas的dom对象var canvas = document.getElementById("canvas");//获取到WebGL的上下文var gl = getWebGLContext(canvas);//不支持WebGL的浏览器将打印一个错误,并结束代码运行if (!gl) {console.log("浏览器不支持WebGL");return;}//初始化着色器if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){console.log("初始化着色器失败");return;}//指定一个覆盖(清空)canvas的颜色gl.clearColor(0.0, 0.0, 0.0, 1.0);//执行清空gl.clear(gl.COLOR_BUFFER_BIT);//绘制一个点gl.drawArrays(gl.POINTS,0,1);}</script></html>

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