[WebGL入门]三十二,四元数和minMatrixb.js

来源:互联网 发布:华为手机推荐2017知乎 编辑:程序博客网 时间:2024/06/07 19:22

注:文章译自http://wgld.org/,原作者杉本雅広(doxas)


这次demo的执行结果

处理四元数的库

上次主要介绍了一下四元数是什么,以及它的计算方法。但是,只有这些的话,还无法了解四元数的实际用法。
这次结合实际应用,来继续了解一下。将三维空间中的坐标变换为四元数,然后进行旋转处理。
虽说,本次用来解说的demo,即使不使用四元数也能轻易的实现,但是使用了四元数之后,会更加的直观一些。
对于四元数周边的处理,会使用到本网站的算法库minMatrixb.js,还有另一个与矩阵相关的处理就是它的姐妹库minMatrix.js。四元数相关的处理是相对比较难的,使用minMatrixb.js能让简化四元数的计算。minMatrixb.js的详细用法已经准备了另一片文章,大家可以参考一下。(lufy:我就不分开翻译了,和本篇合并到一起放到文章后半部分了。)

利用四元数控制镜头

这次的demo会试着使用四元数来控制镜头。
镜头是通过视图坐标变换矩阵来定义的。生成视图坐标变换矩阵的时候,使用的方法是minMatrix.js中的matIV.lookAt函数。
这里出现的lookAt函数,需要镜头坐标,镜头的视点,镜头的上方向三个参数。因为要使用四元数来控制镜头,所以要使用四元数来操作这些镜头相关的信息。
这次的demo,在原点渲染一个圆环,并且一边旋转圆环一边处理镜头。具体一点说,放置在位于原点前方位置(z值为正的位置)的镜头,让镜头以x方向为轴,以原点为中心进行旋转,目的是让原点始终在镜头内。
用语言描述起来比较难理解,可以看一下下面的图。


为了达到这样的镜头效果,程序要怎么做呢?这里的重点是,生成视图坐标变换矩阵的时候的镜头相关的信息。
首先,不做旋转的镜头如下图所示(图中的モデル就是原点)。


模型在原点处进行渲染,镜头单纯的面向这个位置。在镜头运动的时候,镜头需要一直面向这个模型,这时候如果只旋转坐标的话效果如下。


这样明显是很奇怪的吧。所以,镜头的坐标移动之后,镜头的方向也需要跟着变化,才能得到正确的渲染效果。
比如说,像飞行模拟器那样渲染飞行体的场景,考虑一下镜头在飞行体周围边旋转边进行拍摄,这个镜头的上方向其实就像人的脖子一样。
正确的进行镜头坐标和镜头的上方向的变换,得到正确的变换结果,效果如下图所示。


这次的demo的目的,就是像上图那样控制镜头,并且使用四元数进行控制。

根据四元数进行向量旋转

上次已经介绍了,利用四元数对向量进行旋转的时候,使用持有旋转信息的四元数和它的共轭四元数来进行计算。
本站所用的算法库minMatrixb.js中,已经封装了旋转三位向量的函数,那就是qtnIV.toVecIII函数。
这个函数的内部,根据参数自动生成共轭四元数并进行计算。传入三个参数,持有旋转信息的四元数,要旋转的向量,保存计算结果用的向量,就可以轻松的将一个向量旋转。

※下面,q是qtnIV对象的实例化对象。
>toVecIII函数的例子

q.toVecIII([0.0, 0.0, 10.0], quaternion, vector);
当然,传入toVecIII中的四元数,要将这个四元数进行旋转。上一篇文章中也讲了如何旋转一个四元数,使用minMatrixb.js的话,就可以很简单的旋转一个四元数了。
使用qtnIV.rotate函数对四元数进行旋转,这个函数需要三个参数,旋转角度,轴向量,保存结果用的四元数。
>rotate函数的例子
q.rotate(radian, [1, 0, 0], quaternion)
如上,可以生成一个以X轴为中心,旋转量为radian的四元数。使用这个生成的四元数,执行toVecIII,就可以旋转一个三维向量了。
上面这样,本次使用四元数对镜头进行控制。具体地说,用四元数来对应相关的镜头的坐标和镜头的上方向,就可以让镜头保持对着模型进行旋转。

