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

标签: WebGL
346人阅读 评论(0) 收藏 举报
分类:

注:文章译自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

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1546143次
    • 积分:16482
    • 等级:
    • 排名:第641名
    • 原创:87篇
    • 转载:0篇
    • 译文:32篇
    • 评论:2286条
    联系我
    lufy.legend@gmail.com
    偶也微博了
    我写的书
      icon
      系统讲解HTML 5 Canvas的基础知识和高级技巧,深入剖析开源库件lufylegend的原理与使用以实例为向导,详细讲解射击游戏、物理游戏、网络游戏等各类游戏的开发思路和技巧
      qq交流群:298385345
    lufylegend.js游戏引擎官网
    博客专栏
    我开发的游戏
      三国记
    三国记是一款以三国时期为背景的战略类游戏,玩家可以任选一名君主,以统一全国为目标。
      三国记-乱世群雄
    本游戏以三国为背景,本次更新为第一部黄巾之乱的后续剧情,续作了群雄讨伐董卓,界桥之战以及救援徐州等剧情。
      三国记-经典战役版
    本游戏以三国为背景,玩家在游戏中可以体验三国中的四个经典战役,虎牢关之战,官渡之战,赤壁之战,夷陵之战。
    最新评论