WebGL入门教程四:借助
作者:心叶
时间:2019-09-12 14:51
通过前面三篇文档的说明,大家应该基本了解了webgl的绘制方法,为了下一步更深入的学习,我们先来学习一下一个辅助库image3D,这个库主要是提供一些辅助方法。
引入image3D
通过npm方式管理,首先你需要通过命令行安装image3D,就像这样:
npm install --save image3d
安装好了以后,在需要的地方引入即可:
import $$ from 'image3d';
或
const $$ = require("image3d");
着色器
现在,我们再次绘制一个点,完整的代码点击这里。
顶点着色器
<script type='x-shader/x-vertex' id='vs'> void main(){ gl_Position=vec4(0.0,0.0,0.0,1.0); gl_PointSize=100.0; } </script>
gl_Position和gl_PointSize都是着色器固定的内置变量,分别表示点的位置和大小。
片段着色器
<script type='x-shader/x-fragment' id='fs'> void main(){ gl_FragColor=vec4(1.0,0.0,0.0,1.0); } </script>
gl_FragColor是片段着色器的内置变量,表示点的颜色。
绘图代码
我们都知道,着色器就是二段字符串(如果一些细节忘了,可以回去看看前三篇基本概念),下面的代码才是JS,上面只是写好的字符串,提供给我们用。
这里,我们不再使用原生的方法编写了(重要部分还是原生的,为了方便大家理解原理),如何引入image3D大家可以查看README.md,我们这里就直接使用了($$表示image3D)。
<canvas width=500 height=500>非常抱歉,您的浏览器不支持canvas!</canvas>
假设页面中有一个canvas,使用image3D的第一步是获取3D启动对象:
var render3D = $$(document.getElementsByTagName('canvas')[0]).render3D();
好了,余下的就很容易了。回忆一下,绘图的第一步是什么?是的,让着色器生效:
// 启用着色器 render3D.shader( document.getElementById('vs').innerHTML, document.getElementById('fs').innerHTML );
render3D提供了一个方法shader,你只要把二段着色器字符串传递给它,它就会帮你让着色器生效。
着色器生效以后,GPU其实就有了这些数据,接下来只需要告诉GPU帮我绘制就好了:
// 获取画笔 var gl = render3D.painter(); // 绘制一个点 gl.drawArrays(gl.POINTS, 0, 1);
注意,上面的gl提供的是原生的方法,比如这里的drawArrays绘制了一个点。
好了,一个点就绘制完成了。怎么样,是不是更加简单了。接下来我们就希望通过这个库,给大家讲解webgl3D绘图的一些基础知识,可能涉及:3D模型数据的加载和解析、层次模型、光照、透视和纹理等。
缓冲区
主要说明第一个缓冲区的使用,例子完整代码在这里,第二类缓冲区稍微麻烦一点,我们后面再说明。
我们的需求是,绘制三个三角形,三角形每个顶点的颜色都不一样。我们知道,这里一共有9个顶点,9中颜色(和顶点对应),无法直接写死在着色器中,怎么办,很简单,写入缓冲区,然后把缓冲区分配给着色器中的变量。
还是先看看着色器的代码。
顶点着色器
<script type='x-shader/x-vertex' id='vs'> attribute vec4 a_position; attribute vec4 a_color; varying vec4 v_color; void main(){ gl_Position=a_position; v_color=a_color; } </script>
我们定义了一个变量a_position和a_color,这就是过会要和缓冲区绑定的点的坐标和颜色的变量,没问题,那v_color是干什么的,接着看片段着色器。
片段着色器
<script type='x-shader/x-fragment' id='fs'> precision mediump float; varying vec4 v_color; void main(){ gl_FragColor=v_color; } </script>
我们发现,片段着色器中也定义了v_color,是的,片段着色器中没办法一下子传递很多数据,都是绘制点的时候,来自顶点着色器(为了大家理解这样描述,不是很准确,想具体了解的,可以查看这里或点击issue提问)
传递数据
和上面例子差不多的就不解释了,大家可以看完整代码。
着色器写好以后,我们要让它生效,生效以后,是不是就调用绘图方法绘图就可以了?
不是的,前一个例子我们把数据写死在着色器中了,这个例子我们是定义一个变量接收数据,因此,我们在绘图前,需要传递数据给着色器。
怎么传递?使用缓冲区呀:
// 初始化缓冲区 var buffer = render3D.buffer() // 数据写入缓冲区 .write(data) // 写入缓冲区的数据分配 .use('a_position', 3, 6, 0) .use('a_color', 3, 6, 3);
render3D.buffer方法返回缓冲区对象,使用write写入数据,然后使用use分配数据给前面定义的变量即可(data是数据,完整代码中有,这里不贴出来了)。
绘图
好了数据有了以后,就简单了:
// 绘制三个三角形 gl.drawArrays(gl.TRIANGLES, 0, 9);
看看运行截图:
后记
你可以试着修改第二个例子中点的坐标试试。这篇文章主要是要入门借助image3D绘图的流程,是不是很容易。例子中涉及的方法和一些细节我们后面再说明。有任何疑惑可以留言提问。