著色器類:
標頭檔案 h:
#ifndef SHADER_H #define SHADER_H #include <GLAD/glad.h> #include <glfw3.h> #include <string> #include <fstream> #include <sstream> #include <iostream> class Shader { public: // 程式ID unsigned int ID; // 建構函式讀取並構建著色器 Shader(const char* vertexPath,const char* fragmentPath); // 使用/啟用程式 void use(); // uniform 工具函式 void setBool(const std::string &name,bool value) const; void setInt(const std::string &name, int value) const; void setFloat(const std::string &name,float value) const; }; #endif // SHADER_H
原始檔 cpp:
#include "Shader.h" Shader::Shader(const char *vertexPath, const char *fragmentPath) { // 1. 從檔案路徑中獲取頂點/片段著色器 std::string vertexCode; std::string fragmentCode; std::ifstream vShaderFile; std::ifstream fShaderFile; // 保證ifstreamd物件可以丟擲異常 vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try { // 開啟檔案 vShaderFile.open(vertexPath); fShaderFile.open(fragmentPath); std::stringstream vShaderStream, fShaderStream; // 讀取檔案的緩衝內容到資料流中 vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); // 關閉檔案處理器 vShaderFile.close(); fShaderFile.close(); // 轉換資料流到string vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); } catch (std::ifstream::failure e) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; } const char* vShaderCode = vertexCode.c_str(); const char* fShaderCode = fragmentCode.c_str(); // 頂點著色器物件 unsigned int vertexShader; vertexShader = glCreateShader(GL_VERTEX_SHADER); // 建立頂點著色器物件 glShaderSource(vertexShader,1,&vShaderCode,NULL); // 把頂點著色器原始碼附加到頂點著色器物件上 glCompileShader(vertexShader); // 編譯頂點著色器物件 int success; // 檢測頂點著色器物件編譯是否成功 char infoLog[512]; glGetShaderiv(vertexShader,GL_COMPILE_STATUS,&success); if(!success) { glGetShaderInfoLog(vertexShader,512,NULL,infoLog); std::cout<<"Error::shader::vertex::compilation_failed\n"<<infoLog<<std::endl; } // 片段著色器物件 unsigned int fragmentShader; fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); // 建立片段著色器物件 glShaderSource(fragmentShader,1,&fShaderCode,NULL); // 把片段著色器原始碼附加到片段著色器物件上 glCompileShader(fragmentShader); // 編譯片段著色器物件 glGetShaderiv(fragmentShader,GL_COMPILE_STATUS,&success); // 檢查片段著色器物件是否編譯成功 if(!success) { glGetShaderInfoLog(fragmentShader,512,NULL,infoLog); std::cout<<"Error::shader::vertex::compilation_failed\n"<<infoLog<<std::endl; } // 著色器程式物件 unsigned int shaderProgram; shaderProgram = glCreateProgram(); // 建立著色器程式物件 glAttachShader(shaderProgram,vertexShader); // 附加頂點著色器到著色器程式物件上 glAttachShader(shaderProgram,fragmentShader); // 附加片段著色器到著色器程式物件上 glLinkProgram(shaderProgram); // 連結著色器程式物件 glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); // 檢查著色器程式物件是否連結成功 if(!success) { glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); } ID = shaderProgram; // 把著色器物件連結到程式物件以後,刪除著色器物件 glDeleteShader(vertexShader); glDeleteShader(fragmentShader); } void Shader::use() { // 使用著色器程式物件 glUseProgram(ID); } void Shader::setBool(const std::string &name, bool value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), static_cast<int>(value)); } void Shader::setInt(const std::string &name, int value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), value); } void Shader::setFloat(const std::string &name, float value) const { glUniform1f(glGetUniformLocation(ID, name.c_str()), value); }
使用 main.cpp:
#include <iostream> #include <glad/glad.h> #include <glfw3.h> #include "Shader.h" using namespace std; // 回撥函式,每當視窗改變大小,視口大小也跟隨改變 void framebuffer_size_callback(GLFWwindow* window,int width,int height) { glViewport(0,0,width,height); } // 輸入 在GLFW中實現一些輸入控制 void processInput(GLFWwindow *window) { if(glfwGetKey(window,GLFW_KEY_ESCAPE) == GLFW_PRESS) // 是否按下了返回鍵(Esc) { glfwSetWindowShouldClose(window,true); // 把WindowShouldClose屬性設定為 true來關閉GLFW } } // ************** opengl 具體實現 ************ // 頂點資料 float vertices[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f }; //****************************************** int main() { cout << "你好三角形" << endl; // GLFW (視窗) glfwInit(); // 初始化GLFW glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3); // 主版本號 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3); // 次版本號 glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE); // 使用核心模式 //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); Mac OS X系統 // 建立一個GLFW視窗物件 GLFWwindow* window = glfwCreateWindow(800,600,"triangle",NULL,NULL); if(window == NULL) { std::cout<< "Failed to create GLFW window"<<std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); // 視窗的上下文設定為當前執行緒的主上下文 // GLAD if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) // 初始化GLAD(初始化OpenGL函式指標) { std::cout<<"Failed to initialize GLAD"<<std::endl; return -1; } //*********** opengl 具體實現 ****************** // 頂點陣列物件 VAO unsigned int VAO; glGenVertexArrays(1,&VAO); // 建立頂點陣列物件 glBindVertexArray(VAO); // 繫結頂點陣列物件 // 頂點緩衝物件 VBO unsigned int VBO; glGenBuffers(1,&VBO); glBindBuffer(GL_ARRAY_BUFFER,VBO); // 繫結頂點緩衝物件 glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW); // 把之前定義的頂點資料複製到緩衝的記憶體中 Shader shader("vertexSourceCode.vert", "fragmentSourceCode.frag"); // 連結頂點屬性 (告訴 gpu 如何解析記憶體中的頂點資料) glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3 * sizeof(float),(void*)0); glEnableVertexAttribArray(0); //************************** // 視口 glViewport(0,0,800,600); // 視口跟隨視窗大小改變 glfwSetFramebufferSizeCallback(window,framebuffer_size_callback); // 渲染迴圈 while(!glfwWindowShouldClose(window)) // 檢查GLFW是否被要求退出 { // 輸入 (使用者) processInput(window); // 輸入控制(自定義) //************** 渲染指令 (使用者)********** glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); shader.use(); glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES,0,3); //*************************************** // 檢查並呼叫事件,交換緩衝 (預設操作) glfwSwapBuffers(window); // 交換顏色緩衝(它是一個儲存著GLFW視窗每一個畫素顏色值的大緩衝),它在這一迭代中被用來繪製,並且將會作為輸出顯示在螢幕上。 glfwPollEvents(); // 有沒有觸發什麼事件(比如鍵盤輸入、滑鼠移動等)、更新視窗狀態 } // 解綁 VAO VBO 著色器程式物件 glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); // 當渲染迴圈結束後我們需要正確釋放/刪除之前的分配的所有資源 glfwTerminate(); return 0; }
著色器檔案:
頂點著色器檔案 vertexSourceCode.vert
#version 330 core layout (location = 0) in vec3 aPos; void main() { gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0); }
片段著色器檔案 fragmentSourceCode.frag
#version 330 core out vec4 FragColor; void main() { FragColor = vec4(1.0f,0.5f,0.2f,1.0f); }
效果: