最近在學習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.x
、vec.y
、vec.z
、vec.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定義了in
和out
關鍵字來實現着色器的輸入輸出,只要一個輸出變量與下一個着色器階段的輸入匹配,它就會傳遞下棋,但在頂點和片段着色器中會有點不同
頂點着色器的輸入特殊在它從頂點數據中直接接收輸入。爲了定義定點數據該如何管理,使用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 函數需要3個float作爲它的值
fv 函數需要一個float向量/數組作爲它的值
本文的代碼可在這裏找到,如果對您有所幫助,不妨點個贊。☺