WebGL学习系列-基本图形变换

Posted 那个天真的人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebGL学习系列-基本图形变换相关的知识,希望对你有一定的参考价值。

前言

经过前面的学习,我们已经可以绘制基本的图形了。本小节将介绍基本的图形变换,介绍在WebGL中,如何对基本的图形进行平移、旋转和缩放。

平移

在前面的小节中,我们已经绘制过一个三角形,那时候,它看起来是这样的:

我们知道,在WebGL中,要绘制一个基本的图形,我们只需要指定顶点的位置、大小和颜色,然后调用drawArrays接口进行绘制即可。现在,我们想要实现对三角形进行一个平移,比如,把它移到右上角的地方,那如何实现呢?

其实仔细想想,你会发现,我们要移动一个三角形,只需要移动它的三个顶点即可,然后WebGL将会自动在新的顶点位置把三角形绘制出来。

其原理示意图如下:

为了进一步说明在程序中是如何实现平移的,我们先来看下顶点着色器代码:

// 顶点着色器代码(决定顶点的位置、大小、颜色)
var VSHADER_SOURCE = 
  'attribute vec4 a_Position;\\n' +
  'uniform vec4 u_Translation;\\n' +
  'void main() \\n' +
  '  gl_Position = a_Position + u_Translation;\\n' + // 设置顶点的位置
  '  gl_PointSize = 10.0;\\n' +      // 设置顶点的大小
  '\\n';

主要看到两个地方有所变动 :
1、添加了 uniform vec4 u_Translation 定义
2、顶点的位置使用两个 vec4 变量进行相加, gl_Position = a_Position + u_Translation

我们以前曾经使用过 attribute变量,用于直接表示顶点的位置,那时我们知道每个顶点的位置都不一样,而现在,为了对三角形进行平移,实际上是对三个顶点都进行了相同的平移,也就是说,平移的量对所有顶点是一致的,这样所有顶点共享的变量在WebGL中使用uniform 关键字进行表示。

既然定义了 uniform 变量,那么就需要对它进行赋值,对它的赋值跟对 attribute变量进行赋值的流程是完全一样的。

// 三角形顶点的平移量
var Tx = 0.5, Ty = 0.5, Tz = 0.0;
var u_Translation = context.getUniformLocation(context.program,'u_Translation');
context.uniform4f(u_Translation, Tx, Ty, Tz, 0.0);

我们定义了 Tx,Ty,Tz 表示顶点在x、y、z 轴上的位移,最后使用 uniform4f 方法对 u_Translation变量进行了赋值,这里有个地方要注意,方法 uniform4f 最后一个参数我们设置为了0.0,因为我们要确保两个vec4变量相加后,第四个参数为1。a_Position 变量第四个参数已经设置为1,所以u_Translation第四个参数只能设置为0。

最后,我们来看下平移后的效果图:

旋转

旋转看起来比平移要复杂一些,在考虑旋转的时候,我们要考虑三个点:

  1. 绕着哪个轴旋转
  2. 旋转的方向(顺时针还是逆时针)
  3. 旋转的角度

在这里,我们以绕着Z轴逆时针旋转来推导

由上图可以看到,当一个点 p(x,y,z) 沿着Z轴逆时针旋转到 p(x,y,z) 时,可以得到p点满足如下等式:

x=rcosαy=rsinα
同理, p 也满足如下等式:
x=rcos(α+β)=r(cosαcosβsinαsinβ)y=rsin(α+β)=r(sinαcosβ+cosαsinβ)

根据 p p的坐标等式,可以得到 p 的新的坐标表示:

x=xcosβysinβy=xsinβ+ycosβz=z

有了以上旋转后的点的坐标公式,我们便可以编写顶点着色器代码了:

// 顶点着色器代码(决定顶点的位置、大小、颜色)
var VSHADER_SOURCE = 
  'attribute vec4 a_Position;\\n' +
  'uniform float u_CosB, u_SinB;\\n' +
  'void main() \\n' +
     'gl_Position.x = a_Position.x * u_CosB - a_Position.y * u_SinB;\\n' +
     'gl_Position.y = a_Position.x * u_SinB + a_Position.y * u_CosB;\\n' +
     'gl_Position.z = a_Position.z;\\n' +
     'gl_Position.w = 1.0;\\n' +
     'gl_PointSize = 10.0;\\n' +      // 设置顶点的大小
  '\\n';

注意,我们可以通过 . 符号来访问一个vec4变量的x、y、z、w 四个分量值 ,绕着Z轴旋转,只需要计算x和y坐标值即可。

对于u_CosB和u_SinB,由于对三角形三个顶点而言,旋转的角度是一样的,所以变量应该是所有顶点共享,使用uniform进行声明,其赋值如下:

// 旋转的角度
var ANGLE = 30;
var radian = Math.PI * ANGLE / 180.0; //转为弧度
var cosB = Math.cos(radian);
var sinB = Math.sin(radian);

var u_CosB = context.getUniformLocation(context.program, 'u_CosB');
var u_SinB = context.getUniformLocation(context.program, 'u_SinB');
context.uniform1f(u_CosB, cosB);
context.uniform1f(u_SinB, sinB);

这段代码很简单,相信都应该明白了。

绕着Z轴逆序旋转30度的效果图:

如果想要的是顺时针的旋转,把ANGLE设置为负数即可,大家可以拿源码改改试试,这就是三角函数的精妙之处。

以上推导的是绕着Z轴进行旋转,其实绕着x轴或者y轴也可以用类似的方式进行推导,大家有兴趣可以试着推导一下。

缩放

缩放其实是比较简单的,我们来看缩放示意图:

p(x,y,z) 缩放后,在三个轴的缩放因子为: Sx Sy Sz ,则缩放后,点 p(x,y,z) 的坐标如下:

x=xSxy=ySyz=zSz

然后我们来看下顶点着色器的代码:

// 顶点着色器代码(决定顶点的位置、大小、颜色)
var VSHADER_SOURCE = 
  'attribute vec4 a_Position;\\n' +
  'uniform float a_Scale;\\n' +
  'void main() \\n' +
  '  gl_Position.x = a_Position.x * a_Scale;\\n' + 
  '  gl_Position.y = a_Position.y * a_Scale;\\n' + 
  '  gl_Position.z = a_Position.z * a_Scale;\\n' + 
  '  gl_Position.w = 1.0;\\n' + 
  '  gl_PointSize = 10.0;\\n' +      // 设置顶点的大小
  '\\n';

我们定义了一个uniform变量a_Scale,所有顶点都使用相同的缩放,然后对顶点的x、y、z值分别进行坐标变换。a_Scale的初始化也非常的简单。

// 三角形顶点的缩放
var scale = 0.5;
var u_Scale = context.getUniformLocation(context.program, 'a_Scale');
context.uniform1f(u_Scale, scale);

缩放后的三角形效果图:

小结

三角形的基础变换是非常重要的知识,还是要花点时间理解一下,目前使用的是简单的数学知识进行推导,其实,在图形学中,真正强大的是用矩阵进行计算,后面将会详细解说。

源码

点击下载(基本图形变换)

参考

<<WebGL编程指南>>

以上是关于WebGL学习系列-基本图形变换的主要内容,如果未能解决你的问题,请参考以下文章

WebGL学习系列-基础矩阵变换

WebGL学习系列-片元着色器简介

HTML5原生WebGL开发系列教程

HTML5原生WebGL开发系列教程

webgl变换:深入图形平移

WebGL简易教程:图形变换(模型视图投影变换)