three.js歐拉角和四元數(shù)的使用方法
前言
這篇郭先生就來(lái)說(shuō)說(shuō)歐拉角和四元數(shù),歐拉角和四元數(shù)的優(yōu)缺點(diǎn)是老生常談的話題了,使用條件我就不多說(shuō)了,我只說(shuō)一下使用方法。
1. 歐拉角(Euler)
歐拉角描述一個(gè)旋轉(zhuǎn)變換,通過(guò)指定軸順序和其各個(gè)軸向上的指定旋轉(zhuǎn)角度來(lái)旋轉(zhuǎn)一個(gè)物體。下面我們開看看它的方法
1. set( x: number, y: number, z: number, order?: string ): Euler
x - 用弧度表示x軸旋轉(zhuǎn)量。y - 用弧度表示y軸旋轉(zhuǎn)量。z - 用弧度表示z軸旋轉(zhuǎn)量。order - (optional) 表示旋轉(zhuǎn)順序的字符串。設(shè)置該歐拉變換的角度和旋轉(zhuǎn)順序 order。
2. clone(): this
返回一個(gè)與當(dāng)前參數(shù)相同的新歐拉角。
3. copy( euler: Euler ): this
將 euler 的屬性拷貝到當(dāng)前對(duì)象。
4. setFromRotationMatrix( m: Matrix4, order?: string ): Euler
m - Matrix4 矩陣上面的3x3部分是一個(gè)純旋轉(zhuǎn)矩陣rotation matrix (也就是不發(fā)生縮放)order - (可選參數(shù)) 表示旋轉(zhuǎn)順序的字符串。使用基于 order 順序的純旋轉(zhuǎn)矩陣來(lái)設(shè)置當(dāng)前歐拉角。
var vector = new THREE.Vector3(0,0,1); var matrix = new THREE.Matrix4().makeRotationAxis(vector, Math.PI/6) var euler = new THREE.Euler().setFromRotationMatrix(matrix); // 返回Euler {_x: -0, _y: 0, _z: 0.5235987755982987, _order: "XYZ"}
5. setFromQuaternion( q: Quaternion, order?: string ): Euler
根據(jù) order 指定的方向,使用歸一化四元數(shù)設(shè)置這個(gè)歐拉變換的角度。
var vector = new THREE.Vector3(0,0,1); var quaternion = new THREE.Quaternion().setFromAxisAngle(vector, Math.PI/6) var euler = new THREE.Euler().setFromQuaternion(quaternion);// 返回Euler {_x: -0, _y: 0, _z: 0.5235987755982987, _order: "XYZ"}結(jié)果同上
6. setFromVector3( v: Vector3, order?: string ): Euler
設(shè)置 x, y and z 并且選擇性更新 order。
var vector = new THREE.Vector3(0,0,Math.PI/6); var euler = new THREE.Euler().setFromVector3(vector);/ 返回Euler {_x: -0, _y: 0, _z: 0.5235987755982987, _order: "XYZ"}結(jié)果同上
7. reorder( newOrder: string ): Euler
通過(guò)這個(gè)歐拉角創(chuàng)建一個(gè)四元數(shù),然后用這個(gè)四元數(shù)和新順序設(shè)置這個(gè)歐拉角。
8. equals( euler: Euler ): boolean
檢查 euler 是否與當(dāng)前對(duì)象相同。
9. fromArray( xyzo: any[] ): Euler
長(zhǎng)度為3或4的一個(gè) array 。array[3] 是一個(gè)可選的 order 參數(shù)。將歐拉角的x分量設(shè)置為 array[0]。將歐拉角的x分量設(shè)置為 array[1]。將歐拉角的x分量設(shè)置為 array[2]。將array[3]設(shè)置給歐拉角的 order ??蛇x。
10. toArray( array?: number[], offset?: number ): number[]
返回一個(gè)數(shù)組:[x, y, z, order ]。
11. toVector3( optionalResult?: Vector3 ): Vector3
以 Vector3 的形式返回歐拉角的 x, y 和 z。
var vector = new THREE.Vector3(0,0,Math.PI/6); var euler = new THREE.Euler().setFromVector3(vector); euler.toVector3(); //返回Vector3 {x: 0, y: 0, z: 0.5235987755982988}
2. 四元數(shù)
四元數(shù)對(duì)象Quaternion使用x、y、z和w四個(gè)分量表示。在三維空間中一個(gè)旋轉(zhuǎn)由一個(gè)旋轉(zhuǎn)軸、一個(gè)旋轉(zhuǎn)角度和旋轉(zhuǎn)方向來(lái)唯一確定。
假設(shè)我們默認(rèn)為右手法則的旋轉(zhuǎn),則旋轉(zhuǎn)方向?yàn)槟鏁r(shí)針,旋轉(zhuǎn)軸向量為v = (vx, vy, vz), 角度為旋轉(zhuǎn)角度,那么該旋轉(zhuǎn)就應(yīng)該類似如下圖所示:
其對(duì)應(yīng)的四元數(shù)就是:
1. set( x: number, y: number, z: number, w: number ): Quaternion
設(shè)置該四元數(shù)的值。
2. clone(): this
克隆此四元數(shù)。
3. copy( q: Quaternion ): this
將q的值復(fù)制到這個(gè)四元數(shù)。
4. setFromEuler( euler: Euler ): Quaternion
用歐拉角指定的旋轉(zhuǎn)來(lái)設(shè)置此四元數(shù)。
var euler = new THREE.Euler(0,0,Math.PI/6); var quaternion = new THREE.Quaternion().setFromEuler(euler) //返回Quaternion {_x: 0, _y: 0, _z: 0.25881904510252074, _w: 0.9659258262890683}
5. setFromAxisAngle( axis: Vector3, angle: number ): Quaternion
使用由軸和角度指定的旋轉(zhuǎn)來(lái)設(shè)置此四元數(shù)。axis 應(yīng)該是歸一化的,angle 的單位是弧度。
var vector1 = new THREE.Vector3(0,0,1); var vector2 = new THREE.Vector3(0,0,2); var quaternion1 = new THREE.Quaternion().setFromAxisAngle(vector1, Math.PI/6); //返回Quaternion {_x: 0, _y: 0, _z: 0.25881904510252074, _w: 0.9659258262890683} var quaternion2 = new THREE.Quaternion().setFromAxisAngle(vector2, Math.PI/6); //返回Quaternion {_x: 0, _y: 0, _z: 0.5176380902050415, _w: 0.9659258262890683}
可見axis是否歸一化對(duì)四元數(shù)的x、y和z值的影響是線性的。
6. setFromRotationMatrix( m: Matrix4 ): Quaternion
從m的旋轉(zhuǎn)分量來(lái)設(shè)置該四元數(shù)。使用很簡(jiǎn)單就不多說(shuō)了。
7. setFromUnitVectors( vFrom: Vector3, vTo: Vector3 ): Quaternion
通過(guò)從向量vFrom到vTo所需的旋轉(zhuǎn)來(lái)設(shè)置這四元數(shù)。vFrom 和 vTo 應(yīng)該是歸一化的。我們來(lái)看一下
var vector1 = new THREE.Vector3(1,1,0); var vector2 = new THREE.Vector3(0,1,0); var quaternion = new THREE.Quaternion().setFromUnitVectors(vector1, vector2); //相當(dāng)于繞z軸旋轉(zhuǎn)了Math.PI/4
8. angleTo( q: Quaternion ): number
返回這個(gè)四元數(shù)到q的角度
var quaternion1 = new THREE.Quaternion().setFromEuler(new THREE.Euler(0,0,Math.PI/3)); var quaternion2 = new THREE.Quaternion().setFromEuler(new THREE.Euler(0,0,Math.PI/6)); quaternion1.angleTo(quaternion2); // 返回0.5235987755982987
9. rotateTowards( q: Quaternion, step: number ): Quaternion
將此四元數(shù)按給定的step旋轉(zhuǎn)到定義的四元數(shù)q。該方法確保最終四元數(shù)不會(huì)超出q。那么是什么意思呢?
var quaternion1 = new THREE.Quaternion().setFromEuler(new THREE.Euler(0,0,Math.PI/3)); //{_x: 0, _y: 0, _z: 0.49999999999999994, _w: 0.8660254037844387} var quaternion2 = new THREE.Quaternion().setFromEuler(new THREE.Euler(0,0,Math.PI/6)); //{_x: 0, _y: 0, _z: 0.25881904510252074, _w: 0.9659258262890683} quaternion1.rotateTowards( quaternion2, 0); //{_x: 0, _y: 0, _z: 0.49999999999999994, _w: 0.8660254037844387} quaternion1.rotateTowards( quaternion2, 0.5); //{_x: 0, _y: 0, _z: 0.2701980971440553, _w: 0.9628047508709812} quaternion1.rotateTowards( quaternion2, 1); //{_x: 0, _y: 0, _z: 0.25881904510252074, _w: 0.9659258262890683}
可以看出其內(nèi)部使用了quaternion.slerp()方法。當(dāng)step為0時(shí),rotateTowards方法返回就是當(dāng)前四元數(shù)。當(dāng)step為1時(shí),rotateTowards方法返回就是參數(shù)q的四元數(shù)。當(dāng)step為0~1之間時(shí),rotateTowards方法返回就是當(dāng)前四元數(shù)和參數(shù)q的四元數(shù)之間的插值。
10. inverse(): Quaternion
轉(zhuǎn)置此四元數(shù)-計(jì)算共軛。假設(shè)四元數(shù)具有單位長(zhǎng)度。
var quaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI/6,Math.PI/6,Math.PI/6)); //初始四元數(shù)Quaternion {_x: 0.30618621784789724, _y: 0.17677669529663687, _z: 0.30618621784789724, _w: 0.8838834764831845} quaternion.inverse(); //返回Quaternion {_x: -0.30618621784789724, _y: -0.17677669529663687, _z: -0.30618621784789724, _w: 0.8838834764831845}
由此可知計(jì)算共軛之后,x、y和z分別取復(fù)制,而w值不變。
11. conjugate(): Quaternion
返回此四元數(shù)的旋轉(zhuǎn)共軛。四元數(shù)的共軛。表示旋轉(zhuǎn)軸在相反方向上的同一個(gè)旋轉(zhuǎn)。經(jīng)過(guò)我的測(cè)試這個(gè)方法和inverse()方法是一樣的,來(lái)看看inverse的源碼
inverse: function () { // quaternion is assumed to have unit length return this.conjugate(); },
12. dot( v: Quaternion ): number
計(jì)算四元數(shù)v和當(dāng)前四元數(shù)的點(diǎn)積。眾所周知點(diǎn)積得到的是一個(gè)數(shù)字。很簡(jiǎn)單
13. lengthSq(): number
計(jì)算四元數(shù)的平方長(zhǎng)度。就是各個(gè)值平方求和。
14 length(): number
計(jì)算此四元數(shù)的長(zhǎng)度。也就是各個(gè)值平方求和,然后在開根號(hào)。
15. normalize(): Quaternion
歸一化該四元數(shù)。開看下源碼
normalize: function () { var l = this.length(); if ( l === 0 ) { //如果四元數(shù)參length為0,那么this._x、this._y和this._z都設(shè)置為0,this._w設(shè)置為1 this._x = 0; this._y = 0; this._z = 0; this._w = 1; } else { //如果四元數(shù)參length為l,那么四元數(shù)的各個(gè)參數(shù)乘以l的倒數(shù)。 l = 1 / l; this._x = this._x * l; this._y = this._y * l; this._z = this._z * l; this._w = this._w * l; } return this; },
16. multiply( q: Quaternion ): Quaternion
把該四元數(shù)和q相乘。具體怎么相乘。稍后再說(shuō)。
17. premultiply( q: Quaternion ): Quaternion;
使用q左乘以(pre-multiply)該四元數(shù)。同樣稍后再說(shuō)。
18. multiplyQuaternions( a: Quaternion, b: Quaternion ): Quaternion
四元數(shù)a乘以四元數(shù)b,我們說(shuō)一下四元數(shù)的乘法。
multiplyQuaternions: function ( a, b ) { var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; return this; },
19. equals( v: Quaternion ): boolean;
比較v和這個(gè)四元數(shù)的各個(gè)分量,以確定兩者是否代表同樣的旋轉(zhuǎn)。不多說(shuō)。
20. slerp( qb: Quaternion, t: number ): Quaternion
處理四元數(shù)之間的球面線性插值。t 代表quaternionA(這里t為0)和quaternionB(這里t為1)這兩個(gè)四元數(shù)之間的旋轉(zhuǎn)量。quaternion 被設(shè)置為結(jié)果。rotateTowards的底層同樣使用了slerp方法。
var quaternion1 = new THREE.Quaternion().setFromEuler(new THREE.Euler(0,0,Math.PI/6)); var quaternion2 = new THREE.Quaternion().setFromEuler(new THREE.Euler(0,0,Math.PI/2)); quaternion1; //quaternion1的值為{_x: 0, _y: 0, _z: 0.25881904510252074, _w: 0.9659258262890683} quaternion2; //quaternion2的值為{_x: 0, _y: 0, _z: 0.7071067811865475, _w: 0.7071067811865476} quaternion1.slerp(quaternion2, 0) //返回的結(jié)果和quaternion1相同 quaternion1.slerp(quaternion2, 1) //返回的結(jié)果和quaternion2相同 quaternion1.slerp(quaternion2, 其他值) //返回quaternion1到quaternion2的插值,當(dāng)然這個(gè)t也是可以大于1的 //看一下rotateTowards的部分源碼 rotateTowards: function ( q, step ) { var angle = this.angleTo( q ); if ( angle === 0 ) return this; var t = Math.min( 1, step / angle ); this.slerp( q, t ); return this; }
21. static slerp: functistatic slerp(qa: Quaternion, qb: Quaternion, qm: Quaternion, t: number): Quaternionon
這是slerp的靜態(tài)方法,無(wú)需動(dòng)態(tài)設(shè)置。同樣使用了slerp方法。
slerp: function ( qa, qb, qm, t ) { return qm.copy( qa ).slerp( qb, t ); }
關(guān)于歐拉角四元數(shù)要說(shuō)的差不多就這些,還需要平時(shí)多多應(yīng)用才能記熟。
總結(jié)
到此這篇關(guān)于three.js歐拉角和四元數(shù)的使用方法的文章就介紹到這了,更多相關(guān)three.js歐拉角和四元數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析JavaScript中break、continue和return的區(qū)別
這篇文章主要介紹了JavaScript中break、continue和return的區(qū)別,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11javascript設(shè)計(jì)模式 – 享元模式原理與用法實(shí)例分析
這篇文章主要介紹了javascript設(shè)計(jì)模式 – 享元模式,結(jié)合實(shí)例形式分析了javascript享元模式相關(guān)概念、原理、用法及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04對(duì)frameset、frame、iframe的js操作示例代碼
父框架到子框架的引用、子框架到父框架的引用、兄弟框架間的引用、不同層次框架間的互相引用具體實(shí)現(xiàn)如下,有此需求的朋友可以參考下2013-08-08動(dòng)態(tài)的9*9乘法表效果的實(shí)現(xiàn)代碼
下面小編就為大家?guī)?lái)一篇?jiǎng)討B(tài)的9*9乘法表效果的實(shí)現(xiàn)代碼。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧2016-05-05深入淺析JavaScript的API設(shè)計(jì)原則
這篇文章主要介紹了JavaScript的API設(shè)計(jì)原則,包括接口的流暢性,一致性,參數(shù)的處理,可擴(kuò)展性,對(duì)錯(cuò)誤的處理,可預(yù)見性,注釋和文檔的可讀性,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-06-06