學習自:
https://learnopengl-cn.github.io/01%20Getting%20started/05%20Shaders/#_4
1 #include <glad/glad.h> 2 #include <GLFW/glfw3.h> 3 4 #include <iostream> 5 #include <cmath> 6 7 void framebuffer_size_callback(GLFWwindow* window, int width, int height); 8 void processInput(GLFWwindow *window); 9 10 // 設置窗體的寬度和高度 11 const unsigned int SCR_WIDTH = 800; 12 const unsigned int SCR_HEIGHT = 600; 13 14 const char *vertexShaderSource = "#version 330 core\n" 15 "layout (location = 0) in vec3 aPos;\n" 16 "void main()\n" 17 "{\n" 18 " gl_Position = vec4(aPos, 1.0);\n" 19 "}\0"; 20 21 const char *fragmentShaderSource = "#version 330 core\n" 22 "out vec4 FragColor;\n" 23 "uniform vec4 ourColor;\n" 24 "void main()\n" 25 "{\n" 26 " FragColor = ourColor;\n" 27 "}\n\0"; 28 29 int main() 30 { 31 // 初始化glfw 32 glfwInit(); 33 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 34 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 35 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 36 37 // 條件編譯語句,如果是蘋果系統? 38 #ifdef __APPLE__ 39 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X 40 #endif 41 42 // 創建glfw窗體 43 GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); 44 if (window == NULL) 45 { 46 std::cout << "Failed to create GLFW window" << std::endl; 47 glfwTerminate(); 48 return -1; 49 } 50 glfwMakeContextCurrent(window); 51 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 52 53 // glad: load all OpenGL function pointers 54 // --------------------------------------- 55 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) 56 { 57 std::cout << "Failed to initialize GLAD" << std::endl; 58 return -1; 59 } 60 61 // 創建並編譯着色器 62 // vertex shader 63 int vertexShader = glCreateShader(GL_VERTEX_SHADER); 64 //glShaderSource函數把要編譯的着色器對象作為第一個參數。 65 //第二參數指定了傳遞的源碼字符串數量,這里只有一個。 66 //第三個參數是頂點着色器真正的源碼。 67 //第四個參數我們先設置為NULL。 68 glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); 69 glCompileShader(vertexShader); 70 // 錯誤檢測 71 int success;//表示是否編譯成功 72 char infoLog[512];//存儲錯誤信息 73 glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); 74 if (!success) 75 { 76 glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); 77 std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; 78 } 79 // 片段着色器 80 int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 81 glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); 82 glCompileShader(fragmentShader); 83 // 錯誤檢測 84 glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); 85 if (!success) 86 { 87 glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); 88 std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; 89 } 90 // 將着色器鏈接為一個着色器對象 91 int shaderProgram = glCreateProgram(); 92 glAttachShader(shaderProgram, vertexShader); 93 glAttachShader(shaderProgram, fragmentShader); 94 glLinkProgram(shaderProgram); 95 // 錯誤檢測 96 glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); 97 if (!success) { 98 glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); 99 std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; 100 } 101 //在把着色器對象鏈接到程序對象以后,記得刪除着色器對象,我們不再需要它們了: 102 glDeleteShader(vertexShader); 103 glDeleteShader(fragmentShader); 104 105 // 設置頂點 106 float vertices[] = { 107 0.5f, -0.5f, 0.0f, // bottom right 108 -0.5f, -0.5f, 0.0f, // bottom left 109 0.0f, 0.5f, 0.0f // top 110 }; 111 //創建一個VAO——頂點數組對象(Vertex Array Object, VAO) 112 // VAO可以像頂點緩沖對象那樣被綁定,任何隨后的頂點屬性調用都會儲存在這個VAO中。 113 //創建VBO——頂點緩沖對象:Vertex Buffer Object,VBO 114 // 它會在GPU內存(通常被稱為顯存)中儲存大量頂點。 115 // 使用這些緩沖對象的好處是我們可以一次性的發送一大批數據到顯卡上,而不是每個頂點發送一次。 116 unsigned int VBO, VAO; 117 glGenVertexArrays(1, &VAO); 118 glGenBuffers(1, &VBO); 119 // 1.綁定VOA 120 glBindVertexArray(VAO); 121 // 2.把頂點數組復制到緩沖中供OpenGL使用 122 glBindBuffer(GL_ARRAY_BUFFER, VBO); 123 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 124 125 /* 126 GL_STATIC_DRAW :數據不會或幾乎不會改變。 127 GL_DYNAMIC_DRAW:數據會被改變很多。 128 GL_STREAM_DRAW :數據每次繪制時都會改變。 129 */ 130 131 // 3.設置頂點屬性指針 132 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); 133 glEnableVertexAttribArray(0); 134 135 glBindVertexArray(VAO); 136 137 138 // 循環渲染 139 // ----------- 140 while (!glfwWindowShouldClose(window)) 141 { 142 // 輸入 143 processInput(window); 144 145 // 渲染 146 // 清楚顏色緩沖 147 glClearColor(0.2f, 0.3f, 0.3f, 1.0f); 148 glClear(GL_COLOR_BUFFER_BIT); 149 150 // 記得激活着色器 151 glUseProgram(shaderProgram); 152 153 // 更新uniform,然后每個渲染迭代都更新這個uniform: 154 /* 155 首先我們通過glfwGetTime()獲取運行的秒數。 156 然后我們使用sin函數讓顏色在0.0到1.0之間改變, 157 最后將結果儲存到greenValue里。 158 */ 159 float timeValue = glfwGetTime(); 160 float greenValue = sin(timeValue) / 2.0f + 0.5f; 161 /* 162 用glGetUniformLocation查詢uniform ourColor的位置值。 163 如果glGetUniformLocation返回-1就代表沒有找到這個位置值。 164 165 注意,查詢uniform地址不要求你之前使用過着色器程序, 166 但是更新一個uniform之前你必須先使用程序(調用glUseProgram), 167 因為它是在當前激活的着色器程序中設置uniform的。 168 */ 169 int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor"); 170 //最后,我們可以通過glUniform4f函數設置uniform值。 171 glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f); 172 173 // 繪制三角形 174 glDrawArrays(GL_TRIANGLES, 0, 3); 175 176 // 交換緩沖並查詢IO事件 177 glfwSwapBuffers(window); 178 glfwPollEvents(); 179 } 180 181 // 取消分配的空間 182 glDeleteVertexArrays(1, &VAO); 183 glDeleteBuffers(1, &VBO); 184 185 // 終止,清除所有先前分配的GLFW資源。 186 glfwTerminate(); 187 return 0; 188 } 189 190 // glfw:點擊esc退出,可是刪掉這一塊前面的東西還會報錯,還是留着吧 191 void processInput(GLFWwindow *window) 192 { 193 if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) 194 glfwSetWindowShouldClose(window, true); 195 } 196 197 // 每當窗口大小發生變化(通過OS或用戶調整大小)時,都會執行此回調函數 198 void framebuffer_size_callback(GLFWwindow* window, int width, int height) 199 { 200 //確保視口與新窗口尺寸匹配; 請注意寬度和 201 //高度將遠遠大於視網膜顯示器上指定的高度。 202 glViewport(0, 0, width, height); 203 }