作者:心叶
时间:2019-09-12 14:51
通过前面三篇文档的说明,大家应该基本了解了webgl的绘制方法,为了下一步更深入的学习,我们先来学习一下一个辅助库image3D,这个库主要是提供一些辅助方法。
引入image3D
通过npm方式管理,首先你需要通过命令行安装image3D,就像这样:
npm install --save image3d
安装好了以后,在需要的地方引入即可:
import image3D from 'image3d';
或
const image3D = require("image3d");
首先,我们不得不说明一下绘图的基本流程:编辑着色器→创建3D对象→准备好数据→绘制
我们接下来准备绘制一个点,点的颜色、大小和位置不停改变。
着色器
绘图的时候,本质上我们都是需要通过着色器来和GPU进行数据交互,因此,需要传递的数据都需要在这里提前定义好,看看本例子的着色器:
attribute vec4 a_position;
attribute float a_size;
attribute vec4 a_color;
varying vec4 v_color;
void main(){
gl_Position=a_position;
gl_PointSize=a_size;
v_color=a_color;
}
varying vec4 v_color;
void main(){
gl_FragColor=v_color;
}
着色器分二类:顶点着色器和片段着色器,前者用于传递点的位置和大小,后者用于传递点的颜色。
本质上来讲,着色器其实就是二个字符串,用script标签包裹是为了在html文本中方便编辑,在后面的过程就可以看出来了。
着色器的代码有点像C语言,我们目前需要了解这三点:
gl开头的有三个,分别对应点的位置、大小和颜色(从上到下),这是着色器内置的变量,分别隶属于二个着色器,我们所谓的传值,从这个层次看,就是最终给这三个变量赋值。
然后再看看attribute修饰的三个变量,被这个修饰符修饰的变量等于暴露了一个入口,image3D提供了传值的方法,所谓的传值,也就是通过这个入口实现的(第二个修饰符,vec4和float是变量的数据类型,类似别的语言)。
前一条说的入口由attribute修饰实现,是针对每个点提供的,片段着色器是针对全部的点,因此attribute不可以直接出现在第二类着色器中,我们需要使用varying修饰符来标记一个桥梁,实现二个着色器之间的数据传递。
3D对象
着色器准备好了以后,我们就可以使用这二个着色器创建3D对象了,同样的,看看本例中的代码:
var image3d = new image3D(
document.getElementsByTagName('canvas')[0], {
// 传递着色器
"vertex-shader":
document.getElementById("vs").innerText,
"fragment-shader":
document.getElementById("fs").innerText
});
从这里是不是可以看出来,着色器只不过是二段字符串。
传递数据
实际的例子是不停的改变,我们为了方便说明,这里假设某个瞬间的操作:
image3d
// 设置点的位置
.setAttributeFloat("a_position", 0.5, 0.5, 0.0)
// 设置点的大小
.setAttributeFloat("a_size", 50.0)
// 设置点的颜色
.setAttributeFloat("a_color", 1.0, 0.0, 0.0);
比如点的位置,“a_position”是和着色器中attribute修饰的变量对应的。大部分根据感觉应该就可以看出来,下面稍微提二点:
image3D选择的是右手坐标系,记作uvz(对应数学中的坐标系就是xyz),每个轴的有效可视范围是-1.0~1.0,因此这里的坐标(0.5, 0.5, 0.0)页面上看上去就是位于第一象限中心(右上角),请注意和浏览器的坐标区分。
点的颜色需要传递三个值,范围是0.0~1.0,分别对应RGB(当然还可以有一个alpha透明度,这里没有传递)。
绘制
一切准备完毕,获取画笔绘制即可:
image3d.Painter().drawPoint(0, 1);
这里缩减版的例子最终会绘制一个大小是50px,位于第一象限中心的红色正方形。完整的例子请点击此处查看运行效果。
后记
你可以试着修改第二个例子中点的坐标试试。这篇文章主要是要入门借助image3D绘图的流程,是不是很容易。例子中涉及的方法和一些细节我们后面再说明。有任何疑惑可以留言提问。