前面已經瞭解了一些Stage3D的基礎與工作原理,今天我準備繼續深入瞭解下隱藏於Stage3D API背後的神秘代碼 AGAL。
廢話不多說直接進入主題,老規矩先搞清楚什麼是AGAL? AGAL是幹什麼的?
AGAL(Adobe Graphics Assembly Language)是Adobe開發的圖形組合語言,組合語言是僅高於電腦二進位機器碼的低級語言,可以精確地操控機器硬體比如可程式化顯卡,PC的Dirext9、MAC的OpenGL以及行動裝置中的OpenGL ES 2都是可程式化顯卡,並且都支援AGAL。通過Adobe官方提供的編譯器AGALMiniAssembler(實際上是一個AS類庫),我們可以通過字串指令來獲得一個AGAL二進位流,再通過context3D上傳給顯卡的編程管線。對於頂點以及片段的運算都是通過AGAL交由顯卡來處理的,這就是傳說中的GPU硬體加速。),最新的測試版flash player 11中提供了可調用顯卡資源來渲染圖形API.這個百度裡以及很詳細了,有興趣可以去瞭解下 http://baike.baidu.com/view/6423021.htm
AGAL代碼結構 <opcode> <destination> <source1> <source2> <作業碼> <目標> <來源1> <來源2或範例> opcode:表示執行什麼指令或函數,而這個指令或者函數被稱作“作業碼”。 destination:表示運算的結果要去的“目的地”。 source1與source2:資料來源的位置。 例: mov v0, v1 表示將存於 va1 中的值複製到 v0。 AGAL有大約30種不同的作業碼。完整的作業碼列表如下:
名稱 描述 說明
mov 移動 移動 source1 資料到 destination
add 相加 destination = source1 + source2
sub 相減 destination = source1 - source2
mul 相乘 destination = source1 * source2
div 相除 destination = source1 / source2
rcp 倒數 destination = 1 / source1
min 最小值 destination = minimum(source1 , source2)
max 最大值 destination = minimum(source1 , source2)
frc 取小數 destination = source1 - (float) floor(source1)
sqt 平方根 destination = sqrt(source1)
rsq 平方根倒數 destination = 1 / sqrt(source1)
pow 指數 destination = pow(source1 , source2)
log 2 為底的對數 destination = log_2(source1)
exp 2 為底的指數 destination = 2^source1
nrm 標準化 destination = normalize(source1)
sin 正弦 destination = sin(source1)
cos 餘弦 destination = cos(source1)
abs 絕對值 destination = abs(source1)
neg 負值 destination = -source1
sat 飽和值 destination = maximum(minimum(source1 , 1) , 0)
kil 拋棄(只限片斷著色器) 假如單一分量小於 0 便放棄繪圖
tex 材質取樣(只限片斷著色器) 依據 source1 座標從 source2 材質取樣
sge 分量運算(set-if-greater-equal) destination = source1 >= source2 1 : 0
slt 分量運算(set-if-less-than) destination = source1 < source2 1 : 0
crs 向量外積(cross product) destination.x = source1.y * source2.z - source1.z * source2.y destination.y = source1.z * source2.x - source1.x * source2.z destination.z = source1.x * source2.y - source1.y * source2.x
dp3 向量內積(dot product) destination = source1.x * source2.x + source1.y * source2.y + source1.z * source2.z
dp4 向量內積(dot product) destination = source1.x * source2.x + source1.y * source2.y + source1.z * source2.z + source1.w * source2.w
m33 3x3 矩陣相乘 destination.x = (source1.x * source2[0].x) + (source1.y * source2[0].y) + (source1.z * source2[0].z) destination.y = (source1.x * source2[1].x) + (source1.y * source2[1].y) + (source1.z * source2[1].z) destination.z = (source1.x * source2[2].x) + (source1.y * source2[2].y) + (source1.z * source2[2].z)
m44 4x4 矩陣相乘 destination.x = (source1.x * source2[0].x) + (source1.y * source2[0].y) + (source1.z * source2[0].z) + (source1.w * source2[0].w) destination.y = (source1.x * source2[1].x) + (source1.y * source2[1].y) + (source1.z * source2[1].z) + (source1.w * source2[1].w) destination.z = (source1.x * source2[2].x) + (source1.y * source2[2].y) + (source1.z * source2[2].z) + (source1.w * source2[2].w) destination.w = (source1.x * source2[3].x) + (source1.y * source2[3].y) + (source1.z * source2[3].z) + (source1.w * source2[3].w)
m34 3x4 矩陣相乘 destination.x = (source1.x * source2[0].x) + (source1.y * source2[0].y) + (source1.z * source2[0].z) + (source1.w * source2[0].w) destination.y = (source1.x * source2[1].x) + (source1.y * source2[1].y) + (source1.z * source2[1].z) + (source1.w * source2[1].w) destination.z = (source1.x * source2[2].x) + (source1.y * source2[2].y) + (source1.z * source2[2].z) + (source1.w * source2[2].w)
ifz, inz, ife, ine, ifg, ifl, ieg, iel, els, eif, rep, erp, brk, sgn 從AGALMiniAssembler裡面看到還有這些opcode ifz, inz, ife, ine, ifg, ifl, ieg, iel, els, eif, rep, erp, brk, sgn 不過實際測試發現在目前這版 Flash Player 尚未支援
AGAL Registers 緩衝器
緩衝器 定義 許可權
頂點著色器 片斷著色器 AS3編譯器
vc0 - vc127 頂點矩陣常量 讀 寫
va0 - va7 頂點緩衝屬性 讀 寫
vt0 - vt7 頂點臨時變數 讀/寫
op 頂點著色器最終輸出的對象 寫
v0 - v7 變數 寫 讀
fc0 - fc27 片斷常量 讀 寫
ft0 - ft7 片斷臨時變數 讀/寫
fs0 - fs7 片斷紋理採樣器 讀/寫
oc 片斷著色器最終輸出的對象 寫
什麼是寄存器:
<destination>、<source1>與 <source2> 都被稱為“寄存器”。也以把它理解成 AS3中的變數,它是用來儲存資料的地方。它們各自指向一小塊顯存,由於進行過最佳化,因此訪問速度非常快。為了達到最快的速度,AGAL所提供的寄存器是有數量限制的。當你開始編寫那些更為複雜的著色器時,你就會經常把它們用光,而不得不提出創出新的方法就是重用寄存器。 從String到Vector3D再到Bitmap,AS3變數有著各種各樣的資料格式。但與此相反,寄存器全部都是128bit的容量,並且包含有4個浮點數。這4個值又被稱為4個分量。可以通過使用x,y,z,w或者r,g,b,a來單獨訪問一個分量。每個作業碼都是按“分量形式”的方式執行指令。這意味著它們會按順序,把寄存器分量一個一個的分別加到一起。 例:add va0, va1; 這句指令執行了add 作業碼,顯卡就會把 va0.x和va1.x相加,然後是 va0.y 和 va1.y,va0.z 和 va1.z,最後是 va0.w 和 va1.w。 假設 va0 = (20,50,10,0); va1 = (50,5,0,1); 則執行add指令結果 = (70,55,10,1)
Attribute Registers 屬性寄存器
這些寄存器涉及頂點著色器的輸入VertexBuffer。因此,他們只可用在頂點著色器。
為了指派一個VertexBuffer到指定的屬性寄存器,在這個函數中使用正確的索引號Context3D::setVertexBufferAt()。
從著色器中訪問該屬性寄存器的文法:va<n>,其中<n>是屬性寄存器的索引號。
總共有8個用於頂點著色器的屬性寄存器。
Constant Registers 常量寄存器
這些寄存器是為了從ActionScript傳遞參數到著色器。通過Context3D::setProgramConstants()函數完成。
從著色器中訪問這些寄存器的文法:vc<n>,用於頂點著色器,fc<n>,用於像素著色器,其中<n>是常量寄存器的索引號。
有128個用於頂點著色器和28個用於像素著色器的常量寄存器。Temporary Registers 臨時寄存器
這些寄存器供著色器在臨時計算時使用。
訪問它們的文法:vt<n>(點)和 ft<n> (像素),其中<n>是寄存器的序號。
有8個可用於頂點著色器,8個可用於像素著色器。Output Registers 輸出寄存器
輸出寄存器儲存頂點和像素著色器的計算輸出。對於頂點著色器是一個頂點剪輯空間的位置。對於像素著色器是該像素的顏色。
訪問這些寄存器的文法:op,用於頂點著色器,oc,用於像素著色器。
顯然只有一個用於頂點和像素著色器的輸出寄存器。 Varying Registers 變數寄存器
這些寄存器用來從頂點著色器向像素著色器傳遞資料。
這些寄存器用來傳遞從頂點著色器到像素著色器的資料。所傳資料被GPU轉換,從而使像素著色器接收到正確的值,用於正在處理的像素。
用這種方法傳遞的典型資料是頂點的顏色或紋理的UV座標。
訪問這些寄存器的文法:v<n>,其中<n>是寄存器序號。
有8個變數寄存器可用。
Texture Samplers 紋理採樣寄存器
紋理採樣寄存器是用來接收從基於UV座標系的紋理中的顏色值。
紋理的指定通過ActionScript使用方法 Context3D::setTextureAt()。
紋理採樣的使用文法是:ft<n> <flags>,其中<n>是採樣序號,<flags>是一個或多個用於指定應如何取樣的標誌集。
<flags>是一個以逗號分隔的字串集,其定義是:
紋理維度。可以是:2d, 3d, cube
多重材質映射。可以是:nomip, mipnone, mipnearest, mipnone
紋理濾鏡。可以是:nearest, linear
重複紋理。可以是:repeat, wrap, clamp.
好了,舉例來說,一個標準的沒有多重材質映射的2D紋理,進行線性濾鏡採樣到臨時寄存器ft1中,用下行:
“tex ft1, v0, fs0 <2d,linear,nomip> “
其中變數寄存器v0儲存以插入值替換的紋理UV座標。
頂點和像素著色器例子解釋
現在我們返回到著色器的例子,並解釋其運作。
我們假設頂點在VertexBuffer中包含著頂點的位置,位移量是0,紋理的UV位移量是3。
我們希望我們的頂點著色器轉換頂點位置到剪輯空間裡,並傳遞UV到像素著色器。
執行以下代碼:
m44 op, va0, vc0 // pos to clipspace
mov v0, va1 // copy uv第一行執行了在輸入頂點,va0,和從模型空間到剪輯空間的變換矩陣之間的4×4矩陣乘法,我們假定已從ActionScript寫入到常量寄存器0中,vc0。
用下面的方法可將此矩陣寫入到著色器:Context3D::setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, matrix, true );著色器的第二行,複製頂點UV資料到變數寄存器0,V0,因此,它可以獲得修正,並傳遞到像素著色器。
像素著色器採樣紋理,並複製顏色到輸出寄存器。tex ft1, v0, fs0 <2d,linear,nomip>
mov oc, ft1好了,這個頂點/像素著色器剛剛將3D 模型轉換到二維螢幕上,並進行了紋理映射。
這就是我們的第一個頂點和像素著色器!