demo的代码

这次的demo,跟之前一样用电光源进行光照,然后用四元数来控制镜头。电光源部分的着色器不做什么修改,所以HTML部分就不多说明了。
在javascript程序中,做了四元数的初始化,以及镜头相关的变量的声明。然后,在循环处理中,动态旋转四元数并进行渲染。


>四元数的初始化处理

// 四元数の生成と初期化var q = new qtnIV();var xQuaternion = q.identity(q.create());
执行了上述的处理之后,变量xQuaternion就表示了单位话的四元数。
接着,向四元数中加入旋转信息,对四元数进行旋转。
>四元数的旋转和向量的对应
// 镜头坐标var camPosition = [0.0, 0.0, 10.0];// 表示镜头的上方向的向量var camUpDirection = [0.0, 1.0, 0.0];// 计数器的声明var count = 0;// 持续循环(function(){    // canvas的初始化    gl.clearColor(0.0, 0.0, 0.0, 1.0);    gl.clearDepth(1.0);    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);        // 计数器递增    count++;        // 利用计数器来计算弧度    var rad  = (count % 180) * Math.PI / 90;    var rad2 = (count % 720) * Math.PI / 360;        // 四元数的旋转    q.rotate(rad2, [1, 0, 0], xQuaternion);    q.toVecIII([0.0, 0.0, 10.0], xQuaternion, camPosition);   // *1    q.toVecIII([0.0, 1.0, 0.0], xQuaternion, camUpDirection); // *2        // 视图和投影的坐标变换矩阵    m.lookAt(camPosition, [0, 0, 0], camUpDirection, vMatrix);    m.perspective(45, c.width / c.height, 0.1, 100, pMatrix);    m.multiply(pMatrix, vMatrix, tmpMatrix);        // 中间省略        // 持续循环    setTimeout(arguments.callee, 1000 / 30);})();
中间的处理大多被省略了,只看重点部分就可以了。
保存镜头坐标的变量是camPosition,保存镜头上方向的变量是camUpDirection。在循环中,每次将计数器递增并计算弧度。使用计算出的弧度,首先对四元数进行旋转。
如果能向四元数加入旋转信息的话,然后就可以对向量进行旋转了。上面*1部分的代码,是镜头的坐标变换的处理。*2部分的代码是对表示镜头上方向的变量进行旋转。
虽然省略了uniform变量的生成和描画的命令,主循环中对四元数进行了怎样的处理也应该能理解了。

总结

这次的demo,镜头会始终保持对着圆环体并绕着圆环体的周围进行旋转。虽然只是进行了简单的旋转处理,却特意使用了四元数,这也是为了让大家能够更深入的理解。使用minMatrixb.js和四元数,可以非常轻松的对向量进行旋转。如果看一下minMatrixb.js的代码,可以更深入的了解一下四元数的操作计算。其实这次也只是涉及到一些四元数的基本的使用。无论是什么,理解了基本的用法,以后一定会很有用的。下面会给出demo的链接,大家可以确认一下。下一回会更具体的介绍一下四元数的用法,利用鼠标来旋转模型。

利用minMatrixb.js 操作四元数的demo





------------------------------------------------------------------------

下面是minMatrixb.js的用法

------------------------------------------------------------------------

概要

一个用于WebGL的库,包含矩阵计算和四元数计算。
封装了基本的4 x 4 的方阵以及四元数的相关计算,也可以输出立方体,球体,圆环体等模型数据。
库的内部使用了Float32Array,所以无法保证所有浏览器可以正常使用。
和它的姐妹库minMatrix.js一样,基本上没做什么错误处理,实际用的时候最好扩展一下。下面带[※]的部分,minMatrix.js中也封装了。如果只进行基本的矩阵计算的话,使用minMatrix.js就可以了。
minMatrix.js已经有文章进行详细的说明了,传送门http://blog.csdn.net/lufy_legend/article/details/38427571。这里就不再进行重复的翻译了。
这个库是完全免费的,修改也可以自由进行,可能还会对本站起到一些宣传作用呢。


