GBA除了能夠依照Map memory的排列,由左至右、由上到下的產生畫面外,還能夠使用矩陣運算,產生縮放&旋轉過後的背景圖案,本文將會描述其原理,並且這部分的知識將與Affine object共通
仿射矩陣
根據維基百科的對仿射變換的定義: ::: success 仿射轉換(Affine transformation),又稱仿射映射,是指在幾何中,對一個向量空間進行一次線性轉換並接上一個平移,轉換為另一個向量空間。 ::: 言下之意,對於GBA的2D顯示來說,我們會需要一個矩陣
來幫我們做這個轉換,這個矩陣會長得像是這樣,讓我們假設我們要逆時鐘旋轉 然後X軸縮放 倍,Y軸縮放 倍,最後平移(x, y),讓我們先來討論線性轉換的部分(旋轉與縮放) 這個矩陣其實就是由一個旋轉矩陣跟一個縮放矩陣組合而成
忘記怎麼計算矩陣了嗎? 請參考Matrix calculation rules
逆矩陣
- 酷,所以GBA的圖形硬體就是用上面的方式來實現旋轉縮放的囉?
- 很遺憾並不是,正確來說是完全相反
- 字面上意思的相反
- 我們剛剛所提及的方式,是將VRAM中的tile旋轉並縮放後,投射到螢幕上,但你仔細想想就會發現不太可行
- 我們可以思考一個問題,你放大之後,8*8的tile變成16*16,中間的插值是不是需要另外處理?
- 所以GBA的作法是將螢幕座標乘上仿射矩陣的逆矩陣,反著映射回VRAM,這下就保證每一個pixel都會有屬於它的data了
- 可想而知的,只要一轉下去,品質一定糟糕到受不了,不過GBA嘛......你也不能要求太多
- 很遺憾並不是,正確來說是完全相反
- 因為上面的矩陣沒有平移(平移不是線性轉換),所以可逆
實際上的渲染流程
- 我們的渲染流程並不難,先讓我們來看一下幾個重要的register
- 由於能支援仿射功能的圖層有兩個(BG2、BG3),所以以下的register都會是兩組
1.BGX_L, BGX_H, BGY_L, BGY_H
- 用來定義texture space的起始點(Starting point),因為格式不是integer而是fixed-point,因此長度會比較長,需要分兩塊來存 2.BGX_PA, BGX_PD, BGX_PC, BGX_PD
- 用來描述我們的仿設反矩陣
- 由於能支援仿射功能的圖層有兩個(BG2、BG3),所以以下的register都會是兩組
1.BGX_L, BGX_H, BGY_L, BGY_H
Starting point是Q8格式的fixed-point,即[0:7]是小數部分,[8:26]是整數部分,[27]是sign bit
PA、PB、PC、PD是Q8格式的fixed-point,即[0:7]是小數部分,[8:14]是整數部分,[15]是sign bit
- 基本上運算規則如下
- BG_X與BG_Y就是仿射矩陣的平移部份了
- 就是這麼的樸實無華 且枯燥,用圖來看會像是這樣
- 我們之前有提到過在Affine BG下,map data都是1
byte,在這個狀態下只要把
跟 除8,就可以得到map data的address了 - 順帶附上fixed-point乘法的程式碼
1
2
3
4
5
6
7
8int q_mul(int32_t a, int16_t b) {
int32_t temp;
temp = (int32_t)a * (int32_t)b; // result type is operand's type
// Rounding; mid values are rounded up
temp += (temp >> 7) & 1;
return temp >> 8;
}