WebGL入门
webGL,是一项用来在网页上绘制和渲染复杂三维图形(3D图形),并允许用户与之进行交互的技术。webGL接合了HTML5和JavaScript,允许开发者在网页上创建和渲染3D图形。
下面是一些精彩的webGL示例
Aquarium
Cube
WebGL Bookcase
WebGL Earth
接下来先简单介绍一下使用到的知识要点
一、使用 < canvas > 标签
canvas即是画布,< canvas >标签定义了网页上的绘图区域
示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Draw a blue rectangle</title>
</head>
//<body>元素加载完成后执行main()函数作为JavaScript程序的入口
<body onload="main()">
<canvas id="example" width="400" height="400">
//错误信息,提醒那些用着老式浏览器的用户
please use a browser tht supports "canvas"
</canvas>
<script src="DrawRectangle.js"></script>
</body>
</html>
二、绘制图像步骤
1.获取 < canvas >元素
var canvas = docuement.getElementById(“id”)
2.向该元素请求图像的“绘图上下文”
//获取绘制二维图形的绘图上下文
var ctx = canvas.getContext(‘2d’);
//获取绘制三维图形的绘图上下文
var ctx = canvas.getContext(“webgl”) || canvas.getContext(“experimental-webgl”)
3.在绘图上下文上调用相应的绘图函数,以绘制二维图形
示例代码
//DrawRectangle.js
fucntion main(){
//获取<canvas>元素
var canvas=document.getElementById('example');
if(!canvas){
console.log('Failed to retrieve the <canvas> element');
return;
}
//获取绘图上下文
var ctx=canvas.getContext('2d');
//绘制蓝色矩形
ctx.filStyle="rgba(0,0,255,1.0)"//设置填充颜色为蓝色
ctx.fillRect(120,10,150,150);//使用填充颜色填充矩形
}
三、着色器
上面的二维图形绘制,是先指定一个绘图颜色,然后绘制一个矩形
ctx.filStyle=“rgba(0,0,255,1.0)”//设置填充颜色为蓝色
ctx.fillRect(120,10,150,150);//使用填充颜色填充矩形
三维图形的颜色绘制就比二维图形的复杂多了,WebGL依赖于一种新的称为着色器的绘图机制。在三维场景中,仅仅用线条和颜色把图形画出来是远远不够的。你必须考虑,比如,光线照上去之后,或者观察者的视角发生变化吗,对场景会有什么影响。着色器可以高度灵活地完成这些工作,提供各种渲染。
以下先看一段完整代码对着色器有一个大致的认识,我们再慢慢解释
//HelloPoint1.js
//顶点着色器程序
var VSHADER_SOURCE=
'void main(){\n'+
'gl_Position=vec4(0.5,0.0,0.0,1.0);\n'+
'gl_PointSize=10.0;\n'+
'}\n';
//片元着色器程序
var FSHADER_SOURCE=
'void main(){\n'+
'gl_FragColor=vec4(1.0,1.0,0.0,1.0);\n'+
'}\n';
function main(){
//获取<canvas>元素
var canvas=document.getElementById('webgl');
//获取绘制三维图形的绘图上下文
var gl=canvas. canvas.getContext("webgl");
if(!gl){
console.log('Failed to get the rendering context for WebGL');
return;
}
if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
console.log('Failed to initilize shaders.');
return;
}
//设置<canvas>的背景色
gl.clearColor(0.0,0.0,0.0,1.0);
//用背景色填充<canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制一个点
gl.drawArrays(gl.POINTS,0,1);
}
initShaders()是开源代码库中的一个函数,作用是对字符串形式的着色器进行了初始化,具体函数如下:
function initShaders(gl, vshader, fshader) {
var program = createProgram(gl, vshader, fshader);
if (!program) {
console.log('Failed to create program');
return false;
}
gl.useProgram(program);
gl.program = program;
return true;
}
顶点着色器(Vertex shader)
顶点着色器是用来描述顶点特性(如位置、颜色等)的程序。顶点是指二维或三维空间中的一个点,比如二维或三维图形的端点或交点。顶点着色器置顶了点的位置和尺寸
var VSHADER_SOURCE=
'void main(){\n'+
'gl_Position=vec4(0.5,0.0,0.0,1.0);\n'+
'gl_PointSize=10.0;\n'+
'}\n';
上面这段程序表示绘制一个点,这个点的位置是(0.5,0.0,0.0),点的尺寸是10.0
gl_Position:表示顶点位置
vec4:表示由四个浮点数组成的数据类型
float | float | float | float |
---|
三维坐标不是只有x,y,z吗,为什么需要四个浮点数来表示顶点位置呢?
这是因为这里运用了齐次坐标。
齐次坐标就是用N+1维来代表N维坐标,使用如下符号描述:(x,y,z,w)
齐次坐标(x,y,z,w)等价于三维坐标(x/w,y/w,z/w)
将最后一个分量赋值为1.0就可以表示三维坐标了
为什么要用齐次坐标呢?
这是因为齐次坐标的存在使得用矩阵来描述顶点变换成为可能,后面再深入探讨。
gl_Position:表示点的尺寸(像素数)
顺便说说WebGL的坐标系统叭
WebGL的坐标系和< canvas >坐标的对应关系如下
- < canvas>的中心点:(0.0,0.0,0.0)
- < canvas>的上边缘和下边缘:(-1.0,0.0,0.0)和(1.0,0.0,0.0)
- < canvas>的左边缘和右边缘:(0.0,-1.0,0.0)和(0.0,1.0,0.0)
片元着色器(Fragment shader)
进行逐片元处理过程如光照的程序。片元是WebGL术语,你可以将其理解为像素。片元着色器指定了点的颜色
var FSHADER_SOURCE=
'void main(){\n'+
'gl_FragColor=vec4(1.0,1.0,0.0,1.0);\n'+
'}\n';
上面这段程序表示绘制一个点,点的颜色是(1.0,1.0,0.0,1.0)->rgba、
四、绘制操作
建立了着色器之后,我们就需要进行绘制操作,使用到的是gl.drawArrays()函数,这是一个强大的函数,可以用来绘制各种图形,该函数的规范如下
gl.drawArrays(mode,first,count)
mode:指定绘制的方式,可以接受以下常量符号
形状 | mode | 方式 |
---|---|---|
点 | gl.POINTS | 绘制v0,v1…… |
线段 | gl.LINE_STRIP | 一系列单独的线段,绘制(v0,v1),(v2,v3)……如果是奇数,最后一个省略 |
线条 | gl.LINE_STRIP | 一系列连接的线段,绘制(v0,v1),(v1,v2),(v2,v3)……除了第一个和最后一个,其他的点点即是起点又是终点 |
回路 | gl.LINE_LOOP | 一系列连接的线段,绘制(v0,v1),(v1,v2),(v2,v3)……(vn,v0),最后一个点会连接起点 |
三角形 | gl.TRIANGLES | 一系列单独的三角形,绘制(v0,v1,v2),(v3,v4,v5)……如果不是3的倍数,剩下的将会被忽略 |
三角带 | gl.TRIANGLES_STRIP | 一系列连接的三角形,绘制(v0,v1,v2),(v2,v1,v3),(v2,v3,v4)……以此类推,第二个是(v2,v1,v3)而不是(v1,v2,v3)是为了保持绘制按照逆时针绘制 |
扇形 | TRIANGLE_FAN | 与GL_TRIANGLE_STRIP类似,不过它的三角形的顶点排列顺序是T = [n-1 n-2 n].各三角形形成一个扇形序列 |
first:指定从哪个顶点开始绘制
count:指定绘制需要用到多少个顶点
在上一段代码中
//设置的背景色
gl.clearColor(0.0,0.0,0.0,1.0);
//用背景色填充
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制一个点
gl.drawArrays(gl.POINTS,0,1);
gl.drawArrays(gl.POINTS,0,1);表示从v0开始画一个点
当程序调用gl.drawArrays()时,顶点着色器将被执行count次,每次处理一个顶点。一旦顶点着色器执行完后,片元着色器就会开始执行。