matIV 构造器 ※

create 函数 ※
identity 函数 ※
multiply 函数 ※
scale 函数 ※
translate 函数 ※
rotate 函数 ※
lookAt 函数 ※
perspective 函数 ※
transpose 函数 ※

inverse 函数 ※


>>ortho 函数
构成:matrix matIV.ortho(float left, float right, float top, float bottom, float near, float far, matrix dest)第一个参数:left:截面左端的位置第二个参数:right:截面右端的位置第三个参数:top:截面上端的位置第四个参数:bottom:截面下端的位置第三个参数:near:近截面的位置第四个参数:far:远截面的位置第五个参数:dest:用来保存计算结果的矩阵根据正射影生成投影坐标变换矩阵。参数是截面的上下左右,以及前后方坐标的小数点数。
>例子
// context为 500 x 300 的时候var left   = -5.0;var right  =  5.0;var top    =  3.0;var bottom = -3.0;// 截面的范围一定要设置为正数var near = 0.1;var far = 100;m.ortho(left, right, top, bottom, near, far, dmat);



qtnIV 构造器

为了处理四元数,需要把qtnIV对象实例化。
>例子
var q = new qtnIV();
※以后见到q就表示qtnIV对象的实例化。


>>create 函数
构成:quaternion qtnIV.create(void)生成四元数。实际上是一个一维的数组,包含4个元素。跟处理矩阵的matIV对象的create函数一样,数组类型是Float32Array。
>例子
var dqtn = q.create();

>>identity 函数
构成:quaternion qtnIV.identity(quaternion dest)第一个参数:dest:单位化的四元数将四元数单位化。
>例子
q.identity(dqtn);


>>inverse 函数
构成:quaternion qtnIV.inverse(quaternion qtn, quaternion dest)第一个参数:qtn:四元数的反转对象第二个参数:dest:保存结果用的四元数将四元数进行反转处理,得到共轭四元数。
>例子
q.inverse(qtn, dqtn);

>>normalize 函数
构成:quaternion qtnIV.normalize(quaternion dest)第一个参数:dest:正规化处理的四元数。四元数的正规化处理。
>例子
q.normalize(dqtn);


>>multiply 函数
构成:quaternion qtnIV.multiply(quaternion qtn1, quaternion qtn2, quaternion dest)第一个参数:qtn1:相乘的对象四元数第二个参数:qtn2:与其相乘的四元数第三个参数:dest:保存结果用的四元数四元数相乘。
>例子
q.multiply(qtn1, qtn2, dqtn);


>>rotate 函数
构成:quaternion qtnIV.rotate(float angle, vec3 axis, quaternion dest)第一个参数:angle:任意轴旋转的角度(弧度)第二个参数:axis:表示任意轴的向量第三个参数:dest:保存结果用的四元数生成一个沿着任意轴做任意角度旋转的四元数。表示任意角度的弧度是一个小数,表示任意轴的参数是一个包含三个元素的向量。
>例子
// 沿任意轴旋转45度的例子var angle = 45 * Math.PI / 180;// 任意轴向量var axis = [x, y, z];q.rotate(angle, axis, dqtn);


>>toVecIII 函数
构成:vec3 qtnIV.toVecIII(vec3 vec, quaternion qtn, vec3 dest)第一个参数:vec:坐标变换的对象向量第二个参数:qtn:进行坐标变换的四元数第三个参数:dest:保存结果用的向量三维空间中的任意一点,以及含有三个元素的向量,利用四元数进行坐标变换。
>例子
// 三维空间中的任意点var vec = [x, y, z];// 变换后的向量保存用的数组var dvec= [];q.toVecIII(vec, qtn, dvec);


>>toMatIV 函数
构成:matrix qtnIV.toMatIV(quaternion qtn, matrix dest)第一个参数:qtn:相乘的四元数第二个参数:dest:保存结果用的数组用四元数和一个4 x 4的方阵相乘。
>例子
q.toMatIV(qtn, dmat);


