内容简介:WebGL 实质上是一个光栅化引擎,根据你的代码绘制出点,线和三角形。WebGL 每次绘制需要两个着色器, 一个顶点着色器和一个片断着色器,每一个着色器都是一个方法。 一个顶点着色器和一个片断着色器链接在一起放入一个着色程序中(或者只叫程序)。一个典型的 WebGL 应用会有多个着色程序。对于二维变换使用 3x3 矩阵,可以快速的实现平移,旋转,缩放,单位化效果。
一、概念基础
WebGL 实质上是一个光栅化引擎,根据你的代码绘制出点,线和三角形。
- 成对方法:在 GPU 上运行的 WebGL 代码需要是成对的方法,每对方法中一个叫顶点着色器, 另一个叫片断着色器,用 GLSL 编码。每一对组合起来称作一个 program(着色程序)。
- 属性(Attributes)和缓冲:缓冲是发送到 GPU 的一些二进制数据序列,通常情况下缓冲数据包括位置,法向量,纹理坐标,顶点颜色值等。属性用来指明怎么从缓冲中获取所需数据并将它提供给顶点着色器。
- 全局变量(Uniforms):在着色程序运行前赋值,在运行过程中全局有效。
- 纹理(Textures):纹理是一个数据序列,可以在着色程序运行中随意读取其中的数据。
- 可变量(Varyings):是一种顶点着色器给片断着色器传值的方式。
WebGL 每次绘制需要两个着色器, 一个顶点着色器和一个片断着色器,每一个着色器都是一个方法。 一个顶点着色器和一个片断着色器链接在一起放入一个着色程序中(或者只叫程序)。一个典型的 WebGL 应用会有多个着色程序。
-
顶点着色器需要的数据,获取方式分三种:
- Attributes 属性 (从缓冲中获取的数据)
- Uniforms 全局变量 (在一次绘制中对所有顶点保持一致值)
- Textures 纹理 (从像素或纹理元素中获取的数据)
-
片段着色器所需的数据,获取方式分三种:
- Uniforms 全局变量 (values that stay the same for every pixel of a single draw call)
- Textures 纹理 (data from pixels/texels)
- Varyings 可变量 (data passed from the vertex shader and interpolated)
- GLSL 是门强类型语言,以下是一些用法枚举:
// vec2, vec3和 vec4分别代表两个值,三个值和四个值 vec4 a = vec4(1, 2, 3, 4); vec4 b = a * 2.0; // b 现在是 vec4(2, 4, 6, 8); // mat2, mat3 和 mat4 分别代表 2x2, 3x3 和 4x4 矩阵 mat4 a = ??? mat4 b = ??? mat4 c = a * b; vec4 v; // v.x 和 v.s 以及 v.r , v[0] 表达的是同一个分量。 // v.y 和 v.t 以及 v.g , v[1] 表达的是同一个分量。 // v.z 和 v.p 以及 v.b , v[2] 表达的是同一个分量。 // v.w 和 v.q 以及 v.a , v[3] 表达的是同一个分量。 v.yyyy // === vec4(v.y, v.y, v.y, v.y) v.bgra // === vec4(v.b, v.g, v.r, v.a) vec4(1) // === vec4(1, 1, 1, 1) // 支持矢量调制 // 如果 v1 和 v2 都是 vec4, f 是浮点型,以下两个变量等价 vec4 m = mix(v1, v2, f); vec4 m = vec4( mix(v1.x, v2.x, f), mix(v1.y, v2.y, f), mix(v1.z, v2.z, f), mix(v1.w, v2.w, f));
二、二维变换
对于二维变换使用 3x3 矩阵,可以快速的实现平移,旋转,缩放,单位化效果。
var m3 = { translation: function(tx, ty) { return [ 1, 0, 0, 0, 1, 0, tx, ty, 1, ]; }, rotation: function(angleInRadians) { var c = Math.cos(angleInRadians); var s = Math.sin(angleInRadians); return [ c,-s, 0, s, c, 0, 0, 0, 1, ]; }, scaling: function(sx, sy) { return [ sx, 0, 0, 0, sy, 0, 0, 0, 1, ]; }, identity: function() { return [ 1, 0, 0, 0, 1, 0, 0, 0, 1, ]; }, };
关于如下一个矩阵计算,有两种解释方式:
projectionMat * translationMat * rotationMat * scaleMat * position
从右向左解释:首先将位置乘以缩放矩阵获得缩放后的位置,然后将缩放后的位置和旋转矩阵相乘得到缩放旋转位置,然后将缩放旋转位置和平移矩阵相乘得到缩放旋转平移位置,最后和投影矩阵相乘得到裁剪空间中的坐标。
从左往右解释:每一个矩阵改变的都是画布的坐标空间, 画布的起始空间是裁剪空间的范围(-1 到 +1),矩阵从左到右改变着画布所在的空间。
三、三维变换
- WebGL 中的三角形有正反面概念,通过下面代码可以开启不绘制背面三角形(顺时针方向)的特性。
gl.enable(gl.CULL_FACE);
- 深度缓冲(DEPTH BUFFER):WebGL 绘制一个着色像素之前会检查对应的深度像素, 如果对应的深度像素中的深度值小于当前像素的深度值,WebGL 就不会绘制新的颜色。 反之它会绘制片断着色器提供的新颜色并更新深度像素中的深度值。如下命令可以开启这个特性:
gl.enable(gl.DEPTH_TEST);
- 三维矩阵相比二维多一行一列,(x,y,z,w) 中 w 可以用于透视投影(近大远小)处理。
- 日常观察的物体都应是透视投影,而非正射投影。
四、动画与纹理
实现动画与 WebGL 并不直接相关,需要利用 JavaScript 随着时间改变一些值然后绘制。在此处请使用 requestAnimationFrame API.
-
GPU 在绘制时使用的是一个纹理贴图,它是一个逐渐缩小的图像集合, 每一个是前一个的四分之一大小(方法:双线性插值)。
gl.generateMipmap
做的事情就是根据原始图像创建所有的缩小级别。使用generateMipmap
时需注意纹理的维度必须是2的整数次幂。
由于纹理需要异步加载资源,所以在物体渲染上存在两种处理方式。
- 纹理图集:将多个图像通过一个纹理提供的方法,即将图像放在一个纹理中,然后利用纹理坐标映射不同的图像到每个面。
五、组织结构
一个 WebGL 应用推荐遵循的结构
-
初始化阶段
- 创建所有着色器和程序并寻找参数位置
- 创建缓冲并上传顶点数据
- 创建纹理并上传纹理数据
-
渲染阶段
- 清空并设置视图和其他全局状态(开启深度检测,剔除等等)
-
对于想要绘制的每个物体(此处可抽象复用)
-
调用
gl.useProgram
使用需要的程序 -
设置物体的属性变量
-
为每个属性调用
gl.bindBuffer
,gl.vertexAttribPointer
,gl.enableVertexAttribArray
-
为每个属性调用
-
设置物体的全局变量
-
为每个全局变量调用
gl.uniformXXX
-
调用
gl.activeTexture
和gl.bindTexture
设置纹理到纹理单元 -
调用
gl.drawArrays
或gl.drawElements
-
为每个全局变量调用
-
调用
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。