OpenGL Chan視頻學習-8 How I Deal with Shaders in OpenGL

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?ShaderProgramSource結構體

//功能:定義ShaderProgramSource結構體,用于存儲著色器代碼
//方便ParseShader函數返回多個著色器代碼
struct ShaderProgramSource
{std::string VertexSource;std::string FragmentSource;
};

1.2ParseShader函數

//功能:解析著色器代碼文件。
//參數:filepath:著色器代碼文件路徑
//返回值:ShaderProgramSource結構體,包含著色器代碼字符串
static ShaderProgramSource ParseShader(const std::string& filepath)
{//功能:打開文件流//參數:filepath:著色器代碼文件路徑std::ifstream stream(filepath);//定義著色器類型enum  class ShaderType{NONE=-1,VERTEX=0,FRAGMENT=1};//該變量用于存儲著色器代碼std::string line;//該變量用于存儲著色器類型std::stringstream ss[2];//該變量是當前著色器類型ShaderType type = ShaderType::NONE;//功能:讀取文件中的每一行內容,直到文件結束while (getline(stream, line)){//如果當前行包含#shader,則說明接下來是著色器代碼//nposstd::string::npos 是 C++ 標準庫中 std::string 類的一個靜態成員。//它代表了一個無效的位置值,通常用于表示在字符串中未找到子字符串的情況。if (line.find("#shader") != std::string::npos){//如果當前行包含vertex,則說明接下來是頂點著色器代碼if (line.find("vertex") != std::string::npos){type = ShaderType::VERTEX;}else if (line.find("fragment") != std::string::npos){type = ShaderType::FRAGMENT;}}else{//否則,將當前行添加到對應著色器代碼的stringstream中//ss[]是一個數組,用于存儲著色器代碼,通過ss[]<<line<<'\n'將當前行添加到對應著色器代碼的stringstream中ss[(int)type] << line << '\n';std::cout << line << " hhh" << std::endl;}}//返回ShaderProgramSource結構體return { ss[0].str(), ss[1].str() };
}

1.3int main函數補充

//解析著色器代碼文件
ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
std::string vertexShader = source.VertexSource;
std::string fragmentShader = source.FragmentSource;std::cout << "VERTEX" << std::endl << vertexShader << std::endl;
std::cout << "FRAGMENT" << std::endl << fragmentShader << std::endl;

二、完整代碼

1.1完全注釋代碼

#include <GL/glew.h>
#include <GLFW/glfw3.h>#include<iostream>
#include<fstream>
#include<string>
#include<sstream>//功能:定義ShaderProgramSource結構體,用于存儲著色器代碼
//方便ParseShader函數返回多個著色器代碼
struct ShaderProgramSource
{std::string VertexSource;std::string FragmentSource;
};//功能:解析著色器代碼文件。
//參數:filepath:著色器代碼文件路徑
//返回值:ShaderProgramSource結構體,包含著色器代碼字符串
static ShaderProgramSource ParseShader(const std::string& filepath)
{//功能:打開文件流//參數:filepath:著色器代碼文件路徑std::ifstream stream(filepath);//定義著色器類型enum  class ShaderType{NONE=-1,VERTEX=0,FRAGMENT=1};//該變量用于存儲著色器代碼std::string line;//該變量用于存儲著色器類型std::stringstream ss[2];//該變量是當前著色器類型ShaderType type = ShaderType::NONE;//功能:讀取文件中的每一行內容,直到文件結束while (getline(stream, line)){//如果當前行包含#shader,則說明接下來是著色器代碼//nposstd::string::npos 是 C++ 標準庫中 std::string 類的一個靜態成員。//它代表了一個無效的位置值,通常用于表示在字符串中未找到子字符串的情況。if (line.find("#shader") != std::string::npos){//如果當前行包含vertex,則說明接下來是頂點著色器代碼if (line.find("vertex") != std::string::npos){type = ShaderType::VERTEX;}else if (line.find("fragment") != std::string::npos){type = ShaderType::FRAGMENT;}}else{//否則,將當前行添加到對應著色器代碼的stringstream中//ss[]是一個數組,用于存儲著色器代碼,通過ss[]<<line<<'\n'將當前行添加到對應著色器代碼的stringstream中ss[(int)type] << line << '\n';}}//返回ShaderProgramSource結構體return { ss[0].str(), ss[1].str() };
}//功能:編譯著色器代碼
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);//解析著色器代碼文件ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");std::string vertexShader = source.VertexSource;std::string fragmentShader = source.FragmentSource;std::cout << "VERTEX" << std::endl << vertexShader << std::endl;std::cout << "FRAGMENT" << std::endl << fragmentShader << std::endl;//創建著色器程序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;
}

2.2簡潔注釋代碼