>>slerp 函数
构成:quaternion qtnIV.slerp(quaternion qtn1, quaternion qtn2, float time, quaternion dest)第一个参数:qtn1:四元数对象 A第二个参数:qtn2:四元数对象 B第三个参数:time:时间轴小数(0 ~ 1)第四个参数:dest:保存结果用的四元数利用两个四元数对球面进行线性补间处理,生成一个任意时间轴的四元数。参数是两个四元数和任意的时间轴,任意时间轴的取值范围是0 ~ 1,越接近0就越接近第一个四元数的旋转,越接近1就越接近第二个四元数的旋转。
>例子
q.slerp(qtn1, qtn2, time, dqtn);


>>torus 関数
构成:any torus(int row, int column, float irad, float orad [, vec4 color])第一个参数:row:トーラスを形成する輪の分割数第二个参数:column:パイプ断面の円の分割数第三个参数:irad:パイプ自体の半径を表す小数点数第四个参数:orad:原点からパイプの中心点までの距離を表す小数点数第五个参数:color:モデルに適用する色を表す四つの要素を持つ配列生成圆环体模型数据。参数分别可以指定形成圆环体的管子分割成多少份,构成这个管子的圆是多少个顶点,原点到管子中心的距离,生成这个管子的半径,圆环体的颜色。假如说参数row指定为6,那圆环体就会变成一个六角形了。参数column指定为5,那么圆环体的断面就会成为一个五角形。这个函数的第五个参数是可以省略的,省略之后,后面会由hsva函数自动计算颜色信息。如果指定颜色,需要传入一个四个元素的数组。函数的返回值是一个对象,包含5个属性,p是顶点的位置信息,n是顶点的法线信息,c是顶点的颜色信息,t是纹理坐标,i是模型的索引。※像这样返回结果的函数还有下面的sphere函数和cube函数。
>例子
var objTorus = torus(16, 16, 1.0, 2.0, [1.0, 1.0, 1.0, 1.0]);


>>sphere 関数
构成:any sphere(int row, int column, float rad [, vec4 color])第一个参数:row:球体的经度方向上的分割个数第二个参数:column:球体的纬度方向上的分割个数第三个参数:rad:球体的半径第四个参数:color:模型的颜色,是一个含有四个元素的数组生成一个球体模型数据,可以指定球体的经线和纬线的分割个数,球体的半径,以及球体的颜色。这个函数的第四个参数和torus 関数的第五个参数一样是可以省略的。而返回值也是一个特殊的对象
>例子
var objSphere = sphere(16, 16, 1.0, [1.0, 1.0, 1.0, 1.0]);


>>cube 関数
构成:any cube(float side [, vec4 color])第一个参数:side:キューブの一辺の長さを表す小数点数第二个参数:color:モデルに適用する色を表す四つの要素を持つ配列生成一个立方体模型数据,参数是立方体的变长,另外可以指定立方体的颜色。这个函数的第二个参数和torus函数的第五个参数一样,是可以省略的。而返回值也同样是一个特殊的对象。
>例子
var objCube = cube(1.0, [1.0, 1.0, 1.0, 1.0]);


>>hsva 関数
构成:any hsva(int h, float s, float v, float a)第一个参数:h:hue(色相)整数(0 ~ 360)第二个参数:s:saturation(彩度)(0 ~ 1)第三个参数:v:value(亮度)(0 ~ 1)第四个参数:a:alpha(透明度)(0 ~ 1)HSV 颜色变换为 RGB 颜色。参数中指定 HSV 颜色。HSV 中的各要素S和V,以及透明度A,范围都是 0 ~ 1 。返回值是包含四个元素的数组,另外这个函数对透明度一般不做修改。
>例子
var color = hsva(180, 1.0, 1.0, 1.0);




点击下载minMatrixb.js





欢迎继续关注我的博客

转载请注明:转自lufy_legend的博客http://blog.csdn.net/lufy_legend

原创粉丝点击