Android OpenGL ES 2.0 手把手教學(4)- 片段著色器 fragment shader

程式設計師kenney發表於2019-04-06

大家好,下面和大學一起學習如何使用片段著色器fragment shader來渲染豐富多彩的顏色,在我的github上有一個專案OpenGLES2.0SamplesForAndroid,我會不斷地編寫學習樣例,文章和程式碼同步更新,歡迎關注,連結:github.com/kenneycode/…

在上一篇文章中,我們介紹了渲染管線,下面來回顧一下fragment shader在渲染管線中的位置:

Android OpenGL ES 2.0 手把手教學(4)- 片段著色器 fragment shader

fragment shader會在光柵化後,對每個畫素執行一次,先看一下我們之前的例子中使用的fragment shader:

precision mediump float;
void main() {
    gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
}
複製程式碼

在一開始宣告瞭float的精度為中精度,接著和vertex shader一樣有一個main()方法作為入口,fragment shader中有一個內建變數gl_FragColor表示fragment shader的輸出,在之前的例子我們給gl_FragColor設定了一個固定值vec4(0.0, 0.0, 1.0, 1.0),這是一個RGBA的顏色值,因此我們之前看到的三角形是一個純藍色的,現在,我們來實現一個彩色的三角形,這需要vertex shaderfragment shader同時修改,來看看我們修改後的shader

// vertex shader
precision mediump float;
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main() {
    v_Color = a_Color;
    gl_Position = a_Position;
}
複製程式碼
// fragment shader
precision mediump float;
varying vec4 v_Color;
void main() {
    gl_FragColor = v_Color;
}
複製程式碼

修改後,gl_FragColor不再是一個固定值,而是一個型別為varying的顏色值v_Colorvarying型別變數是一種經過插值後得到的變數,我們可以看到vertex shader中也宣告瞭同樣的varying vec4 v_Color,然後將a_Color賦給v_Colorfragment shader中的v_Color就是通過vertex shader傳遞過來的,而a_Colora_Position一樣是attribute型別。

上篇文章提到過,vertex shader會對每個頂點都執行一次,而fragment shader會對每個畫素執行一次,那麼fragment shader中拿到的v_Color究竟是什麼值?它是經過插值的值,這個如何理解呢?先來看一下我們這個例子中傳遞的值:

// 顏色資料
// The color data
private val colorData = floatArrayOf(
                                    1.0f, 0.0f, 0.0f, 1.0f,
                                    0.0f, 1.0f, 0.0f, 1.0f,
                                    0.0f, 0.0f, 1.0f, 1.0f)
// 每個顏色的成份數(RGBA)
// The num of components of per color(RGBA)
private val COLOR_COMPONENT_COUNT = 4
    
// 將三角形頂點資料放入buffer中
// Put the triangle vertex data into the buffer
val colorDataBuffer = ByteBuffer.allocateDirect(colorData.size * java.lang.Float.SIZE)
    .order(ByteOrder.nativeOrder())
    .asFloatBuffer()
colorDataBuffer.put(colorData)
colorDataBuffer.position(0)

// 獲取欄位a_Color在shader中的位置
// Get the location of a_Color in the shader
val aColorLocation = GLES20.glGetAttribLocation(programId, "a_Color")

// 啟動對應位置的引數
// Enable the parameter of the location
GLES20.glEnableVertexAttribArray(aColorLocation)

// 指定a_Color所使用的頂點資料
// Specify the vertex data of a_Color
GLES20.glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false,0, colorDataBuffer)
複製程式碼

我們以與傳遞三角形頂點給a_Position相同的方式,將三個顏色值(1.0f, 0.0f, 0.0f, 1.0f)(0.0f, 1.0f, 0.0f, 1.0f)(0.0f, 0.0f, 1.0f, 1.0f)傳遞給a_Color,這時在vertex shader執行時會同時取到頂點和顏色資料的同一位置的資料,將這三個顏色值傳遞給v_Color後,在fragment shader中的v_Color就是經過這三個顏色值插值後的值,例如越靠近顏色(1.0f, 0.0f, 0.0f, 1.0f)對應的點的地方,顏色就越接近(1.0f, 0.0f, 0.0f, 1.0f),我們來看下效果:

Android OpenGL ES 2.0 手把手教學(4)- 片段著色器 fragment shader

程式碼在我github的OpenGLES2.0SamplesForAndroid專案中,本文對應的是SampleFragmentShader,專案連結:github.com/kenneycode/…

感謝閱讀!

相關文章