作者:心叶
时间:2018-05-11 10:30
写在前面
阅读这篇文章的人应该都知道Canvas绘制二维位图是通过getContext('2d')获取类似画笔的东西在其中绘制,而这里是绘制三维位图,通过getContext('webgl')来获取这只神奇的笔。
由于本系列更多的是以个人以后复习或查阅为主要目的,因此阅读起来如果有没有说清楚的地方,请留言。
下面,我们开始吧!
绘图过程
canvas 2D绘制过程
页面添加canvas元素 -> 获取2D画笔 -> 设置好画笔等 -> 清空屏幕(如果需要) -> 绘制(相应API)
canvas WebGL绘制过程
页面添加canvas元素 -> 获取3D画笔 -> 设置好着色器等 -> 清空屏幕(如果需要) -> 绘制(相应API)
可以看出来,主要是【设置好着色器等】这一步和之前的绘制方法不一样,因此,我们先来说明一下,什么是着色器?
着色器
绘制三维图形的时候(以绘制一个点为例),你需要告诉他点的位置、尺寸和颜色,当你设置好这些以后就类似2D设置好画笔了,就可以绘制了,而这三个的设置就是设置着色器的过程。
着色器种类
着色器分为二类:顶点着色器和片段着色器,前者控制位置和尺寸,后者控制颜色。
着色器目前本篇就说这些,由于还没有实践的东西,说太多理解起来有点累。
绘制一个简单的点
下面,我们通过绘制一个简单的点为例来按照上面的过程来绘制,感受一下。
页面添加canvas元素
首先在页面中添加canvas标签:
<canvas id='webgl' width='400' height='400'></canvas>
获取3D画笔
获取3D画笔也2D的一样,只不过参数有点改变:
var canvas = document.getElementById('webgl');
var gl = canvas.getContext('webgl');
设置好着色器等
着色器的设置会有点麻烦,其实着色器就是二段字符串,先定义好,然后使其生效。
下面是大致过程:
定义着色器字符串 -> 创建着色器对象并绑定好对应的着色器字符串 -> 创建着色器程序并添加前面创建的着色器对象 -> 把着色器程序链接成一个完整的程序并使用他
说明:上面的过程看起来有点昏,是因为3D的绘制比较复杂,有很多新概念的东西,需要慢慢去适应。
下面看看具体代码:
【定义着色器字符串】
顶点着色器有二个固定的属性gl_Position和gl_PointSize,分别表示位置和尺寸:
<!-- 顶点着色器 -->
<script type='x-shader/x-vertex' id='vs-shader'>
void main(){
gl_Position=vec4(0.0,0.0,0.0,1.0);
gl_PointSize=100.0;
}
</script>
片段着色器有一个固定的属性gl_FragColor表示颜色:
<!-- 片段着色器 -->
<script type='x-shader/x-fragment' id='fs-shader'>
void main(){
gl_FragColor=vec4(1.0,1.0,0.0,1.0);
}
</script>
这样,二段字符串就准备好了,也就是二个着色器字符串好了(为了方便定义在标签中,后续可以看见,他们就是二个字符串)。
【创建着色器对象并绑定好对应的着色器字符串】
具体在代码中备注,看代码:
//初始化着色器(上面第一步的其实就是这样在用,这里直接写字符串也可以,只不过上面的写法更方便编辑)
var vs_source = document.getElementById('vs-shader').innerHTML,
fs_source = document.getElementById('fs-shader').innerHTML;
// 创建顶点着色器对象
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
// 绑定资源
gl.shaderSource(vertexShader, vs_source);
// 编译着色器
gl.compileShader(vertexShader);
// 创建片段着色器对象
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
// 绑定资源
gl.shaderSource(fragmentShader, fs_source);
// 编译着色器
gl.compileShader(fragmentShader);
【创建着色器程序并添加前面创建的着色器对象】
到这里,二个着色器就准备好了,可是需要程序使用,还需要变成着色器程序,看代码:
// 创建一个着色器程序
var glProgram = gl.createProgram();
// 把前面创建的二个着色器对象添加到着色器程序中
gl.attachShader(glProgram, vertexShader);
gl.attachShader(glProgram, fragmentShader);
【把着色器程序链接成一个完整的程序并使用他】
此时,着色器程序也好了,我们需要指定使用他:
// 把着色器程序链接成一个完整的程序
gl.linkProgram(glProgram);
// 使用这个完整的程序
gl.useProgram(glProgram);
这样,着色器就设置好了,当然,这是最简单的着色器,具体还有很多操作,后续会说明,先理解这些基本的吧。
清空屏幕(如果需要)
// 设置清空颜色
gl.clearColor(0.5, 0.5, 0.5, 1.0);
// 用设置的颜色清空屏幕(参数代表的是清除颜色缓冲)
gl.clear(gl.COLOR_BUFFER_BIT);
绘制(相应API)
最后一步绘制点:
gl.drawArrays(gl.POINTS, 0, 1);
drawArrays就类似2D中的绘图方法,第一个参数代表绘制一个点,第二个参数代表从第一个点开始,第三个参数代码绘制个数一个。
你可能好奇他从哪里知道点的位置的?是的,你开始不是定义了顶点着色器吗?就是他。
完整代码
由于是第一个例子,给出上面的完整例子代码:
<!DOCTYPE html>
<html>
<head>
<!-- 顶点着色器 -->
<script type='x-shader/x-vertex' id='shader-vs'>
void main(){
gl_Position=vec4(0.0,0.0,0.0,1.0);
gl_PointSize=100.0;
}
</script>
<!-- 片段着色器 -->
<script type='x-shader/x-fragment' id='shader-fs'>
void main(){
gl_FragColor=vec4(1.0,1.0,0.0,1.0);
}
</script>
</head>
<body>
<canvas id='webgl' width='400' height='400'></canvas>
</body>
<script>
// 1.获取webgl
var canvas = document.getElementById('webgl');
var gl = canvas.getContext('webgl');
// 2.清空屏幕
gl.clearColor(0.5, 0.5, 0.5, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// 3.初始化着色器
var vs_source = document.getElementById('shader-vs').innerHTML,
fs_source = document.getElementById('shader-fs').innerHTML;
// 创建顶点着色器对象
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
// 绑定资源
gl.shaderSource(vertexShader, vs_source);
// 编译着色器
gl.compileShader(vertexShader);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs_source);
gl.compileShader(fragmentShader);
// 创建一个着色器程序
var glProgram = gl.createProgram();
// 把前面创建的二个着色器对象添加到着色器程序中
gl.attachShader(glProgram, vertexShader);
gl.attachShader(glProgram, fragmentShader);
// 把着色器程序链接成一个完整的程序
gl.linkProgram(glProgram);
// 使用这个完整的程序
gl.useProgram(glProgram);
// 4.绘制一个点
gl.drawArrays(gl.POINTS, 0, 1);
</script>
</html>
总结
一个简单的例子开始的入门就结束了,一定会有很多没有没有说清楚的,可以在下面留言,经过这个,你需要大概知道webgl的整体思想,绘图过程,最好可以感受这里例子的代码就可以了。