首页 > 技术文章 > WebGL 踩坑系列-1

brifuture 2018-01-05 21:29 原文

WebGL 中的一些选项
WebGL 中开启颜色混合(透明效果)
gl.enable(gl.BLEND);   
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

设置遮挡剔除有效。生成三角形时,沿着逆时针方向的那面会被生成出来,而另一面就不会生成出来。

gl.enable(gl.CULL_FACE); 
gl.cullFace(gl.BACK);

观察球面的效果:

 

当设置透明效果却不开启遮挡剔除的时候,用 web GL 生成球面,在球外观察球面时就会看到一些奇怪的角。

 第二个球就很明显的有一些不同的部分。

 

在 web GL 中使用矩阵

可以利用矩阵的平移、旋转、缩放实现物体的各种动作。

我在最开始使用 Web GL 绘图的时候,球面上的点都是利用循环得到,但是由于有缩放球面的需求,所以最开始的做法是

1. 创建缓冲区时用的 gl.DYNAMIC_DRAW

2. 当要缩放球面时,重新计算顶点

3. 用 gl.updateBufferData 函数更新定点数据

当缩放的时候就能明显看到画面撕裂,帧率下降。

可能的原因是:

1. 每次重新计算都要使用大量的计算资源,若帧率为 60,那么每秒要计算上千个顶点,如果球面较精细,那么需要计算的顶点数更多。

2. 并且每次计算之后都要将这些顶点传入到 GPU 中,可能会占用一部分的传输带宽

正常的做法是用坐标变换矩阵,将变换后的矩阵通过  gl.uniformMatrix4fv 传入到着色器,就可以轻松的实现平移旋转和缩放。并且不会造成性能严重下降。

但是矩阵的乘法与普通的数乘有所差别,矩阵的乘法一般不满足交换律。

若 pMatrix 表示透视矩阵,vMatrix 表示视图矩阵,mMatrix 表示模型矩阵,aVertex 表示传入的顶点,那么一般的乘式是

gl_Position = pMatrix * vMatrix * mMatrix * aVertex;

如果矩阵的顺序不同,可能最后得到的图形也就不同。

 

对矩阵先进行旋转操作,再进行平移操作。缩放操作的顺序一般没有影响。

但我在使用 gl-Matrix.js 时,对一个矩阵先进行旋转,再进行平移操作:

1 mat4.identity(this.mMatrix);
2 
3 mat4.fromRotation(this.mMatrix, angle[1] * Math.PI*2, [0, 0, 1]);
4 mat4.rotate(this.mMatrix, this.mMatrix, angle[0] * Math.PI, [0, 1, 0]);
5 mat4.translate(this.mMatrix, this.mMatrix, pos);
6 
7 mat4.multiply(mvpMatrix, pvMatrix, this.mMatrix);
8 gl.uniformMatrix4fv(uniforms.pmv_matrix, false, mvpMatrix);

 

和将旋转操作和平移操作放在两个矩阵中进行得到的结果并不相同。

1 mat4.identity(this.mMatrix);
2 
3 mat4.fromRotation(this.rMatrix, angle[1] * Math.PI*2, [0, 0, 1]);
4 mat4.rotate(this.rMatrix, this.rMatrix, angle[0] * Math.PI, [0, 1, 0]);
5 mat4.translate(this.mMatrix, this.mMatrix, pos);
6 mat4.mul(this.mMatrix, this.mMatrix, this.rMatrix);
7 
8 mat4.multiply(mvpMatrix, pvMatrix, this.mMatrix);
9 gl.uniformMatrix4fv(uniforms.pmv_matrix, false, mvpMatrix);

注意这里用 pvMatrix 乘  mMatrix 之前先用 mMatrix 乘了一个附加矩阵 rMatrix

具体的原因并不清楚,但是第二个操作实现的图像符合我的需求。

 

=========================

这几天又重新测试了下代码,发现上面的旋转平移操作的矩阵还是有些问题,

具体问题在于经过旋转平移后的面上反的,以下矩阵操作可以方便的做到旋转平移,并且得到的面上正的

1 mat4.fromZRotation(this.rMatrix,         this.beta);   // 绕 Z 轴旋转 beta 角
2 mat4.rotateY(this.rMatrix, this.rMatrix, this.theta);  // 再绕 Y 轴旋转 theta 角 
3 mat4.fromRotationTranslation(this.mMatrix, this.rMatrix, pos);
4 mat4.rotateZ(this.mMatrix, this.mMatrix, this.beta);
5 mat4.rotateY(this.mMatrix, this.mMatrix, this.theta);

最后得到的面就是我想要的

 

完整的代码可以在我的 GitHub 上查看。

 

推荐阅读