着色器的一些歸納總結

最近在學習OpenGL,把學習的一些過程寫在這裏,希望與大家共同分享討論。歡迎光臨我的個人網站Orient一起討論學習。這裏是我的GitHub,如果您喜歡,不妨點個贊?☺

着色器(shaders)

結構(structure)

#version version_number
in type in_variable_name;
in type in_variable_name;

out type out_variable_name;

uniform type uniform_name;

int main()
{
    // 處理輸入並進行一些圖形操作
    ...
    // 輸出處理的結果到輸出變量
    out_variable_name = weird_stuff_we_processed;
}

查詢頂點屬性上限

查詢 GL_MAX_VERTEX_ATTRIBS 獲取能申明的頂點屬性上限(一般由硬件決定,OpenGL確保至少有16個包含4分量的頂點屬性可用)

unsigned int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximun nr of vertex attributes supported:" << nrAttributes << std::endl;

vector(大多時候我們使用vecn,float足夠滿足大多數要求)

vecn:包含n個float分量的默認向量
bvecn:包含n個bool分量的向量
ivecn:包含n個int 分量的向量
uvecn:包含n個unsigned int分量的向量
dvecn:包含n個double分量的向量

分量獲取

向量的分量可通過vec.x這種方式獲取,vec.xvec.yvec.zvec.w獲取第1、2、3、4個分量。GLSL也允許對顏色使用rgba,或是對紋理座標使用stpq訪問相同的分量

向量重組(Swizzling)

vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy
vec2 vect = vec2(0.5, 0.7);
vec4 result = vec4(vect, 0.0, 0.0);
vec4 otherResult = vec4(result.xyz, 1.0);

輸入與輸出

GLSL定義了inout關鍵字來實現着色器的輸入輸出,只要一個輸出變量與下一個着色器階段的輸入匹配,它就會傳遞下棋,但在頂點和片段着色器中會有點不同

頂點着色器的輸入特殊在它從頂點數據中直接接收輸入。爲了定義定點數據該如何管理,使用location這一元數據指定輸入變量,這樣就可以在CPU上配置頂點屬性。頂點着色器需要爲它的輸入提供一個額外的layout標識,這樣才能把它鏈接到頂點數據。

改動程序中的着色器

頂點着色器:

#version 410 core
layout (location = 0) in vec3 aPos; // 位置變量的屬性值爲0

out vec4 vertexColor;   // 爲片段着色器指定一個顏色輸出

void main()
{
    gl_Position = vec4(aPos, 1.0);  // 注意,這裏把一個vec3作爲vec4的構造器參數
    vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // 把輸出變量設置爲暗紅色
}

片段着色器:

#version 410 core
out vec4 FragColor;

in vec4 vertexColor;    // 從頂點着色器傳來的輸入變量(名稱、類型相同)

void main()
{
    FragColor = vertexColor;
}

這樣完成了從頂點着色器向片段着色器發送數據,改變了三角形的顏色

Uniform

Uniform是一種從CPU中的應用向GPU中的着色器發送數據的方式,但它和定點屬性有些不同。

1、Uniform是全局的,Uniform變量必須在每個着色器程序對象中都是獨一無二的,而且它可以被着色器程序的任意着色器在任意階段訪問。
2、無論把Uniform值設置成什麼,它會一直保存它們的數據,直到它們被重置或更新。

在一個着色器中添加Uniform關鍵字至類型和變量名前來生命一個GLSL的Uniform。

#version 410 core
out vec4 FragColor;

uniform vec4 ourColor;  // 在OpenGL程序代碼中設定這個變量

void main()
{
    FragColor = ourColor;
}

如果申明瞭一個uniform卻在GLSL代碼中沒用過,編譯器會靜默移除這個變量,導致最後編譯出的版本中不會包含它,這可能導致幾個非常麻煩的錯誤!

接下來給uniform添加數據,使得三角形顏色隨時間而改變

// 獲取運行的秒數
float timeValue = glfwGetTime();
// sin函數(引入cmath)讓顏色在0.0到1.0之間改變
float greenValue = sin(timeValue) / 2.0f + 0.5f;
// 查詢uniform ourColor的位置值,如果返回-1則表示沒有找到這個位置值
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
glUseProgram(shaderProgram);
// 設置uniform值。
glad_glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

注意,查詢uniform地址不要求你之前使用過的着色器程序,但更新一個uniform之前必須先使用程序(調用glUseProgram),因爲它是在當前激活的着色器中設置uniform的

因爲OpenGL其核心是一個C庫,所以它不支持類型重載,在函數參數不同的時候就要爲其定義新的函數;glUniform就是一個典型的例子:

後綴  含義
f    函數需要一個float作爲它的值
i    函數需要一個int作爲它的值
ui   函數需要一個unsigned int作爲它的值
3f   函數需要3float作爲它的值
fv   函數需要一個float向量/數組作爲它的值

本文的代碼可在這裏找到,如果對您有所幫助,不妨點個贊。☺

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章