#include <GL/glew.h>
#include <GLFW/glfw3.h>#include<iostream>
#include<fstream>
#include<string>
#include<sstream>//功能:定義ShaderProgramSource結構體,用于存儲著色器代碼
struct ShaderProgramSource
{std::string VertexSource;std::string FragmentSource;
};//功能:解析著色器代碼文件。
static ShaderProgramSource ParseShader(const std::string& filepath)
{//功能:打開文件流std::ifstream stream(filepath);//定義著色器類型enum  class ShaderType{NONE=-1,VERTEX=0,FRAGMENT=1};//該變量用于存儲著色器代碼std::string line;//該變量用于存儲著色器類型std::stringstream ss[2];//該變量是當前著色器類型ShaderType type = ShaderType::NONE;//功能:讀取文件中的每一行內容,直到文件結束while (getline(stream, line)){//如果當前行包含#shader,則說明接下來是著色器代碼if (line.find("#shader") != std::string::npos){//如果當前行包含vertex,則說明接下來是頂點著色器代碼if (line.find("vertex") != std::string::npos){type = ShaderType::VERTEX;}else if (line.find("fragment") != std::string::npos){type = ShaderType::FRAGMENT;}}else{//否則,將當前行添加到對應著色器代碼的stringstream中ss[(int)type] << line << '\n';}}//返回ShaderProgramSource結構體return { ss[0].str(), ss[1].str() };
}//功能:編譯著色器代碼
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);//解析著色器代碼文件ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");std::string vertexShader = source.VertexSource;std::string fragmentShader = source.FragmentSource;std::cout << "VERTEX" << std::endl << vertexShader << std::endl;std::cout << "FRAGMENT" << std::endl << fragmentShader << std::endl;//創建著色器程序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;
}

2.3運行結果

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/82701.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/82701.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/82701.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

動態防御新紀元:AI如何重構DDoS攻防成本格局

1. 傳統高防IP的靜態瓶頸與成本困境 傳統高防IP依賴預定義規則庫&#xff0c;面對SYN Flood、CC攻擊等威脅時&#xff0c;常因規則更新滯后導致誤封合法流量。例如&#xff0c;某電商平臺曾因靜態閾值過濾誤封20%的訂單接口流量&#xff0c;直接影響營收。以下代碼模擬傳統方案…

如何實現高性能超低延遲的RTSP或RTMP播放器

隨著直播行業的快速發展&#xff0c;RTSP和RTMP協議成為了廣泛使用的流媒體傳輸協議&#xff0c;尤其是在實時視頻直播領域&#xff0c;如何構建一個高性能超低延遲的直播播放器&#xff0c;已經成為了決定直播平臺成功與否的關鍵因素之一。作為音視頻直播SDK技術老兵&#xff…

UE5 編輯器工具藍圖

文章目錄 簡述使用方法樣例自動生成Actor&#xff0c;并根據模型的包圍盒設置Actor的大小批量修改場景中Actor的屬性&#xff0c;設置Actor的名字&#xff0c;設置Actor到指定的文件夾 簡述 使用編輯器工具好處是可以在非運行時可以對資源或場景做一些操作&#xff0c;例如自動…

解鎖5月游戲新體驗 高速電腦配置推薦

很多玩家用戶會發現一個規律&#xff0c;618大促前很多商家會提前解鎖各種福利&#xff0c;5月選購各種電腦配件有時候會更劃算&#xff01;并且&#xff0c;STEAM在5月還有幾個年度主題促銷&#xff0c;“生物收集游戲節”、“僵尸大戰吸血鬼游戲節”等等&#xff0c;配件大促…

干貨|VR全景是什么?

VR全景技術解析&#xff1a;概念、特點與用途 VR全景&#xff0c;全稱為虛擬現實全景技術&#xff08;Virtual Reality Panorama Technology&#xff09;&#xff0c;是基于虛擬現實&#xff08;Virtual Reality,VR&#xff09;技術的創新展示方式。VR全景技術利用專業的拍攝設…

Nacos適配GaussDB超詳細部署流程,通過二進制包、以及 Docker 打通用鏡像包部署保姆級教程

1部署openGauss 官方文檔下載 https://support.huaweicloud.com/download_gaussdb/index.html 社區地址 安裝包下載 本文主要是以部署輕量級為主要教程,系統為openEuler,ip: 192.168.1.15 1.1系統環境準備 操作系統選擇 系統AARCH64X86-64openEuler√√CentOS7√Docker…

MySQL 表內容的增刪查改 -- CRUD操作,聚合函數,group by 子句

目錄 1. Create 1.1 語法 1.2 單行數據 全列插入 1.3 多行數據 指定列插入 1.4 插入數據否則更新數據 1.5 替換 2. Retrieve 2.1 SELECT 列 2.1.1 全列查詢 2.1.2 指定列查詢 2.1.3 查詢字段為表達式 2.1.4 為查詢結果指定別名 2.1.5 結構去重 2.2 WHERE 條件 …

LabVIEW累加器標簽通道

主要展示了 Accumulator Tag 通道的使用&#xff0c;通過三個并行運行的循環模擬不同數值的多個隨機序列&#xff0c;分別以不同頻率向累加器寫入數值&#xff0c;右側循環每秒讀取累加器值&#xff0c;同時可切換查看每秒內每次事件的平均值&#xff0c;用于演示多線程數據交互…

【iOS】源碼閱讀(五)——類類的結構分析

