bilibili視頻鏈接:
【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p=5&vd_source=44b77bde056381262ee55e448b9b1973
函數網站:
docs.gl
說明:
1.之后就不再整理具體函數了,網站直接翻譯會更直觀也會有更多注意點。直接通過csdn索引查找反而會慢。
2.代碼區域會單獨注釋功能參數返回值和相關注意事項。
3.課程學習從4-本節,如果有些函數沒有注釋可以看專欄里面的前面發表的文章,一般會有解釋。
4.如果覺得代碼注釋白色字體不太直觀可以直接copy到相應軟件看。
5.有兩種版本的可供查看:注釋全面的和值注釋功能的簡潔版的,可以在索引里面找到相關代碼查看。
6.希望能幫到你。
7.有錯誤請跟我說明一下,可能整理的時候沒有檢查好。
一、知識點整理
1.1著色器程序
1.1.1 解釋
- 功能:創建著色器程序
- 參數:頂點著色器代碼、片段著色器代碼
1.1.2過程
連接兩個著色器到單獨著色器程序,并返回唯一標識符,所以可以綁定一個頂點著色器,用頂點緩沖獲得一個返回id并在glGenBuffers里面去訪問。
1.1.3 程序
static unsigned int CompilesShader(unsigned int type, const std::string& source)
//功能:編譯著色器代碼
//參數:1.type表示著色器類型,GL_VERTEX_SHADER表示頂點著色器,GL_FRAGMENT_SHADER表示片段著色器
//2.source表示著色器源代碼的字符串
//返回值:編譯成功的著色器對象ID,失敗則返回0
static unsigned int CompilesShader(unsigned int type, const std::string& source)
{//功能:創建著色器對象//參數:1.type表示著色器類型,GL_VERTEX_SHADER表示頂點著色器,GL_FRAGMENT_SHADER表示片段著色器//返回值:著色器對象IDunsigned int id = glCreateShader(type);//功能:設置著色器源代碼.//通過傳遞的字符串指針,將源代碼復制到著色器對象中//注意:這里的src指針必須指向以null結尾的字符串,否則會導致編譯錯誤//c_str()函數可以將std::string轉換為const char*類型//也可const char* src = &source[0];const char* src = source.c_str();//功能:替換著色器對象中的源代碼。將該id的指定著色器的源代碼設置為src指針指向的字符串//參數:1.id表示著色器對象ID//2.1表示著色器源代碼的數量//3.src指針表示著色器源代碼的字符串指針//4.nullptr表示長度為0的字符串指針glShaderSource(id, 1, &src, nullptr);//功能:編譯著色器對象的源代碼//參數:1.id表示著色器對象IDglCompileShader(id);//設置返回著色器的對象ID//這里不能寫成unsigned,會報錯——// "unsigned int *" 類型的實參與 "GLint *" (aka "int *") 類型的形參不兼容int result;//功能:從著色器對象返回一個參數,表示編譯是否成功。//參數:1.id表示著色器對象ID//2.GL_COMPILE_STATUS表示對象的參數//3.result指針表示編譯成功/請求的對象參數值glGetShaderiv(id, GL_COMPILE_STATUS, &result);//如果編譯失敗,則輸出錯誤信息if (result == GL_FALSE){int length;//功能:獲取編譯錯誤信息的長度glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);//分配內存,用于存儲編譯錯誤信息//alloca()函數用于分配堆棧內存,避免堆內存碎片化//alloca和new的區別:alloca分配的內存不會被自動釋放,而new分配的內存會被自動釋放//alloca和malloc的區別:alloca分配的內存大小必須是編譯器確定的,而malloc分配的內存大小可以由用戶指定char* message = (char*)alloca(length*sizeof(char));//功能:獲取編譯錯誤信息//參數:1.id表示著色器對象ID//2.length表示編譯錯誤信息的長度,指定用于存儲返回的信息日志的字符緩沖區大小。//3.length指針表示實際獲取的編譯錯誤信息的長度,返回在infoLog中返回的字符串長度(不包括終止符)。//4.message指針表示編譯錯誤信息的字符串指針glGetShaderInfoLog(id, length, &length, message);std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;std::cout << message << std::endl;//刪除著色器對象glDeleteShader(id);return 0;}//TODO:錯誤處理ingreturn id;
}
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
//功能:創建著色器程序
//將頂點著色器和片段著色器的代碼連接(作為字符串)編譯為一個程序對象,并返回程序對象
//參數:頂點著色器代碼、片段著色器代碼
//返回值:著色器程序對象的ID
//定義為靜態函數:
// 靜態函數可以使函數的可見性降低,僅限于被定義的文件內部使用。
// 這有助于封裝代碼,使得其他文件無法直接調用這個函數。
// 可以避免命名沖突
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{//創建程序對象//返回:程序對象ID。創建的程序對象是一個ID值,用于標識一個OpenGL程序對象unsigned int program = glCreateProgram();//編譯頂點著色器對象//參數:1.GL_VERTEX_SHADER表示創建頂點著色器對象//2.vertexShader.c_str()表示頂點著色器源代碼的字符串指針//返回值:編譯成功的著色器對象IDunsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);//編譯片段著色器對象//參數:1.GL_FRAGMENT_SHADER表示創建片段著色器對象//2.fragmentShader.c_str()表示片段著色器源代碼的字符串指針//返回值:編譯成功的著色器對象IDunsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);//功能:將編譯好的著色器對象附加到程序對象中//參數:1.program表示程序對象ID//2.vs表示頂點著色器對象ID//3.fs表示片段著色器對象IDglAttachShader(program, vs);glAttachShader(program, fs);//功能:鏈接程序對象//實際上鏈接是通過把所有著色器對象中的代碼合并到一個程序對象中,然后編譯這個程序對象來實現的。//參數:1.program表示程序對象IDglLinkProgram(program);//功能:驗證著色器程序對象是否可以在當前OpenGL狀態中執行。檢查著色器程序的完整性和可執行性。//如果驗證失敗,OpenGL會設置一個錯誤標志,可以通過glGetProgramiv函數查詢驗證結果和錯誤信息。//驗證過程生成的信息將存儲在 program 的信息日志中。// 驗證信息可能是一個空字符串,或者是一個包含當前程序對象與當前OpenGL狀態其余部分如何交互的信息的字符串。// 驗證操作的狀態將作為程序對象狀態的一部分被存儲。// 如果驗證成功,此值將被設置為GL_TRUE,否則將被設置為GL_FALSE。//可以通過調用glGetProgram并傳入參數program和GL_VALIDATE_STATUS來查詢。glValidateProgram(program);//刪除著色器對象,因為它們已經被鏈接到程序對象中glDeleteShader(vs);glDeleteShader(fs);//返回著色器程序return program;
}
int main增加代碼
//準備著色器代碼//core表示使用的是核心配置文件,它移除了舊版本中一些過時的OpenGL函數和功能,使得代碼更加清晰和高效。//layout(location = 0) : 這是一個布局限定符(layout qualifier)// 用于指定輸入變量在著色器程序中的位置索引。//in vec4 position; : 這是一個輸入變量聲明。// in關鍵字表示該變量是輸入到頂點著色器的,// vec4表示數據類型為4維浮點數向量(vec4),// position是變量的名稱。// 這行代碼的意思是頂點著色器接收一個4維浮點數向量的輸入,變量名是position,用于表示頂點的位置。// 實際應用中,通常只使用前三個分量(x, y, z)來表示頂點的位置,第四個分量(w)用于透視除法等操作。//void main(): 這是頂點著色器的主函數聲明。每個頂點著色器程序都必須有一個名為main的函數。//gl_Position = position;將輸入的頂點位置position賦值給gl_Position。// gl_Position是OpenGL內置的變量,用于存儲頂點在裁剪空間中的位置。//在這個簡單的例子中,頂點著色器不做任何額外的處理,只是將輸入的頂點位置直接輸出到裁剪空間。// 這意味著頂點的位置不會被變換,而是直接基于裁剪空間的坐標系來繪制。std::string vertexShader ="#version 330 core\n""\n""layout (location = 0) in vec4 position;\n""void main()\n""{\n"" gl_Position = position;\n""}\n";//vec4 是 GLSL(OpenGL Shading Language)中的一個內置類型,表示一個包含四個浮點數的向量。// 這四個浮點數通常用于表示顏色的 RGBA 值,即紅(R)、綠(G)、藍(B)和透明度(A)。//color 是片段著色器中的一個輸出變量。用于設置最終輸出到屏幕上的顏色。std::string fragmentShader ="#version 330 core\n""\n""layout (location = 0) out vec4 color;\n""void main()\n""{\n"" color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n""}\n";//創建著色器程序unsigned int shader = CreateShader(vertexShader, fragmentShader);//使用著色器程序glUseProgram(shader);
1.2 glCreateProgram
1.2.1c規范
1.2.2功能
創建程序對象
1.2.3實例
unsigned int program = glCreateProgram();
1.2.4描述
創建一個空的程序對象并返回一個非零值,通過該值可以引用它。程序對象是一個可以附加著色器對象的對象。這提供了一種指定將要鏈接以創建程序的著色器對象的機制。它還提供了一種檢查將用于創建程序的著色器兼容性的方法(例如,檢查頂點著色器和片段著色器之間的兼容性)。當不再作為程序對象的一部分所需時,著色器對象可以被分離。
通過成功地使用glAttachShader將著色器對象附加到程序對象上,成功地使用glCompileShader編譯著色器對象,并成功地使用glLinkProgram鏈接程序對象,可以在程序對象中創建一個或多個可執行文件。當調用glUseProgram時,這些可執行文件將被加入到當前狀態中。程序對象可以通過調用glDeleteProgram來刪除。當程序對象不再屬于任何上下文的當前渲染狀態時,與程序對象相關的內存將被刪除。
像顯示列表和紋理對象一樣,程序對象的命名空間也可以在一組上下文中共享,只要這些上下文的服務器端共享相同的地址空間。如果命名空間在上下文中共享,任何附加的對象及其相關數據也會被共享。
如果在創建程序對象時發生錯誤,此函數將返回0。
1.3glCreateShader
1.3.1c規范
1.3.2功能
創建著色器對象
1.3.3描述
創建一個空的著色器對象并返回一個非零值,通過該值可以引用它。著色器對象用于維護定義著色器的源代碼字符串。shaderType 指示要創建的著色器類型。支持兩種類型的著色器。類型為 GL_VERTEX_SHADER 的著色器是旨在在可編程頂點處理器上運行的著色器。類型為 GL_FRAGMENT_SHADER 的著色器是旨在在可編程片段處理器上運行的著色器。 當創建著色器對象時,其GL_SHADER_TYPE參數設置為GL_VERTEX_SHADER或GL_FRAGMENT_SHADER,具體取決于shaderType的值。
像紋理對象一樣,著色器對象的命名空間可以在一組上下文中共享,只要這些上下文的服務器端共享相同的地址空間。如果命名空間在上下文中共享,任何附加的對象及其相關數據也會被共享。
如果在創建著色器對象時發生錯誤,此函數將返回0。
GL_INVALID_ENUM
?生成如果?shaderType
?不是可接受的值。
1.4glShaderSource
1.4.1c規范
1.4.2功能
替換著色器對象中的源代碼
1.4.3參數
shader
指定要替換源代碼的著色器對象的句柄。
count
指定?string
?和?length
?數組中的元素數量。
string
指定一個字符串數組的指針,這些字符串包含要加載到著色器中的源代碼。
length
指定一個字符串長度的數組。
?1.4.4代碼
glShaderSource(id, 1, &src, nullptr);
1.4.5描述
glShaderSource 將源代碼設置為 shader 中指定的字符串數組。任何之前存儲在著色器對象中的源代碼將被完全替換。字符串數組的長度由 string 指定。如果 count 為 length,則每個字符串被認為是 null 終止的。如果 NULL 是一個值,它指向一個包含每個相應元素的字符串長度的數組。每個元素在 length 數組中可能包含相應字符串的長度(不包括 null 字符作為字符串長度的一部分)或一個小于 0 的值,表示字符串是 null 終止的。源代碼字符串在此時不會被掃描或解析;它們只是被復制到指定的著色器對象中。
OpenGL在glShaderSource
被調用時復制著色器源代碼字符串,因此應用程序可以在函數返回后立即釋放其源代碼字符串的副本。
GL_INVALID_VALUE
?生成,如果?shader
?不是 OpenGL 生成的值。
GL_INVALID_OPERATION
?生成?shader
?如果不是著色器對象。
GL_INVALID_VALUE
?生成如果?count
?小于 0。
1.5glCompileShader
1.5.1c規范
1.5.2功能
編譯著色器對象
1.5.3參數
-
hader
指定要編譯的著色器對象。
?1.5.4代碼
glCompileShader(id);
1.5.5描述
對于支持著色器編譯的實現,glCompileShader 編譯由 shader 指定的著色器對象中存儲的源代碼字符串。 編譯狀態將作為著色器對象狀態的一部分進行存儲。如果著色器編譯時沒有錯誤并且可以使用,則此值將被設置為GL_TRUE,否則為GL_FALSE。可以通過調用glGetShaderiv并傳入參數shader和GL_COMPILE_STATUS來查詢。 著色器的編譯可能會因多種原因失敗,具體原因由OpenGL ES 著色語言規范規定。無論編譯是否成功,都可以通過調用glGetShaderInfoLog從著色器對象的信息日志中獲取編譯信息。
著色器編譯器支持是可選的,因此在使用之前必須通過調用?glGet?與參數?GL_SHADER_COMPILER
?進行查詢。glShaderSource、glCompileShader
、glGetShaderPrecisionFormat?和?glReleaseShaderCompiler?在不支持著色器編譯器的實現中將分別生成?GL_INVALID_OPERATION
。此類實現提供了?glShaderBinary?作為提供預編譯著色器二進制數據的替代方案。
GL_INVALID_OPERATION
如果不受支持的著色器編譯器生成。
GL_INVALID_VALUE
?生成,如果?shader
?不是 OpenGL 生成的值。
GL_INVALID_OPERATION
?生成?shader
?如果不是著色器對象。
1.6glAttachShader
1.6.1c規范
1.6.2功能
?將著色器對象附加到程序對象
1.6.3參數
program
指定將著色器對象附加到的程序對象。
shader
指定要附加的著色器對象。
?1.6.4代碼
glAttachShader(program, vs);
glAttachShader(program, fs);
1.6.5描述
為了創建一個可執行文件,必須有一種方法來指定將要鏈接在一起的一系列事物。程序對象提供了這種機制。要鏈接在一起的著色器必須首先附加到該程序對象。glAttachShader
將由shader
指定的著色器對象附加到由program
指定的程序對象。shader
這表示program
將被包含在對
可以對著色器對象執行的所有操作在著色器對象是否附加到程序對象上都是有效的。允許在將源代碼加載到著色器對象中或編譯著色器對象之前將著色器對象附加到程序對象上。允許附加多個相同類型的著色器對象,因為每個著色器對象可能包含完整著色器的一部分。還允許將著色器對象附加到一個以上的程序對象上。如果在著色器對象附加到程序對象時刪除它,它將被標記為刪除,直到調用glDetachShader?將其從所有附加的程序對象中分離出來,才會進行刪除。
1.7glValidateProgram
1.7.1c規范
1.7.2功能
根據當前 GL 狀態驗證程序管道對象。
驗證著色器程序對象是否可以在當前OpenGL狀態中執行。具體來說,它會檢查著色器程序中所有著色器的接口是否匹配,包括輸入和輸出變量的類型、名稱和數量。此外,它還會檢查著色器程序是否可以在當前的OpenGL版本和上下文中正確執行。
1.7.3參數
-
program
指定要驗證的程序對象的句柄。即要驗證的著色器程序對象的ID。這個ID在之前通過
glCreateProgram()
創建,并通過glAttachShader
和glLinkProgram
附加和鏈接了頂點著色器和片段著色器。
?1.7.4代碼
glValidateProgram(program);
1.7.5描述
這個函數會檢查著色器程序的完整性和可執行性。它驗證著色器程序的接口是否正確,并且在特定的OpenGL環境中是否可以正確地執行。
如果驗證失敗,OpenGL會設置一個錯誤標志,可以通過glGetProgramiv
函數查詢驗證結果和錯誤信息。
glValidateProgram 檢查是否可以在當前OpenGL狀態下調用包含在 program 中的可執行文件。驗證過程生成的信息將存儲在 program 的信息日志中。驗證信息可能是一個空字符串,或者是一個包含當前程序對象與當前OpenGL狀態其余部分如何交互的信息的字符串。這為OpenGL實現者提供了一種傳達當前程序為何效率低下、不優化、無法執行等更多信息的方法。 驗證操作的狀態將作為程序對象狀態的一部分被存儲。如果驗證成功,此值將被設置為GL_TRUE,否則將被設置為GL_FALSE。可以通過調用glGetProgram并傳入參數program和GL_VALIDATE_STATUS來查詢。如果驗證成功,program在當前狀態下保證會被執行。否則,program保證不會執行。 此功能通常僅在應用程序開發期間有用。存儲在信息日志中的信息字符串完全取決于實現;因此,應用程序不應期望不同的 OpenGL 實現產生相同的信息字符串。
此函數模擬了當渲染命令發出時,OpenGL 實現必須執行的驗證操作,此時可編程著色器是當前狀態的一部分。如果發生以下情況,將生成錯誤GL_INVALID_OPERATION:
????????當前程序對象中的任意兩個活動采樣器是不同類型的,但引用相同的紋理圖像單元,
???????? 程序中活動采樣器的數量超過了允許的最大紋理圖像單元數量。
當發出渲染命令時,應用程序可能難以捕獲這些錯誤或會導致性能下降。因此,建議應用程序在開發過程中調用glValidateProgram以檢測這些問題。
GL_INVALID_VALUE
?生成,如果?program
?不是 OpenGL 生成的值。
GL_INVALID_OPERATION
?生成?program
?如果不是程序對象。
1.8glLinkProgram
1.8.1c規范
1.8.2功能
鏈接程序對象
1.8.3參數
-
program
指定要鏈接的程序對象的句柄。
?1.8.4代碼
glLinkProgram(program);
1.8.5描述
glLinkProgram 將指定的程序對象鏈接 program。如果 GL_VERTEX_SHADER類型的任何著色器對象附加到 program,它們將被用來創建一個將在可編程頂點處理器上運行的可執行文件。如果 GL_GEOMETRY_SHADER類型的任何著色器對象附加到 program,它們將被用來創建一個將在可編程幾何處理器上運行的可執行文件。如果 GL_FRAGMENT_SHADER類型的任何著色器對象附加到 program,它們將被用來創建一個將在可編程片段處理器上運行的可執行文件。
鏈接操作的狀態將作為程序對象狀態的一部分被存儲。如果程序對象鏈接成功且無錯誤,該值將被設置為GL_TRUE,否則為GL_FALSE。可以通過調用glGetProgram并傳入參數program和GL_LINK_STATUS來查詢。
成功的鏈接操作后,屬于program的所有活動的用戶定義的統一變量將被初始化為0,并且每個程序對象的活動統一變量將被分配一個可以通過調用glGetUniformLocation查詢的位置。同時,任何未綁定到通用頂點屬性索引的活動用戶定義的屬性變量將在此時綁定到一個。
程序對象的鏈接可能會因多種原因失敗,具體原因請參閱OpenGL著色語言規范。以下列出了一些會導致鏈接錯誤的條件。
實現所支持的活動屬性變量數量已超出。
均勻變量的存儲限制已超出。
實現支持的活動統一變量數量已超出。
頂點、幾何或片段著色器的main函數缺失。
在片段著色器中實際使用的可變變量沒有以相同的方式聲明(或根本未聲明)在頂點著色器中,如果存在幾何著色器,則在幾何著色器中也是如此。
對函數或變量名的引用未解析。
聲明一個全局共享變量,有兩種不同類型或兩種不同的初始值。
一個或多個附加的著色器對象編譯未成功。
綁定通用屬性矩陣時導致矩陣的一些行超出了允許的最大值GL_MAX_VERTEX_ATTRIBS。
無法找到足夠的連續頂點屬性插槽來綁定屬性矩陣。
程序對象包含用于形成片段著色器的對象,但不包含用于形成頂點著色器的對象。
程序對象包含用于形成幾何著色器的對象,但不包含用于形成頂點著色器的對象。
程序對象包含用于形成幾何著色器的對象,但未在任何編譯的幾何著色器對象中指定輸入原始類型、輸出原始類型或最大輸出頂點數。
程序對象包含用于形成幾何著色器的對象,并且在多個幾何著色器對象中幾何輸入類型、幾何輸出類型或最大輸出頂點數的指定方式不同。
片段著色器中活動輸出的數量大于GL_MAX_DRAW_BUFFERS的值。
該程序有一個活動輸出被分配到一個大于或等于GL_MAX_DUAL_SOURCE_DRAW_BUFFERS的值的位置。
該程序有一個活動輸出被分配到一個大于或等于一的索引。
多個變化輸出變量綁定到相同的編號和索引。
顯式綁定分配沒有為鏈接器自動分配一個位置留下足夠的空間,對于需要多個連續位置的可變輸出數組來說是這樣。
glTransformFeedbackVaryingscount指定的值非零,但程序對象沒有頂點或幾何著色器。
任何在glTransformFeedbackVaryings中指定的變量名在varyings數組中未在頂點著色器(或啟用時的幾何著色器)中聲明為輸出。
數組中的任意兩個條目varyings由glTransformFeedbackVaryings指定相同的可變變量。
在任何變換反饋可變變量中捕獲的組件總數大于常量GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,緩沖模式是GL_SEPARATE_ATTRIBS.。
當程序對象成功鏈接后,可以通過調用glUseProgram使程序對象成為當前狀態的一部分。無論鏈接操作是否成功,程序對象的信息日志都會被覆蓋。信息日志可以通過調用glGetProgramInfoLog來檢索。
glLinkProgram 如果鏈接操作成功,并且指定的程序對象在之前調用 glUseProgram 后已經正在使用中,則還會將生成的可執行文件安裝為當前渲染狀態的一部分。如果當前正在使用的程序對象鏈接不成功,其鏈接狀態將被設置為 GL_FALSE ,但其可執行文件和相關狀態將保持在當前狀態中,直到后續調用 glUseProgram 將其從使用中移除。在移除之前,它不能在成功重新鏈接之前成為當前狀態的一部分。
如果program包含類型為GL_VERTEX_SHADER的著色器對象,并且可以包含類型為GL_GEOMETRY_SHADER的著色器對象,但不包含類型為GL_FRAGMENT_SHADER的著色器對象,頂點著色器可執行文件將被安裝在可編程頂點處理器上,如果存在幾何著色器可執行文件,將被安裝在可編程幾何處理器上,但不會在片段處理器上安裝任何可執行文件。使用這種程序渲染原語的結果將是未定義的。
程序對象的信息日志會在鏈接操作時更新并生成程序。鏈接操作完成后,應用程序可以自由修改附加的著色器對象、編譯附加的著色器對象、分離著色器對象、刪除著色器對象以及附加額外的著色器對象。這些操作都不會影響程序對象的一部分的信息日志或程序。
如果鏈接操作不成功,任何關于之前鏈接操作的信息都會丟失(即,失敗的鏈接不會恢復program
的舊狀態)。某些信息即使在鏈接操作不成功后仍然可以從program
檢索出來。例如program
glGetActiveAttrib和glGetActiveUniform。
?1.9glDeleteShader
1.9.1c規范
1.9.2功能
刪除著色器對象
1.9.3參數
-
shader
指定要刪除的著色器對象。
?1.9.4代碼
glDeleteShader(vs);
glDeleteShader(fs);
1.9.5描述
glDeleteShader 釋放指定的著色器對象所關聯的內存并使該名稱無效 shader。此命令有效地撤銷了對 glCreateShader 的調用效果。
如果要刪除的著色器對象附加到一個程序對象上,它將被標記為刪除,但在它不再附加到任何程序對象、任何渲染上下文之前不會被刪除(即,它必須從之前附加的位置 detachment 才會被刪除)。shader的值為0將被靜默忽略。
要確定一個對象是否已被標記刪除,請調用 glGetShader 并傳入參數 shader 和 GL_DELETE_STATUS。
GL_INVALID_VALUE
?生成,如果?shader
?不是 OpenGL 生成的值。
?1.10glGetShaderInfoLog
1.10.1c規范
1.10.2功能
返回著色器對象的信息日志
1.10.3參數
shader
指定要查詢信息日志的著色器對象。
maxLength
指定用于存儲返回的信息日志的字符緩沖區的大小。
length
返回在infoLog
中返回的字符串長度(不包括終止符)。
infoLog
指定用于返回信息日志的字符數組。
?1.10.4代碼
char* message = (char*)alloca(length*sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
1.10.5描述
glGetShaderInfoLog返回指定著色器對象的信息日志。當著色器編譯時,著色器對象的信息日志會進行修改。返回的字符串將是以空字符結尾的。
glGetShaderInfoLog 返回 infoLog 盡可能多的信息日志,最多 maxLength 個字符。實際返回的字符數(不包括空終止字符)由 length 指定。如果不需要返回字符串的長度,可以在 NULL 中傳遞 length 的值。通過調用 glGetShader 和傳遞值 GL_INFO_LOG_LENGTH 可以獲得存儲返回信息日志所需的緩沖區大小。
著色器對象的信息日志是一個字符串,可能包含診斷消息、警告消息和其他關于上次編譯操作的信息。當著色器對象創建時,其信息日志將是一個長度為0的字符串。
GL_INVALID_VALUE 生成,如果 shader 不是 OpenGL 生成的值。
GL_INVALID_OPERATION 如果 shader 不是著色器對象,則生成。
GL_INVALID_VALUE 生成如果 maxLength 小于 0。
1.11glGetShaderiv
1.11.1c規范
1.11.2功能
從著色器對象返回一個參數
1.11.3參數
-
shader
指定要查詢的著色器對象。
-
pname
指定對象參數。接受的符號名稱是 GL_SHADER_TYPE、GL_DELETE_STATUS、GL_COMPILE_STATUS、GL_INFO_LOG_LENGTH、GL_SHADER_SOURCE_LENGTH。
-
params
返回請求的對象參數。
?1.11.4代碼
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
1.11.5描述
如果生成錯誤,則不會更改params
的內容。
GL_INVALID_VALUE 生成,如果 shader 不是 OpenGL 生成的值。
GL_INVALID_OPERATION 如果 shader 不是指向著色器對象,則生成
GL_INVALID_ENUM 生成 pname 如果不是接受的值。
?1.12glUseProgram
1.12.1c規范
1.12.2功能
將程序對象安裝為當前渲染狀態的一部分
1.12.3參數
-
program
指定用于當前渲染狀態的程序對象的句柄。
?1.12.4代碼
glUseProgram(shader);
1.12.5描述
?1.13glGetShaderInfoLog
1.13.1c規范
1.13.2功能
返回著色器對象的信息日志
1.13.3參數
-
shader
指定要查詢信息日志的著色器對象。
-
maxLength
指定用于存儲返回的信息日志的字符緩沖區大小。
-
length
返回在infoLog中返回的字符串長度(不包括終止符)。
-
infoLog
指定用于返回信息日志的字符數組。
?1.13.4代碼
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;
std::cout << message << std::endl;
1.13.5描述
GL_INVALID_VALUE
?生成,如果?shader
?不是 OpenGL 生成的值。
GL_INVALID_OPERATION
?生成?shader
?如果不是著色器對象。
GL_INVALID_VALUE
?生成如果?maxLength
?小于 0。
二、代碼
2.1 代碼
全注釋版
#include <GL/glew.h>
#include <GLFW/glfw3.h>#include<iostream>//功能:編譯著色器代碼
//參數:1.type表示著色器類型,GL_VERTEX_SHADER表示頂點著色器,GL_FRAGMENT_SHADER表示片段著色器
//2.source表示著色器源代碼的字符串
//返回值:編譯成功的著色器對象ID,失敗則返回0
static unsigned int CompilesShader(unsigned int type, const std::string& source)
{//功能:創建著色器對象//參數:1.type表示著色器類型,GL_VERTEX_SHADER表示頂點著色器,GL_FRAGMENT_SHADER表示片段著色器//返回值:著色器對象IDunsigned int id = glCreateShader(type);//功能:設置著色器源代碼.//通過傳遞的字符串指針,將源代碼復制到著色器對象中//注意:這里的src指針必須指向以null結尾的字符串,否則會導致編譯錯誤//c_str()函數可以將std::string轉換為const char*類型//也可const char* src = &source[0];const char* src = source.c_str();//功能:替換著色器對象中的源代碼。將該id的指定著色器的源代碼設置為src指針指向的字符串//參數:1.id表示著色器對象ID//2.1表示著色器源代碼的數量//3.src指針表示著色器源代碼的字符串指針//4.nullptr表示長度為0的字符串指針glShaderSource(id, 1, &src, nullptr);//功能:編譯著色器對象的源代碼//參數:1.id表示著色器對象IDglCompileShader(id);//設置返回著色器的對象ID//這里不能寫成unsigned,會報錯——// "unsigned int *" 類型的實參與 "GLint *" (aka "int *") 類型的形參不兼容int result;//功能:從著色器對象返回一個參數,表示編譯是否成功。//參數:1.id表示著色器對象ID//2.GL_COMPILE_STATUS表示對象的參數//3.result指針表示編譯成功/請求的對象參數值glGetShaderiv(id, GL_COMPILE_STATUS, &result);//如果編譯失敗,則輸出錯誤信息if (result == GL_FALSE){int length;//功能:獲取編譯錯誤信息的長度glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);//分配內存,用于存儲編譯錯誤信息//alloca()函數用于分配堆棧內存,避免堆內存碎片化//alloca和new的區別:alloca分配的內存不會被自動釋放,而new分配的內存會被自動釋放//alloca和malloc的區別:alloca分配的內存大小必須是編譯器確定的,而malloc分配的內存大小可以由用戶指定char* message = (char*)alloca(length*sizeof(char));//功能:獲取編譯錯誤信息//參數:1.id表示著色器對象ID//2.length表示編譯錯誤信息的長度,指定用于存儲返回的信息日志的字符緩沖區大小。//3.length指針表示實際獲取的編譯錯誤信息的長度,返回在infoLog中返回的字符串長度(不包括終止符)。//4.message指針表示編譯錯誤信息的字符串指針glGetShaderInfoLog(id, length, &length, message);std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;std::cout << message << std::endl;//刪除著色器對象glDeleteShader(id);return 0;}//TODO:錯誤處理ingreturn id;
}//功能:創建著色器程序
//將頂點著色器和片段著色器的代碼連接(作為字符串)編譯為一個程序對象,并返回程序對象
//參數:頂點著色器代碼、片段著色器代碼
//返回值:著色器程序對象的ID
//定義為靜態函數:
// 靜態函數可以使函數的可見性降低,僅限于被定義的文件內部使用。
// 這有助于封裝代碼,使得其他文件無法直接調用這個函數。
// 可以避免命名沖突
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{//創建程序對象//返回:程序對象ID。創建的程序對象是一個ID值,用于標識一個OpenGL程序對象unsigned int program = glCreateProgram();//編譯頂點著色器對象//參數:1.GL_VERTEX_SHADER表示創建頂點著色器對象//2.vertexShader.c_str()表示頂點著色器源代碼的字符串指針//返回值:編譯成功的著色器對象IDunsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);//編譯片段著色器對象//參數:1.GL_FRAGMENT_SHADER表示創建片段著色器對象//2.fragmentShader.c_str()表示片段著色器源代碼的字符串指針//返回值:編譯成功的著色器對象IDunsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);//功能:將編譯好的著色器對象附加到程序對象中//參數:1.program表示程序對象ID//2.vs表示頂點著色器對象ID//3.fs表示片段著色器對象IDglAttachShader(program, vs);glAttachShader(program, fs);//功能:鏈接程序對象//實際上鏈接是通過把所有著色器對象中的代碼合并到一個程序對象中,然后編譯這個程序對象來實現的。//參數:1.program表示程序對象IDglLinkProgram(program);//功能:驗證著色器程序對象是否可以在當前OpenGL狀態中執行。檢查著色器程序的完整性和可執行性。//如果驗證失敗,OpenGL會設置一個錯誤標志,可以通過glGetProgramiv函數查詢驗證結果和錯誤信息。//驗證過程生成的信息將存儲在 program 的信息日志中。// 驗證信息可能是一個空字符串,或者是一個包含當前程序對象與當前OpenGL狀態其余部分如何交互的信息的字符串。// 驗證操作的狀態將作為程序對象狀態的一部分被存儲。// 如果驗證成功,此值將被設置為GL_TRUE,否則將被設置為GL_FALSE。//可以通過調用glGetProgram并傳入參數program和GL_VALIDATE_STATUS來查詢。glValidateProgram(program);//刪除著色器對象,因為它們已經被鏈接到程序對象中glDeleteShader(vs);glDeleteShader(fs);//返回著色器程序return program;
}int main(void)
{GLFWwindow* window;//初始化glfwif (!glfwInit())return -1;//創建一個窗口模式的窗口并設置OpenGL上下文window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);if (!window)//如果窗口創建失敗,則終止程序{glfwTerminate();//釋放glfw資源return -1;}//設置當前窗口的上下文,之后所有的OpenGL調用都會在這個上下文中進行glfwMakeContextCurrent(window);//初始化GLEWif (glewInit() != GLEW_OK)std::cout << "Error!" << std::endl;//打印OpenGL版本信息std::cout << glGetString(GL_VERSION) << std::endl;//準備數據float position[6] = {0.0f, 0.5f,-0.5f, -0.5f,0.5f, -0.5f};//定義緩沖區對象unsigned int buffer;//功能:生成緩沖區對象,并將數據寫入緩沖區glGenBuffers(1, &buffer);//功能:將緩沖區對象綁定到目標glBindBuffer(GL_ARRAY_BUFFER, buffer);//功能:將數據寫入緩沖區glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), position, GL_STATIC_DRAW);//功能:配置頂點屬性指針//參數:1.0表示頂點屬性數組的索引glEnableVertexAttribArray(0);//功能:指定頂點屬性數組的索引、大小、數據類型、是否歸一化、偏移量、數據指針//參數:1.0表示頂點屬性數組的索引.和下面vertexShader(location=0)的0匹配//2.2表示頂點屬性數組的大小,這里是2D坐標//3.GL_FLOAT表示數據類型//4.GL_FALSE表示是否歸一化//5.sizeof(float)*2表示數據指針的字節大小//6.0表示偏移量glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//準備著色器代碼//core表示使用的是核心配置文件,它移除了舊版本中一些過時的OpenGL函數和功能,使得代碼更加清晰和高效。//layout(location = 0) : 這是一個布局限定符(layout qualifier)// 用于指定輸入變量在著色器程序中的位置索引。//in vec4 position; : 這是一個輸入變量聲明。// in關鍵字表示該變量是輸入到頂點著色器的,// vec4表示數據類型為4維浮點數向量(vec4),// position是變量的名稱。// 這行代碼的意思是頂點著色器接收一個4維浮點數向量的輸入,變量名是position,用于表示頂點的位置。// 實際應用中,通常只使用前三個分量(x, y, z)來表示頂點的位置,第四個分量(w)用于透視除法等操作。//void main(): 這是頂點著色器的主函數聲明。每個頂點著色器程序都必須有一個名為main的函數。//gl_Position = position;將輸入的頂點位置position賦值給gl_Position。// gl_Position是OpenGL內置的變量,用于存儲頂點在裁剪空間中的位置。//在這個簡單的例子中,頂點著色器不做任何額外的處理,只是將輸入的頂點位置直接輸出到裁剪空間。// 這意味著頂點的位置不會被變換,而是直接基于裁剪空間的坐標系來繪制。std::string vertexShader ="#version 330 core\n""\n""layout (location = 0) in vec4 position;\n""void main()\n""{\n"" gl_Position = position;\n""}\n";//vec4 是 GLSL(OpenGL Shading Language)中的一個內置類型,表示一個包含四個浮點數的向量。// 這四個浮點數通常用于表示顏色的 RGBA 值,即紅(R)、綠(G)、藍(B)和透明度(A)。//color 是片段著色器中的一個輸出變量。用于設置最終輸出到屏幕上的顏色。std::string fragmentShader ="#version 330 core\n""\n""layout (location = 0) out vec4 color;\n""void main()\n""{\n"" color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n""}\n";//創建著色器程序unsigned int shader = CreateShader(vertexShader, fragmentShader);//使用著色器程序glUseProgram(shader);//渲染循環,直到窗口被關閉while (!glfwWindowShouldClose(window)){//清除顏色緩沖區glClear(GL_COLOR_BUFFER_BIT);//功能:繪制三角形glDrawArrays(GL_TRIANGLES, 0, 3);//刷新緩沖區并交換窗口glfwSwapBuffers(window);//處理窗口事件,如鍵盤輸入、鼠標移動等glfwPollEvents();}//刪除著色器程序glDeleteProgram(shader);//釋放 GLFW 庫占用的所有資源。它在程序結束時調用,以確保不會出現資源泄漏。//調用 glfwTerminate() 后,GLFW 將釋放所有與 OpenGL 上下文相關的資源,包括窗口、OpenGL 對象等。glfwTerminate();return 0;
}
簡潔版,純功能注釋
#include <GL/glew.h>
#include <GLFW/glfw3.h>#include<iostream>//功能:編譯著色器代碼
static unsigned int CompilesShader(unsigned int type, const std::string& source)
{//功能:創建著色器對象unsigned int id = glCreateShader(type);//功能:設置著色器源代碼.const char* src = source.c_str();//功能:替換著色器對象中的源代碼。將該id的指定著色器的源代碼設置為src指針指向的字符串glShaderSource(id, 1, &src, nullptr);//功能:編譯著色器對象的源代碼glCompileShader(id);//設置返回著色器的對象IDint result;//功能:從著色器對象返回一個參數,表示編譯是否成功。glGetShaderiv(id, GL_COMPILE_STATUS, &result);//如果編譯失敗,則輸出錯誤信息if (result == GL_FALSE){int length;//功能:獲取編譯錯誤信息的長度glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);//分配內存,用于存儲編譯錯誤信息char* message = (char*)alloca(length*sizeof(char));//功能:獲取編譯錯誤信息glGetShaderInfoLog(id, length, &length, message);std::cout << "Failed to compile shader!" << (type == GL_VERTEX_SHADER? "Vertex" : "Fragment") << "shader!" << std::endl;std::cout << message << std::endl;//刪除著色器對象glDeleteShader(id);return 0;}//TODO:錯誤處理ingreturn id;
}//功能:創建著色器程序
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{//創建程序對象unsigned int program = glCreateProgram();//編譯頂點著色器對象unsigned int vs = CompilesShader(GL_VERTEX_SHADER, vertexShader);//編譯片段著色器對象unsigned int fs = CompilesShader(GL_FRAGMENT_SHADER, fragmentShader);//功能:將編譯好的著色器對象附加到程序對象中glAttachShader(program, vs);glAttachShader(program, fs);//功能:鏈接程序對象glLinkProgram(program);//功能:驗證著色器程序對象是否可以在當前OpenGL狀態中執行。檢查著色器程序的完整性和可執行性。glValidateProgram(program);//刪除著色器對象,因為它們已經被鏈接到程序對象中glDeleteShader(vs);glDeleteShader(fs);//返回著色器程序return program;
}int main(void)
{GLFWwindow* window;//初始化glfwif (!glfwInit())return -1;//創建一個窗口模式的窗口并設置OpenGL上下文window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);if (!window)//如果窗口創建失敗,則終止程序{glfwTerminate();//釋放glfw資源return -1;}//設置當前窗口的上下文,之后所有的OpenGL調用都會在這個上下文中進行glfwMakeContextCurrent(window);//初始化GLEWif (glewInit() != GLEW_OK)std::cout << "Error!" << std::endl;//打印OpenGL版本信息std::cout << glGetString(GL_VERSION) << std::endl;//準備數據float position[6] = {0.0f, 0.5f,-0.5f, -0.5f,0.5f, -0.5f};//定義緩沖區對象unsigned int buffer;//功能:生成緩沖區對象,并將數據寫入緩沖區glGenBuffers(1, &buffer);//功能:將緩沖區對象綁定到目標glBindBuffer(GL_ARRAY_BUFFER, buffer);//功能:將數據寫入緩沖區glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), position, GL_STATIC_DRAW);//功能:配置頂點屬性指針glEnableVertexAttribArray(0);//功能:指定頂點屬性數組的索引、大小、數據類型、是否歸一化、偏移量、數據指針glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//準備著色器代碼std::string vertexShader ="#version 330 core\n""\n""layout (location = 0) in vec4 position;\n""void main()\n""{\n"" gl_Position = position;\n""}\n";std::string fragmentShader ="#version 330 core\n""\n""layout (location = 0) out vec4 color;\n""void main()\n""{\n"" color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n""}\n";//創建著色器程序unsigned int shader = CreateShader(vertexShader, fragmentShader);//使用著色器程序glUseProgram(shader);//渲染循環,直到窗口被關閉while (!glfwWindowShouldClose(window)){//清除顏色緩沖區glClear(GL_COLOR_BUFFER_BIT);//功能:繪制三角形glDrawArrays(GL_TRIANGLES, 0, 3);//刷新緩沖區并交換窗口glfwSwapBuffers(window);//處理窗口事件,如鍵盤輸入、鼠標移動等glfwPollEvents();}//刪除著色器程序//glDeleteProgram(shader);//釋放 GLFW 庫占用的所有資源。glfwTerminate();return 0;
}