WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染(部分计算GPU),这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。总结一下,WebGL的本质 —— JavaScript操作OpenGL接口。
JavaScript操作一些OpenGL接口,也就意味着,可能会编写一部分GLSL ES 2.0的代码,WebGL只是绑定了一层,内部的一些核心内容,如着色器,材质,灯光等都是需要借助GLSL ES语法来操作的.
WebGL / OpenGL 之间的关系?
•OpenGL(Open Graphics Library)
一种图形应用程序编程接口规范(Application Programming Interface,API)。它是一种可以对图形硬件设备特性进行访问的软件库,OpenGL被设计为一个现代化的、硬件无关的接口,因此我们可以在不考虑计算机操作系统或窗口系统的前提下,在多种不同的图形硬件系统上,完全通过软件的方式实现OpenGL的接口。•OpenGL ES(embedded system)
OpenGL ES
是OpenGL的一个特殊版本,主要针对嵌入式设备使用,专用于嵌入式计算机、智能手机、家用游戏机等设备。OpenGL ES 2003-2004年被首次提出来,其中两次重要升级分别在2007年(OpenGL ES 2.0)和2012年(OpenGL ES 3.0),WebGL就是基于OpenGL ES 2.0的。
绘制流程
var canvas = document.getElementById("canvas");
gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
//指定一个覆盖(清空)canvas的rgba颜色,本质是setColor,它把背景色存到了webgl system中的glCOLOR_BUFFER_BIT,需要render一下
gl.clearColor(0.0,0.0,0.5,1.0)
//清除canvas,会清除全部,再使用背景色 填充
gl.clear(gl.COLOR_BUFFER_BIT)
结论:
WebGL需要依赖canvas这个载体获取对应的绘图上下文
WebGL API基于OpenGL ES,函数命名相对应
WebGL基于多缓冲区模型
绘制一个点
如果类似canvas 2d的话,你可能以为WebGL绘制一个点:
gl.drawColor(1.0,1.0,1.0,1.0)//点的颜色
gl.drawPoint(0,0,0,10)//点的位置大小
类似这样就可以了,不幸的是:WebGL依赖于一种着色器(shader)的绘图机制,复杂而强大,着色器是 WebGL的核心机制。WebGL中着色器程序可以写成字符串变量:
//着色器运行在WebGL系统中,而不是JS程序
//创建顶点着色器 描述顶点特性(位置,尺寸)
var VSHADER_SOURCE =
'void main() {\n' +
' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n' +
' gl_PointSize = 10.0;\n' +
'}\n';
//创建片元着色器 描述 片元(像素)处理过程。
var FSHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
'}\n';
着色器中包含几个内置变量:gl*Position, gl*PointSize, gl_FragColor。
着色器语言中涉及到vec4的数据类型,此数据类型是一个思维浮点数组,所以其值不可以是整形如(1,1,1,1),正确应为:****(1.0,1.0,1.0,1.0)
gl_Position: 为一种vec4类型的变量,且必须被赋值。四维坐标矢量,我们称之为齐次坐标,即(x,y,z,w)等价于三维左边(x/w,y/w,z/w),w相当于深度,没有特殊要求设置为1.0即可。
gl_PointSize:表示顶点的尺寸,也是浮点数,为非必填项,如果不填则默认显示为1.0。
-
gl_FragColor:该变量为片元着色器唯一的内置变量,表示其颜色,也是一个vec4类型变量,分别代表(R,G,B,A),不过颜色范围是从0.0-1.0对应Javascript中的#00-#FF。
有了着色器我们就可以着手去绘制图像了,既然绘制3D图形,必然会有对应的三维坐标系,WebGL采用右手坐标系,如图所示:
var program = gl.createProgram();
// 创建顶点着色器
var vShader = gl.createShader(gl.VERTEX_SHADER);
// 创建片元着色器
var fShader = gl.createShader(gl.FRAGMENT_SHADER);
// shader容器与着色器绑定
gl.shaderSource(vShader, VSHADER_SOURCE);
gl.shaderSource(fShader, FSHADER_SOURCE);
// 将GLSE语言编译成浏览器可用代码
gl.compileShader(vShader);
gl.compileShader(fShader);
// 将着色器添加到程序上
gl.attachShader(program, vShader);
gl.attachShader(program, fShader);
// 链接程序,在链接操作执行以后,可以任意修改shader的源代码,
//对shader重新编译不会影响整个程序,除非重新链接程序
gl.linkProgram(program);
// 加载并使用链接好的程序
gl.useProgram(program);
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0 ,1);
光栅化
顶点着色器的信息在传递给OpenGL底层绘制的时候,会先进行光栅化,也就是把点转化成对应的像素。然后在片元着色器会逐个点进行渲染,最终就达到了视觉看到的效果。
点也是一样,会将点转变成多个像素点,所以要变成圆点,需要如下的方式
我们需要在片元着色器中来处理,将非原型区域的像素点,不用片元着色器来绘制,着色器需要判断距离圆点的位置超过0.5的话,就忽略此片元点,最终就会出现一个圆点的效果。
var FSHADER_SOURCE = `
\#ifdef GL_ES
precision mediump float;
\#endif
void main() {
float d = distance(gl_PointCoord, vec2(0.5,0.5));
if(d < 0.5){
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}else{ discard;}
}`;