上车WebGL——绘制基础图形

385 阅读6分钟

哈喽大家好啊,我是广州小井。好久没在掘金更文了,最近跑去学习 WebGL 了,然后打算把学习路径写成系列文章来分享给大家。

因为要更好的学习 WebGL 就需要更多的上手敲代码,所以案例和演示代码就很显得重要了。为此,笔者打算将案例、源码都统一放到 github 仓库,并且搞了个在线文档供大家学习参考~大家可以给笔者点个 star!文章更新不迷路!

img.png

本文的同步地址:

经过上个小节的学习,我们已经掌握了 WebGL 中如何绘制线和三角,学习了缓冲区对象,那这一节,我们继续深入 WebGL 的绘制能力,掌握如何用 WebGL 绘制出更多的基础图形。

上一节有提到,所有的 3D 图形的基础都是三角形,但是抛开实现复杂的 3D 图形,我们需要知道如何利用 gl.drawArrays 的不同 mode 和不同顶点的组合来绘制一些基本图形,这将会是本文的重点内容。

绘制LINE的组合图形

说到 LINE 其实我们并不陌生,因为上一小节我们通过 gl.LINE_STRIP 绘制了一个小锐角。

那本节,将在之前的基础上,使用不同的绘制 mode 来看看都能实现怎么样的图形效果。

为了更加体现出每个 mode 的区别,本文的示例程序采用 6 个顶点来绘制,但是基本代码跟上一小节是一致的,也是会使用到缓冲区,所以对于具体的代码实现本文不会再赘述了,我们更多要关注是每个 mode 的绘制效果即可~

还是跟之前一样,我们先通过一幅图来看看本文所用到的顶点和坐标:

6.1.png

本文的示例程序都会以上述的顶点坐标来实现各种基本图形的绘制。

// 本节的顶点坐标
const vertices = new Float32Array([
  -.5, .5, -.5, -.5,
  0., .5, 0., -.5,
  .5, .5, .5, -.5
])

关于 LINES 的相关 mode,我们先大概了解一下他们的定义:

  1. gl.LINES 绘制单独的线段
  2. gl.LINE_STRIP 绘制连接的线段
  3. gl.LINE_LOOP 绘制连接的线段,最后一个点会和第一个点连接

光说不够直观,我们直接通过示例程序亲自来感受一下他们之间的区别:

根据示例程序,我们可以发现不同的 mode 会绘制出不同的线段效果,那以后我们可以灵活的通过组合使用不同的 mode 来实现各种线段图形了。不过在这里需要提醒一下大家,我们的顶点顺序有可能会影响最终的绘制结果,具体表现在点与点之间的连接顺序不同导致出现不同的图形结果。

比如我修改一下缓冲区数据中点的顺序,将每一对点的前后顺序改变一下:

const vertices = new Float32Array([
  -.5, -.5, -.5, .5, // 每两个为一组,改变前后两组的顺序
  0., -.5, 0., .5,  // 每两个为一组,改变前后两组的顺序
  .5, -.5, .5, .5 // 每两个为一组,改变前后两组的顺序
])

还是之前的示例,感兴趣的同学可以把上述的坐标点替换掉示例中的坐标点自己运行体验一下(当然也可以打开在线电子书看看点顺序不同的绘制区别):

最后其实你可以发现 LINE_STRIPLINE_LOOP 绘制出的线段图形跟上一个的示例程序呈镜面对称关系

绘制TRIANGLE的组合图形

学完了线段的基本图形绘制,我们到"面"的基本图形绘制了。与其说是面,不如说是通过三角形组合起来的基本二维图形而已。

我们这一节接着沿用本文的最开始的顶点坐标:

const vertices = new Float32Array([
  -.5, .5, -.5, -.5,
  0., .5, 0., -.5,
  .5, .5, .5, -.5
])

好吧,没什么好说的,我们还是一样先了解一下每个 mode 的基本概念:

  1. gl.TRIANGLES 绘制多个单独的三角形
  2. gl.TRIANGLE_STRIP 绘制组合的三角形,从第二个点开始,每三个点构成一个三角形。比如下文逆时针绘制的图片 v1(就是第二个点) 跟 v2v3 就组成一个新的三角形。
  3. gl.TRIANGLE_FAN 绘制组合的三角形(扇形),全部三角共用同一个点,每下一个点前一个三角形的最后一条边组成新的三角形

注意一点,三角形的绘制是按照 逆时针 的顺序绘制,比如我们看下图:

6.2.png

该图按照本示例的坐标,展示了 gl.TRIANGLE_STRIP 时前四个顶点之间的绘制关系,可以发现第一个三角形是 (v0, v1, v2) 的顺序绘制的(逆时针),而第二个三角形则是 (v2, v1, v3) 也是一个逆时针顺序

光说肯定不直观,我们接着上示例程序给大家体验一下,加深理解(为了让大家看出区别,我这里通过不同的颜色去绘制了三个三角形。如果大家看示例代码的话,不用深究缓冲区的顶点坐标数据,这个涉及到步进参数的知识,暂时还没讲到那一块):

从示例程序的 TRIANGLE_STRIP 中,我们"不明不白"地就画了个长方形,由于当前的坐标点不太能体现 TRIANGLE_FAN 的能力,所以我们换一组坐标来看看 TRIANGLE_FAN 怎么来发挥它的优势绘制一些基础图形。

我把顶点坐标改成如下图所示的位置(根据v0-v5的顺序写入缓冲区):

6.3.png

对应的缓冲区坐标点数据如下:

const vertices = new Float32Array([
  0., 0., -.5, .3, // v0, v1
  -.3, .6, 0., .8, // v2, v3
  .3, .6, .5, .3 // v4, v5
])

整理好坐标后,我们通过 gl.TRIANGLE_FAN 再次进行绘制,绘制结果图下:

可以看到示例程序中画出了一个类似扇形的蓝色图形!这下,你应该对 TRIANGLE_FAN 这个绘制 mode 有所体验了把。

总结

本文的最后,跟大家一起回顾本文的主要内容:

  1. 了解不同 modeLINE 组合绘制出不同的线段图形,并且我们要注意顶点顺序不同带来的绘制结果不同的可能
  2. 了解不同 modeTRIANGLE 组合绘制出不同的图形,有长方形、扇形,当然我们也需要注意点顺序的

最后,因为本文涉及的绘制内容比较多,我建议大家都自己敲一下代码实现一下效果,这样可以加深你对不同 mode 参数的理解。