What is WegGL?

OpenGL 最初由 SGI(Silicon Graphics Inc) 开发,并在1992年发布为开源标准,它是一种3D开源库。为适用于智能手机、平板电脑、 家用游戏机等轻便设备, OpenGL ES 于2003~2004年被提出,后来进行了两次升级 —— ES 2.0(1997) 和 ES 3.0(2012),WebGL 是基于 OpenGL ES 2.0 的。 其中 GL 的全称是 Graphics Library,意为图形库。编程时,采用一种类似于 C 语言的着色器语言 GLSL —— Graphics Library Shading Language 图形库着色编程语言。

使用 WebGL 的网页包含这3部分:Html5, JavaScript, GLSL ES.
html: <canvas id="canvas" width="800" height="500"></canvas> js: var canvas = document.getElementById('canvas'); var gl = canvas.getContext('webgl');

GLSL ES: 有两种写法,可写在<script>标签里,加上id;也可写在js文件里,需要用引号''。

What is Shader?

着色器是 WebGL 依赖的绘图机制,是 WebGL 的核心机制。它内置了矢量和矩阵运算功能。着色器程序运行在显卡中。 着色器是使用 GLSL 编写的程序,它携带着绘制形状的顶点信息以及构造绘制在屏幕上像素的所需数据,换句话说, 它负责记录着像素点的位置和颜色。着色器运行在 WebGL 系统中,而非 JavaScript 程序中。在初始化着色器之前, 顶点着色器和片元着色器都是空白的, 我们需要将着色器代码从 JavaScript 传给 WebGL 系统,并建立着色器。

Vertex shader:   顶点着色器时用来描述顶点位置的程序,先执行。 它的工作是将输入顶点从原始坐标系转换到WebGL使用的缩放空间 (clipspace) 坐标系,其中每个轴的坐标范围从-1.0到1.0。 位置存储在变量 gl_Position 中,类型是vec4。尺寸储存在变量 gl_PointSize 中,类型是float,默认值是1.0。

Fragment shader:  片断着色器用来处理点的颜色、光照的程序,后执行。颜色存储在变量 gl_FragColor 中,类型是vec4。

WebGL 程序流程

获取 <canvas> 元素 document.getElementById('canvas')
获取 WebGL 绘图上下文 gl = canvas.getContext('webgl')
初始化着色器 initShader
设置背景色 gl.clearColor( r, g, b, alpha )
清空颜色缓冲区,深度缓冲区 gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.DEPTH_BUFFER_BIT)
绘图 gl.drawArrays( mode, first, count )

WebGL 坐标系统

<canvas> 坐标:y轴向下,原点在左上角,width、height、位置 以像素计算。而 WebGL 系统还多了个计算深度的z轴,在二维的 xOy 平面上, y轴向上,原点在 <canvas> 的中心:(0.0, 0.0, 0.0),坐标是以 Float 来计算。x轴的左右端点坐标分别是 (-1.0, 0.0, 0.0) 和 (1.0, 0.0, 0.0);y轴的上下端点坐标分别是 (0.0, 1.0, 0.0) 和 (0.0, -1.0, 0.0)。

如何得到从屏幕的坐标到 WebGL 的坐标呢? 首先求屏幕坐标到 <canvas> 的坐标变换,只需要减去 <canvas> 的左上角的对应的 x、y 值即可。 <canvas> 在屏幕中的区域为 rect = canvas.getBoundingClientRect( ),左上角的对应的 x、y 值分别为 rect.left 和 rect.top。 那么屏幕中的坐标在 <canvas> 的坐标是 x - rect.left 和 y - rect.top。

<canvas> 的坐标又怎么变换到 WebGL 的坐标呢? 因为 WebGL 的坐标在 <canvas> 的正中心,所以x坐标要减去 canvas.width 的一半,但 WebGL 坐标的最大值是1.0,所以还要除以 canvas.width 的一半。y坐标也依据相同的逻辑计算:
x = ( (x - rect.left) - canvas.width/2 )/( canvas.width/2 );
y = ( canvas.height/2 - (y - rect.top) )/( canvas.height/2 );

如果 <canvas> 的 width、height 不一致,会导致绘制出来的图形拉伸、变形,下图的左边图形是 <canvas> 的 width = height 时绘制出来的,右边则是 width > height 时绘制出来的,旋转时,把原来的等腰三角形绘制得不等腰了。




<canvas> 上显示的就是可视空间中物体在近裁剪面上的投影。如果裁剪面的宽高比和 <canvas> 的不一样,那么画面就会被按照 <canvas> 的宽高比进行压缩。