首先了解什么是WebGL?
WebGL 是一种 3D 绘图标准,这种绘图技术标准允许把 JavaScript 和 OpenGL ES 2.0 结合在一起,通过增加 OpenGL ES 2.0 的一个 JavaScript 绑定,WebGL 可以为 HTML5 Canvas 提供硬件 3D 加速渲染,这样 Web 开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。
下面我们就开始写一个简单的。
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>第一个WebGL尝试</title>
</head>
<body>
<div>
<!--WebGL 是JavaScript API, 内容都写在HTML5 的<canvas> 标签底下-->
<canvas id="canvas" width="500" height="500"></canvas>
</div>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if(!gl){
console.log("该浏览器不支持WEBGL");
}else{
//设置清除颜色(红色,不透明)
gl.clearColor(1.0, 0.0, 0.0, 1.0);
//深度清理
gl.clearDepth(1.0);
//开启“深度测试”,Z-缓存
gl.enable(gl.DEPTH_TEST);
//设置深度测试,近的物体遮挡远的物体
gl.depthFunc(gl.LEQUAL);
//清理画布
gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
}
</script>
</body>
</html>
效果运行如下:
方法参数参照如下:
1.HTMLCanvasElement.getContext()
2.WebGLRenderingContext.clearColor()
接着我们了解下一步:
WebGL 的出现使得在浏览器上面实时显示 3D 图像成为可能,WebGL 本质上是基于光栅化的 API ,而不是基于 3D 的 API。
WebGL 只关注两个方面,即投影矩阵的坐标和投影矩阵的颜色。使用 WebGL 程序的任务就是实现具有投影矩阵坐标和颜色的 WebGL 对象即可。可以使用“着色器”来完成上述任务。顶点着色器可以提供投影矩阵的坐标,片段着色器可以提供投影矩阵的颜色。
无论要实现的图形尺寸有多大,其投影矩阵的坐标的范围始终是从 -1 到 1 。
说起3D,我们需要对三维图形,也就是立体几何有个概念。当然对于矩阵也最好有些理解,
那么接下来先了解一下
矩阵
在3D中,一般使用4x4的矩阵。
相乘
矩阵相乘在3D图形中是一个非常重要的运算,在3D中无论是移动、旋转还是缩放大小,都是通过在当前矩阵的基础上乘以一个新的矩阵来达到目的。
单位矩阵
可以理解为常量中的1,任何矩阵乘于单位矩阵都不变。
逆矩阵
逆矩阵可以理解为倒数,即当前矩阵乘于其逆矩阵的结果为单位矩阵,需要注意的是,只有方阵(行列数量相等)才有逆矩阵,同时不是所有的方阵都有逆矩阵。
引入逆矩阵的原因之一是用来实现矩阵的除法。比如有矩阵X,A,B,其中XA = B,我们要求X矩阵的值。本能来说,我们只需要将B/A就可以得到X矩阵了。但是对于矩阵来说,不存在直接相除的概念。我们需要借助逆矩阵,间接实现矩阵的除法。具体的做法是等式两边在相同位置同时乘以矩阵A的逆矩阵,如下所示,XA(A的逆矩阵)=B(A的逆矩阵)。由于A(A的逆矩阵)=I,即单位矩阵,任何矩阵乘以单位矩阵的结果都是其本身。所以,我们可以得到X=B(A的逆矩阵)。
转置矩阵
转置矩阵是指将行列互换之后的矩阵,和逆矩阵常用于法线变换。
仿射变换
矩阵的仿射变换包含了主要包含了平移、旋转和缩放。
坐标系、向量
在我们现实世界中,每个东西都有它的长、宽、高等度量分量,那么我们对它进行建模的时候会使用到一个对象坐标系。将这个对象放入现实世界,那么它就存在于现实世界中的世界坐标系。我们将它显示在我们的系统设备上,则它存在于应用程序坐标系。
我们把应用程序中度量顶点位置的数值称为顶点坐标。
用显示器上单位度量出的数值起初叫做物理设备坐标或者叫设备坐标。对于光栅设备,我们使用的术语是窗口坐标或者屏幕坐标。屏幕坐标总是用某种整数类型来表示,因为帧缓存中任何像素中心都必须位于固定的网格点上。
然后就是
基本图元
在webgl中,所有的几何图元都是由点、线和三角形这样的基本图元组成。
webgl 提供了多种点和线段图元,相应的type参数如下:
点
点就只有一种类型:gl.POINTS。可以在顶点着色器中使用内置变量gl_PointSize设置点精灵的大小。
线
WebGL中绘制线有三种方式:gl.LINES(独立线)、gl.LINE_STRIP(线带)、gl.LINE_LOOP(线环)。
对于一系列点(v0、v1、v2、......),独立线每两个点组成一条线((v0,v1)、(v2,v3)、......);线带每次将当前线的后面一个顶点与下一个顶点组成三角形((v0,v1)、(v1,v2)、......);线环与线带类似,线环最后一个顶点与第一个顶点相连。
三角形
WebGL中绘制三角形有三种方式:gl.TRINGLES(独立三角形)、gl.TRINGLE_STRIP(三角形带)、glTRINGLE_FAN(三角形扇)。
对于一系列点(v0、v1、v2、......),独立的三角形每三个点组成一个三角形((v0,v1,v2)、(v2,v3,v4)、......);三角形带每次将当前三角形的后面两个顶点与下一个顶点组成三角形((v0,v1,v2)、(v1,v2,v3)、......);三角形扇除掉第一个顶点,后面的每两个顶点与第一个顶点组成三角形((v0,v1,v2)、(v0,v3,v4)、......)。
......
综合起来基本就三种:
最后就了解到
Shader
着色器 着色器作为WebGL核心主要分为:顶点着色器 和 片元着色器
顶点着色器
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
}
</script>
片元着色器
<script id="2d-fragment-shader" type="x-shader/x-fragment">
void main() {
gl_FragColor = vec4(0, 1, 0, 1); // green
}
</script>
如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>第二个WebGL尝试</title>
<script src="webgl-utils.js"></script>
</head>
<body>
<div>
<!--WebGL 是JavaScript API, 内容都写在HTML5 的<canvas> 标签底下-->
<canvas id="canvas" width="300" height="300"></canvas>
</div>
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
}
</script>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
void main() {
gl_FragColor = vec4(1, 0, 0, 1); // red
}
</script>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if(!gl){
console.log("该浏览器不支持WEBGL");
}else{
var program = createProgramFromScripts(gl,["2d-vertex-shader", "2d-fragment-shader"]);
gl.useProgram(program);
var positionLocation = gl.getAttribLocation(program, "a_position");
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
-1.0, -1.0,
1.0, -1.0,
-1.0, 1.0,
-1.0, 1.0,
1.0, -1.0,
1.0, 1.0]),
gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// draw
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
</script>
</body>
</html>
createProgramFromScripts方法在外部webgl-utils.js中。
附录: