AGSL 與 GLSL 之間的差異

AGSL 和 GLSL 在語法中非常類似,可讓許多 GLSL 片段著色器影響,僅須進行極少的變更即可提供給 Android。AGSL 修正了 GLSL ES 1.0 (OpenGL ES 2.0 使用的陰影語言) 的 GLSL 功能集,盡可能擴大裝置觸及範圍。

GLSL 片段著色器可控制 GPU 在光柵器和混合硬體之間的整體行為。這個著色器會執行所有工作來計算顏色,而產生的顏色正好提供給管道的混合階段。當您在 AGSL 中編寫著色器時,您會編寫 Android 圖形管道的階段。這也有許多語言差異來自這點。

著色器執行作業

就像 GLSL 著色器一樣,AGSL 著色器會在主要函式中開始執行。 與 GLSL 不同,函式會使用「本機」座標中的著色器位置做為參數。這與 gl_FragCoord 類似,但而不是 framebuffer 座標,這些座標在呼叫著色器之前可能已轉譯。接著,著色器會以中等或高精確度的 vec4 的形式傳回像素顏色 (與 GLSL 中的 out vec4 colorgl_FragColor)。

mediump vec4 main(in vec2 fragCoord)

座標空間

GLSL 與 AGSL 座標空間

使用 GLSL 繪製著色器和使用 AGSL 繪製的相似著色器

根據預設,AGSL 和 GLSL 使用不同的座標空間。在 GLSL 中,片段座標 (fragCoord) 是相對於左下方的值。AGSL 與 Canvas 的螢幕座標系統相符,也就是說,Y 軸從左上角開始。如有需要,您可以藉由以統一的形式傳入解析度,並針對 Y 軸值使用 resolution.y - fragCoord.y,藉此在這兩個空間之間轉換。或者,您也可以將本機轉換矩陣套用至著色器。

// AGSL to GLSL coordinate space transformation matrix
val localMatrix = Matrix()
localMatrix.postScale(1.0f, -1.0f)
localMatrix.postTranslate(0.0f, viewHeight)
gridShader.setLocalMatrix(localMatrix)

精確度與類型

支援與 GLSL 相容的精確度修飾符,但 AGSL 導入 halfshort 類型,同樣代表中精確度。

向量類型可以宣告為名為 <base type><columns>。您可以使用 float2 取代 vec2bool4,而不使用 bvec4。矩陣類型可宣告為已命名的 <base type><columns>x<rows>,因此 float3x3 而非 mat3。AGSL 也允許 matvec 的 GLSL 樣式宣告,這些類型會對應至相應的浮點等項目。

預先處理器

AGSL 不支援 GLSL 樣式的預先處理器指令。將 #define 陳述式轉換為 Const 變數。AGSL 的編譯器支援常數變數的常數折疊和分支消除作業,因此能夠提高效率。

色域

Android 應用程式會以顏色管理。Canvas 的色域會決定繪圖的工作色空間。來源內容 (例如著色器,包括 BitmapShader) 也具有色域。

對於特定效果 (例如實際亮度) 而言,數學應在線性色域中完成。為協助解決這個問題,AGSL 提供下列內建函式:

half3 toLinearSrgb(half3 color)
half3 fromLinearSrgb(half3 color)

這些顏色會轉換工作色域和 Android 的 LINEAR_EXTENDED_SRGB 色域。該空間使用 sRGB 原色 (色調) 和線性傳輸函式。這會使用延伸範圍值 (低於 0.0 和 1.0 以上) 表示 sRGB 色域以外的值。

制服

由於 AGSL 不知道製服是否包含顏色,因此不會自動為它們套用顏色轉換。您可以使用 layout(color)half4/float4/vec4 加上標籤,讓 Android 瞭解系統會將統一值當做顏色使用,以便 Android 將統一值轉換為工作的顏色空間。

在 AGSL 中宣告製服,如下所示:

layout(color) uniform half4 iColor;  // Input color
uniform float2 iResolution;          // Viewport resolution (pixels)

接著,在 Android 程式碼中,您可以像這樣設定統一:

shader.setColorUniform("iColor", Color.GREEN)
shader.setFloatUniform("iResolution", canvas.width.toFloat(), canvas.height.toFloat())