一起学 WebGL:绘制一个点

大家好,我是前端西瓜哥。

本文讲解如何用 WebGL 绘制一个点。

WebGL

WebGL 是浏览器支持的一种绘制图形的 API,是一个标准。我们可以通过 Canvas 元素 在网页的特定区域绘制 2D 和 3D 图形。

相比 Canvas 2D,WebGL 利用了 GPU 的计算能力,绘制速度更快,性能更优。

WebGL 基于 OpenGL 发展而来,某种意义上就是 Web 版的 OpenGL,但是阉割了一些功能。

更具体点,是来自 OpenGL 的一个特殊版本 OpenGL ES 2.0,全称为 OpenGL for Embedded Systems,“用于嵌入式系统的 OpenGL”。

使用 WebGL,除了浏览器正统脚本语言 JavaScript,还要使用一种 名为 GLSL ES 的类 C  着色器语言

绘制过程和着色器

将代码描述的效果真正绘制到屏幕上的过程,称为 渲染管线

管线(pipeling)这个词有点奇怪,因为它没有对应的比较好的翻译,是一个直译。

管线指的是 数据处理的流水线,这个流水线上有很多处理器,会将数据一步步地进行处理,最终得到一个成品。渲染管线,就是渲染过程中执行的一个个步骤。

渲染管线的流程为:

扫描二维码关注公众号,回复: 14697015 查看本文章
  1. 顶点处理阶段。接收顶点信息,比如我要画一个三角形,三个点的位置在哪里,尺寸、颜色分别是多少。

  2. 图形装配。多个点组合成怎样的图形。我们会用 API 进行指定,比如点、线段、三角形。

  3. 光栅化。将顶点转换为需要绘制的像素信息,比如位置、深度。

  4. 片元处理阶段。设置像素的颜色信息。

这四个流程中,我们能操作的是第 1 和第 4 步。

绘制一个点

Demo 地址:

codesandbox.io/s/webgl-hui…

下面我们来讲解如何绘制一个点。

首先是 WebGL 绘制的地方 Canvas。我们需要在 HTML 中添加一个 Canvas 元素,然后在 JavaScript 中获取这个元素,并拿到 WebGL 渲染上下文

const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");

复制代码

如果你用过 Canvas 2D,它对应的上下文变量命名通常是 ctx(context)。但对于 WebGL,我们通常会跟随 OpenGL 的习惯,将变量命名为 gl(OpenGL 的 gl,Graphics Library 的意思)。

接着是顶点着色器。

顶点着色器,用于设置图形的顶点相关的信息,设置好顶点,WebGL 才能确定好图形的位置等信息,好绘制出来。

着色器的代码是在 JavaScript 脚本中,用字符串来写 glsl。

顶点着色器

先是顶点着色器

const vertexShaderSrc = `
void main() {
 gl_Position = vec4(0.00.00.01.0);
 gl_PointSize = 20.0;
}
`;

复制代码

gl_Postion 和 gl_PointSize 是 WebGL 顶点着色器的内部变量,用于设置点的位置和点的大小。

vec4 表示矢量类型,同时也是内置函数,调用它就能得到一个 vec4 类型。

这里设置了顶点的位置 (0.0, 0.0, 0.0, 1.0)。WebGL 使用的是三维坐标系,并使用右手坐标系,就是 x 轴指向右侧,y 轴指向上方,z 轴指向观察者。原点就在画布的正中央。

关于坐标系,可以看我的这篇文章:

一起学 WebGL:坐标系

三维中,一个点只要三个维度 x、y、z 就够了,但引入了第四个维度 w,从笛卡尔坐标升维为齐次坐标,作用是方便做矩阵变换和透视投影。齐次坐标 (x, y, z, w) 等价于三维坐标 (x/w, y/w, z/w)。w 通常会设置为 1。

需要注意的是,着色器中的的数值需要加上小数点,表示用的是浮点数类型。这和 JavaScript 随便写都会变成浮点数不一样。

片元着色器

然后是片元着色器

顶点着色器确定图形的点的位置,片元着色器则是用于设置多个顶点围成的图形的像素点的 颜色

const fragmentShaderSrc = `
void main() {
  gl_FragColor = vec4(1.00.00.01.0);
}
`;

复制代码

gl_FragColor 是片元着色器的内部变量,这里设置为红色。

创建渲染器

因为是入门文章,细节不展开讲了。

总之下面这段代码,将前面声明的顶点着色器和片元着色器的两段源码,进行了编译。

/**** 渲染器生成处理 ****/
// 创建顶点渲染器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);

// 创建片元渲染器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSrc);
gl.compileShader(fragmentShader);

// 程序对象
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
gl.program = program;

复制代码

清空缓存

gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);

复制代码

首先第一行代码将背景色设置为黑色。当然你也可以设置为其他颜色,比如绿色 (0, 1, 0, 1)

第二行是清空缓存区,填充背景色。

绘制点

gl.drawArrays(gl.POINTS, 0, 1);

复制代码

该 API 用于调用绘制指令,有三个参数:

  1. mode。绘制怎样的图元。比如点(gl.POINTS)、各种类型的线段、各种类型的三角形。也就这三种图元。再复杂的图形也是由一个个三角形组成的。这里用到的微积分的思想,将三维物体不断的细分,其实就是一个个非常小的平面组成的,三个点确定一个平面,也就是三角形。正方形也是两个三角形组成。

  2. first。从哪个顶点开始绘制,通常是 0。本文只是画一个点,这个参数没太大意义,存在多个顶点时才有用,虽然也少用。

  3. count。使用到几个顶点。

绘制结果如下:

图片

结尾

下一篇画个三角形。

我是前端西瓜哥,欢迎关注我,学习更多前端图形知识。

猜你喜欢

转载自juejin.im/post/7219478427300003898