opengl es版本: 2.0
3D引擎庫 : Rajawali3D
ShaderToy上用的shader語言 爲glsl , 效果是用webgl跑的,而webgl封裝了opengl es, 所以ShaderToy上的例子同樣使用於Android端。
ShaderToy基本上 都是用fragment shader 對柵格化後的像素進行處理。 大部分會用到紋理來豐富最終渲染結果的形狀和質地,有些也會用到聲音,鍵盤等外部輸入信息。 但是,最終都是歸結爲對柵格化區域內的每個像素進行處理,因此,我們首先來認識gl_FragCoord這個內置變量以及其與屏幕座標的關係。
gl_FragCoord根據glsl language spec的解釋爲:
它是fragment shaders的輸入變量,並持有該framgent的屏幕相對座標(x, y, z, 1/w)
什麼是屏幕相對座標,它的座標範圍是多少,這些都沒有告訴我們。需要我們實驗
假設我們採用2d ortho projection的方式來渲染,輸入的頂點信息爲屏幕的4個頂點座標,這樣我們最終渲染出來的是一個 鋪滿屏幕的圖。
由於是2D渲染,最終每個fragment的 gl_FragCoord的z接近0.0, 而w 爲1.0, 而它的x, y分量,是相對於屏幕左下角爲原點的屏幕座標。什麼意思?
假如,我們設定的viewport的渲染區域爲(0, 0, 1280, 574) 這麼大,那麼,gl_Fragment的x分量 範圍就在0~1280之間, y分量就在0~574之間。
我們可以用一下測試用例來進行測試:
vertex shader:
precision mediump float ;
uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
void main(){
position = vec3 (uMVPMatrix*aPosition);
gl_Position = uMVPMatrix*aPosition;
}
fragment shader:
precision mediump float ;
uniform vec2 screenSize; // step 1
void main()
{
vec2 uv = vec2(gl_FragCoord.xy/screenSize.xy); // step 2
//Calculate polar coordinates
float r = length(uv);
float c = 0.0;
if(uv.x>0.98 &&uv.x<1.0 ) // step 3
{
c = 1.0;
}
if(uv.y>0.98 &&uv.y<1.0 ) // step 4
{
c = 1.0;
}
//Calculate the final color mixing lines and backgrounds.
vec3 bg = mix(vec3(0.93 , 0.71 , 0.62 ), vec3(0.9 , 0.44 , 0.44), r); // step 5
bg = mix(bg, vec3 (0.9 , 0.91 , 0.62 ), c); // step 6
gl_FragColor = vec4(bg, 1.0);
}
運行後,效果圖如下:
這裏主要說下 fragment shader:
step 1: 之前說到, gl_FragCoord的座標範圍, 這裏screenSize 表示屏幕的寬高。
step 2 : 將每個fragment的 每個gl_FragCoord歸一化,這是一個慣例,利於後面計算
step3: 和 step4: 這兩個分別表示,當fragment的座標(x, y) 的x和y分量分別落在這個範圍時(即中間)c 的值會發生變化
step5: step5 和 step6都用到了glsl 的 mix內置函數, 考慮到 bg = mix(color1, color2, r)它的意思,就是將color1和color2 兩種顏色,按照bg = color1*(1-r)+r*color2的方式混合,其中bg, color1, color2都是表示顏色,有三個分量。 那麼,當r=0.0時,表示的是color1顏色,當r = 1.0表示的是color2顏色。 我們利用mix可以在一種背景上標記出另一種顏色。
step3 和 step4 表示,當x, y 分別落在值範圍的中間時,c的值從0.0變爲1.0, 即在這個範圍內,背景色變爲我們設置的顏色。
當我們把step3 和 step4 改爲:
if (uv.x>0.09 &&uv.x<0.11 )
// step 3
{
c = 1.0;
}
if (uv.y>0.09 &&uv.y<0.11 )
// step 4
{
c = 1.0;
}
效果圖如下:
通過,以上的例子我們得出gl_FragCoord的正確表示方式。