在上篇中主要作了三件事javascript
在本篇中咱們將運用推導的變換矩陣,一一驗證代碼中更新節點變換矩陣的代碼背後的邏輯。遊戲場景中的節點都成樹形的父子關係。當前節點 worldMatrix是經過父級節點對應的矩陣獲取,因此當前場景中只有一個節點時,當前節點的 worldMatrix 應該與localMatrix相同(未測試)。因此這裏就經過分析 updateLocalMatrix 來了解。java
cocos creator 中圖形變換採用標記髒數據方式告知渲染流須要更新變換矩陣。採用位運算存儲當前須要更新的變換信息。updateLocalMatrix 方法代碼行數比較長,也爲了方便分析,因此會將代碼塊拆分。如想總體瀏覽此代碼塊,請下載v2.1.3版本的cocos creator。對應的代碼在安裝文件 resourcesenginecocos2dcoreCCNode.js微信
從以下代碼就能夠論證我上邊說明的變換過程,判斷髒值,有更新無返回。判斷是否有圖形變換,有更新無返回。這裏有必要說明下位運算是如何作到存儲多值的。函數
設某選擇題存在ABC三個選項,正確選項爲AC。咱們設ABC的權值分別是 A=001 B=010 C=100 ,AC的權值 AC=A|B = 101。此時若用戶選擇 B,程序只須要將 AC & B > 0 就知道是否正確。代碼中就恰好利用這一點,在節點變換過程當中,不斷改變存在變換 localMatDirty 的值。測試
// author:herbert 公衆號:小院不小 _updateLocalMatrix() { let dirtyFlag = this._localMatDirty; if (!dirtyFlag) return; let t = this._matrix; if (dirtyFlag & (LocalDirtyFlag.RT | LocalDirtyFlag.SKEW)) { // 旋轉 縮放 傾斜 } t.m12 = this._position.x; t.m13 = this._position.y; this._localMatDirty = 0; this._worldMatDirty = true; }
代碼中(LocalDirtyFlag.RT | LocalDirtyFlag.SKEW)
LocalDirtyFlag.RT=LocalDirtyFlag.POSITION | LocalDirtyFlag.SCALE | LocalDirtyFlag.ROTATION 因此代碼中if 判斷是當前變換中是否存在 位置 、縮放 、旋轉、傾斜。雖然判斷了位置,並無放到if代碼塊中設置,也許還有其餘什麼變換致使位置變換。最後就是還原標記,以及告訴渲染流得更新worldMatrix了。this
矩陣的乘法是不知足交換律,即 AB <> BA 因此體如今代碼中就是判斷旋轉和傾斜還在設置縮放的緣由。複合變換的順序會影響最終節點的位置。此部分代碼邏輯以下spa
// author:herbert 公衆號:小院不小 if (dirtyFlag & (LocalDirtyFlag.RT | LocalDirtyFlag.SKEW)) { let rotation = -this._eulerAngles.z; let hasSkew = this._skewX || this._skewY; let sx = this._scale.x, sy = this._scale.y; if (rotation || hasSkew) { // 旋轉 傾斜 } else { t.m00 = sx; t.m01 = 0; t.m04 = 0; t.m05 = sy; } }
代碼中,沒有旋轉或傾斜信息,就只剩下縮放。那麼當前矩陣就是縮放矩陣,只須要把矩陣對角線上的值依次設置成sx sy。let rotation = -this._eulerAngles.z;
取負值是由於,rotation 順時針爲正,而後歐拉角中,逆時針爲正。取z軸旋轉角,是由於2d中旋轉軸就是z軸。code
從代碼中可知,若是存在複合變換。cocos creator 變換順序爲,旋轉->縮放->傾斜->位移。這裏有兩個須要注意地方blog
// author:herbert 公衆號:小院不小 wx:464884492 if (rotation || hasSkew) { let a = 1, b = 0, c = 0, d = 1; // rotation if (rotation) { let rotationRadians = rotation * ONE_DEGREE; c = Math.sin(rotationRadians); d = Math.cos(rotationRadians); a = d; b = -c; } // scale t.m00 = a *= sx; t.m01 = b *= sx; t.m04 = c *= sy; t.m05 = d *= sy; // skew if (hasSkew) { // 傾斜 } }
代碼中將旋轉矩陣分塊,只提取左上角的四項,得出具體的分塊矩陣A爲。A此時就應該等於選擇矩陣,即 a=cos(b) b=sin(b) c=-sin(b) d=cos(b).從上篇中咱們推導旋轉矩陣是逆時針旋轉推倒。而後代碼中rotation爲了符合使用習慣是順時針的。全部對應的旋轉矩陣應該乘以-1;遊戲
$$ A= \left[ \begin{matrix} cos(b)&-sin(b)\\ sin(b)&cos(b)\\ \end{matrix} \right] =>-1\times \left[ \begin{matrix} cos(b)&sin(b)\\ -sin(b)&cos(b)\\ \end{matrix} \right] = \left[ \begin{matrix} a&c\\ b&d\\ \end{matrix} \right] $$
因爲cos是偶函數,sin是奇函數,將-1帶入矩陣獲得
a=cos(b) b=-sin(b) c=sin(b) d=cos(b);接下來處理縮放,將縮放矩陣右乘(cocos 中複合變換矩陣,是左乘仍是右乘,沒有明確的地方說明。此處是經過代碼反推可能有誤)變化後的矩陣,以下圖所示
$$ \left[ \begin{matrix} a&c\\ b&d\\ \end{matrix} \right] = \left[ \begin{matrix} a&c\\ b&d\\ \end{matrix} \right] \times \left[ \begin{matrix} sx&0\\ 0&sy\\ \end{matrix} \right] $$
根據矩陣乘法規則(行乘列)可知
a=asx b=bsx c=csy d= dsy
傾斜實際上是兩個變換,X軸傾斜和Y軸傾斜。在上篇推導中,獲得對應變換矩陣。同上邊同樣也只取左上角的的分塊矩陣A.其中
$$ Askx=\left[ \begin{matrix} 1&tan(a)\\ 0&1\\ \end{matrix} \right], Asky=\left[ \begin{matrix} 1&0\\ tan(a)&1\\ \end{matrix} \right] $$
// author:herbert 公衆號:小院不小 wx:464884492 if (hasSkew) { let a = t.m00, b = t.m01, c = t.m04, d = t.m05; let skx = Math.tan(this._skewX * ONE_DEGREE); let sky = Math.tan(this._skewY * ONE_DEGREE); if (skx === Infinity) skx = 99999999; if (sky === Infinity) sky = 99999999; t.m00 = a + c * sky; t.m01 = b + d * sky; t.m04 = c + a * skx; t.m05 = d + b * skx; }
因爲 tan(90)趨近無窮大,當計算值爲Infinity skx 和 sky 分別作一個值限定。接下來看代碼對應的矩陣變換。首先先從y到x的順序,將Asky和Askx相乘獲得一個複合矩陣。再左乘當前變換矩陣p,爲了和前邊對照,依然採用a b c d
$$ \left[ \begin{matrix} m00&m04\\ m01&m05 \end{matrix} \right] =\left[ \begin{matrix} a&c\\ b&d \end{matrix} \right]\times\left[ \begin{matrix} 1&0\\ sky&1\\ \end{matrix} \right]\times\left[ \begin{matrix} 1&skx\\ 0&1\\ \end{matrix} \right] $$
矩陣乘法知足結合率,先將右邊的兩個矩陣相乘
$$ \left[ \begin{matrix} m00&m04\\ m01&m05 \end{matrix} \right] =\left[ \begin{matrix} a&c\\ b&d \end{matrix} \right]\times\left[ \begin{matrix} 1&skx\\ sky&1\\ \end{matrix} \right] $$
因此經過矩陣乘法規則獲得新的值
m00=a+c*sky m04=c+a*skx
m01=d+b*sky m05=d+b*skx
中篇相對於上篇,中間間隔了一個多月的時間,原創實屬不易。這期間一直在惡補圖形學和矩陣相關知識。最初分析版本2.0.10,當時代碼中存在rotationX rotationY 旋轉,當rotationX 和rotationY 不相等時,一直卡在那段代碼的分析過程當中。後來還去官方論壇提問 https://forum.cocos.com/t/top... ,沒有獲得滿意的結果,也沒多少人回覆。後來各類查資料,才發現官方將那段代碼移除了,採用歐拉角的方式。全部我將本地版本升級成v2.1.3版本。到這個版本後,又卡在了 let rotation = -this._eulerAngles.z這個負號問題。越分析越,感受欠缺的越多,歐拉角,四元數。同時感受可能寫不出中篇了,不過我仍是找了一個感受是對的推導將中篇完成了。固然其中我以爲不清楚的地方還有
歡迎感興趣的朋友關注個人微信訂閱號"小院不小",或者點擊下方的二維碼關注。我將多年開發中遇到的難點,以及一些有意思的功能,體會都會一一發布到個人訂閱號中。須要本文demo能夠在公衆號中回覆matrix
維護了一個Coscos Creator 的遊戲開發羣,歡迎喜歡聊技術的朋友加入
閒來無事,採用cocos creator開發了一個小遊戲【坦克俠】,感興趣的朋友一個能夠來玩玩