1. 程式人生 > >Qt OpenGL:學習現代3D圖形程式設計之二,玩轉色彩

Qt OpenGL:學習現代3D圖形程式設計之二,玩轉色彩

        除了給三角形賦予單一的顏色,我們還有兩種方法來改變三角形表面的顏色,一種是利用片段的位置來計算顏色,另一種是利用每個頂點的資料來計算顏色。

一、利用片段位置計算顏色

        片段的資料包括片段在螢幕上的位置,因此如果我們想要改變三角形表面的顏色,可以訪問片段著色器中的資料,並計算片段最終的顏色。gl_FragCoord是片段著色器獨有的內建變數,它是個三維向量,包含x、y、z,其中x和y表示視窗座標,z表示片段的深度值。需要注意的是,視窗座標以窗口的左下角為原點,所以三角形底部片段的y值要小於頂部片段的y值。下面這個片段著色器使得片段的顏色基於它在視窗中的y值變化。500.0f是視窗的高度,main()函式中第一行的除法將y值轉化到[0,1]範圍,此時0表示

視窗的底部,1表示視窗的頂部。第二行使用[0,1]之間的值來計算兩種顏色之間的線性混合。mix函式是OpenGL著色器語言內建的標準函式,類似mix的很多函式都是向量化的,也就是說這些函式的引數可以是向量,當這些引數為向量時,向量的維數必須相同。mix的第三個引數必須是[0,1]之間的值,當它為0時,函式返回第一個引數,當它為1時,函式返回第二個引數,否則函式返回第一個引數和第二個引數的線性混合,該混合基於第三個引數。

const std::string strFragmentShader(
    "#version 330\n"
    "out vec4 outputColor;\n"
    "void main()\n"
    "{\n"
    "   float lerpValue = gl_FragCoord.y / 500.0f;\n"
    "   outputColor = mix(vec4(1.0f, 1.0f, 1.0f, 1.0f), vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpValue);\n"
    "}\n"
);

        渲染後的效果是,當y靠近底部是,三角形接近白色;當y靠近頂部時,三角形接近黑色。如下圖所示。


參考連結:http://alfonse.bitbucket.org/oldtut/Basics/Tutorial%2002.html

原始碼連結:http://download.csdn.net/detail/caoshangpa/9473453

二、利用頂點資料計算顏色

 1.頂點屬性      

         在片段著色器中使用片段位置雖然有效,但不是控制三角形顏色的最好方法,一個更好的方法是給每個頂點賦予一個準確的顏色。下面陣列每行表示一個頂點的四維向量,因為每個float佔用四個位元組,所以每個向量佔用16個位元組。前三個向量為一組,表示三角形的三個頂點;後三個向量為另一組,表示三角形三個頂點的顏色。我們其實在記憶體中有兩個陣列,它們相互毗鄰,一個數組在記憶體中的地址為&vertexData[0],另一個數組在記憶體中的地址為&vertexData[12]。
const float vertexData[] = {
     0.0f,    0.5f, 0.0f, 1.0f,
     0.5f, -0.366f, 0.0f, 1.0f,
    -0.5f, -0.366f, 0.0f, 1.0f,
     1.0f,    0.0f, 0.0f, 1.0f,
     0.0f,    1.0f, 0.0f, 1.0f,
     0.0f,    0.0f, 1.0f, 1.0f,
};


2.頂點著色器

        這裡我們定義了一個輸出變數theColor,它用於將資料輸出頂點著色器,這是通過關鍵字out來實現的。關鍵字smooth是插值限定符。頂點著色器只執行三次,產生三個位置輸出(gl_Position)和三個顏色輸出(theColor)。這三個位置構成一個三角形,該三角形接著被光柵化,產生大量(成千上萬)片段。

const std::string strVertexShader(
    "#version 330\n"
    "layout(location = 0) in vec4 position;\n"
    "layout(location = 1) in vec4 color;\n"
    "smooth out vec4 theColor;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = position;\n"
    "   theColor = color;\n"
    "}\n"
);

下圖是頂點著色器的資料流圖。


3.片段著色器

       第二行定義了一個輸入變數theColor,它與頂點著色器中的輸出變數名字相同,這樣片段著色器就可以從頂點著色器獲取反饋資訊。片段著色器執行次數與光柵化三角形時產生的片段數有關,有多少個片段,就執行多少次。theColor只從頂點著色器獲取了三個顏色,那麼這三個顏色是如果傳遞給各個片段的呢?答案是片段插值,每個片段獲得的顏色是這三個顏色的混合,片段離三角形的哪個頂點越近,這個頂點的顏色在混合時所佔的比重就越大。smooth定義了插值的方式,其他的兩個插值限定符分別是noperspective和flat。使用smooth時,三角形表明的顏色會均勻變化;使用noperspective時,除非渲染過程複雜,否則看不出與smooth的區別;使用flat時,實際上關閉了插值,每個片段簡單的使用頂點著色器輸出的第一個顏色。需要注意的是,頂點著色器和片段著色器中相同變數的插值限定符必須相同。

const std::string strFragmentShader(
    "#version 330\n"
    "smooth in vec4 theColor;\n"
    "out vec4 outputColor;\n"
    "void main()\n"
    "{\n"
    "   outputColor = theColor;\n"
    "}\n"
);

4.顯示到螢幕

        注意與《畫一個三角形》中不同的地方。

void display()
{
    //指定OpenGL清理螢幕是將要使用的顏色,這裡為黑色。
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    //開始清理螢幕,GL_COLOR_BUFFER_BIT表示清理將影響顏色緩衝區,清理時使用上面指定的顏色。
    glClear(GL_COLOR_BUFFER_BIT);
    //告知OpenGL渲染的時候需要呼叫應用程式物件。
    glUseProgram(theProgram);
    //下面三行設定三角形的座標,它們告知OpenGL三角形在緩衝區中的頂點位置和頂點顏色。
    //獲取已經初始化的緩衝區物件。
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
    //啟用緩衝區物件中的資料,引數指定要修改的頂點屬性的索引值。在緩衝區物件中有位置和顏色兩個陣列,我們
    //必須告訴OpenGL如何取到這兩組資料。這兩組資料對應兩個頂點屬性,在頂點著色器中屬性位置是layout(location=0)
    //和layout(location=1),因此,屬性的索引值需要用glEnableVertexAttribArray函式指定兩次。
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    //儘管這個函式包含“Pointer”,但是它不處理指標,它用來對緩衝區物件中的頂點屬性進行設定。
    //引數1指定要修改的頂點屬性的索引值;引數2指定每個頂點向量的維數;引數3指定每個頂點向量的資料型別;
    //引數4指定是否歸一化;引數5指定各頂點向量間是否有空隙,0表示緊密排列;引數6指定頂點陣列起始位置與緩衝區
    //物件起始位置的偏移量,0表示無偏移。後三個引數通常取預設值。
    //48=4*4*3,48之前加(void*),是因為這個引數就是一個void指標。
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)48);
    //渲染函式,從頂點陣列索引0開始,讀取3個頂點,然後將他們連線成一個三角形。
    glDrawArrays(GL_TRIANGLES, 0, 3);
    //下面兩行是清理工作,釋放為了實現渲染所做的一些設定。
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glUseProgram(0);
}

        渲染後的效果如下圖所示。


參考連結:http://alfonse.bitbucket.org/oldtut/Basics/Tutorial%2002.html

原始碼連結:http://download.csdn.net/detail/caoshangpa/9473456