文章目錄 前言類的分析類的本質objc_class 、objc_object和NSObjectobjc_object&#xff1a;所有對象的基類型objc_class&#xff1a;類的底層結構NSObject&#xff1a;面向用戶的根類 小結 指針內存偏移普通指針----值拷貝對象----指針拷貝或引用拷貝用數組指針引出----內存偏…

Baklib構建企業CMS高效協作與安全管控體系

企業CMS高效協作體系構建 基于智能工作流引擎的設計邏輯&#xff0c;現代企業內容管理系統通過預設多節點審核路徑與自動化任務分配機制&#xff0c;有效串聯市場、技術、法務等跨部門協作鏈路。系統支持多人同時編輯與版本追溯功能&#xff0c;結合細粒度權限管控模塊&#x…

Linux環境變量與地址空間

哈嘍&#xff0c;各位Linux初學者們&#xff01;今天咱們來聊聊Linux中那兩個看起來很高大上但實際上跟我們日常使用息息相關的概念&#xff1a;環境變量和地址空間。別被這些術語嚇到&#xff0c;我會用最接地氣的方式給你解釋清楚&#xff01; 一、環境變量&#xff1a;Linu…

Oracle SHARED POOL的SUB POOL技術

從Oracle 9i開始&#xff0c;SHARED POOL可以分為多個SUB POOL&#xff0c;其數量受以下幾個因素影響&#xff1a; ?系統CPU的數量。默認情況下&#xff0c;在Oracle中每4個CPU分配一個SUB POOL&#xff0c;最多不能超過7個。 ?共享池的大小。SUB POOL的最小容量隨著Oracle版…

Collection集合遍歷的三種方法

1.foreach循環遍歷 格式&#xff1a;for&#xff08;元素的數據類型 變量名&#xff1a;數組或集合&#xff09;{ } 2.使用迭代器遍歷 方法名稱&#xff1a;Iterator<E> iterator&#xff08;&#xff09; 說明&#xff1a;返回集合中的迭代器對象&#xff0c;該迭代…

頭歌之動手學人工智能-Pytorch 之autograd

目錄 第1關&#xff1a;Variable 任務描述 編程要求 測試說明 沒有偉大的愿望&#xff0c;就沒有偉大的天才。——巴爾扎克開始你的任務吧&#xff0c;祝你成功&#xff01; 第2關&#xff1a;Variable 屬性 任務描述 編程要求 測試說明 真正的科學家應當是個幻想家&a…

篇章二 數據結構——前置知識(二)

目錄 1. 包裝類 1.1 包裝類的概念 1.2 基本數據類型和對應的包裝類 1.3 裝箱和拆箱 1.4 自動裝箱和自動拆箱 1.5 練習 —— 面試題 2. 泛型 2.1 如果沒有泛型——會出現什么情況&#xff1f; 2.2 語法 2.3 裸類型 1.沒有寫<> 但是沒有報錯為什么&#xff1f; …

Git典型使用場景相關命令

Git典型使用場景相關命令 1 建立本地倉庫與遠程倉庫的聯系2 作為開發者參與項目的常用命令2-1 一般步驟2-2 **合并與同步主分支改動**2-3 **查看日志和差異**2-4 **提交后想修改或撤銷**2-5 分支管理2-6 清除未被追蹤的文件&#xff08;謹慎使用&#xff09; 3 作為遠程倉庫管理…

redis緩存-更新策略-三大緩存問題

緩存&#xff1a;數據交換的緩沖區&#xff0c;存儲的數據的臨時地方&#xff0c;讀寫性能較高。 步驟&#xff1a; 先從redis里面查詢 緩存命中&#xff1a;直接返回結果緩存未命中 從數據庫里面查詢 沒有數據&#xff1a;返回null有數據&#xff1a;存到redis里面&#xff…

[TriCore] 01.QEMU 虛擬化 TriCore 架構中的寄存器 指令

目錄 1.寄存器宏 - FIELD() 2.寄存器操作 - FIELD_SETTER() & FIELD_GETTER() 3.指令輔助方法 - HELPER() 3.1.輔助宏 3.2.指令示例 3.3.函數調用 4.PSW 寄存器讀寫 - psw_read() & psw_write() 1.寄存器宏 - FIELD() FIELD() 宏定義寄存器 MASK // include/hw…

《軟件工程》第 4 章 - 需求獲取

在軟件工程中&#xff0c;需求獲取是挖掘用戶真實需求的關鍵步驟&#xff0c;它為后續的設計、開發和測試提供堅實基礎。本章將圍繞需求獲取的流程、方法及工具展開&#xff0c;結合實際案例與 Java 代碼&#xff0c;深入講解這一重要環節。 4.1 軟件需求的初始表示 4.1.1 用例…

react diff 算法

diff 算法作為 Virtual DOM 的加速器&#xff0c;其算法的改進優化是 React 整個界面渲染的基礎和性能的保障&#xff0c;同時也是 React 源碼中最神秘的&#xff0c;最不可思議的部分 diff 算法會幫助我們就算出 VirtualDOM 中真正變化的部分&#xff0c;并只針對該部分進行原…