GLFW(2) - uniform
今天來用 OpenGL 畫一個呼吸燈,下面圖片的三角形顏色會隨著時間改變。
1. Header, shaders and vertices:
先加入會使用的函式庫、著色器及頂點座標。
於 Fragment shader 中定義一個 uniform 變數,透過 uniform 變數我們可以將顏色傳遞給 shader。
#include<iostream> using namespace std; #include<math.h> #include<GL/glew.h> #include<GLFW/glfw3.h> const GLchar* vertexShaderSource = R"glsl( #version 330 core layout (location = 0) in vec4 position; void main() { gl_Position = position; } )glsl"; const GLchar* fragmentShaderSource = R"glsl( #version 330 core uniform vec4 frag_color; out vec4 color; void main() { color = frag_color; // color = vec4(.3, .2, .1, 1.); } )glsl"; GLfloat vertices[] = { // First triangle -0.3, 0.01, 0.0, 1., 0.0, 0.5, 0.0, 1., 0.3, 0.01, 0.0, 1., // Second triangle 0.0, -0.5, 0.0, 1., -0.3, -0.01, 0.0, 1., 0.3, -0.01, 0.0, 1., }; GLuint indices[] = { 0, 1, 2, 3, 4, 5, };
2. 撰寫 key 事件:
新增一些按鍵偵測的流程,ESC 會關閉視窗、E 只畫出線條、F 會將顏色填滿。
void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } if (glfwGetKey(window, GLFW_KEY_F) == GLFW_PRESS) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } }
3. 編輯 main:
開個 800*600 的視窗,用 GLEW 進行初始化。
int main() { if (!glfwInit()) { return -1; } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif GLFWwindow *window = glfwCreateWindow(800, 600, "Hello GL", NULL, NULL); if (window == NULL) { cout << "Fail to create window" << endl; return -1; } glfwMakeContextCurrent(window); // load funcs glewInit();
將 shader 編譯成 program,簡單檢查一下編譯過程是否有問題。
// vertex shader unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader); int success; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) { cout << "Fail to create the vertex shader" << endl; return -1; } // fragment shader unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader); glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); if (!success) { cout << "Fail to create the fragment shader" << endl; return -1; } // link unsigned int shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { cout << "Fail to link" < endl; return -1; } glDeleteShader(vertexShader); glDeleteShader(fragmentShader);
準備 VAO, VBO 和 EBO。VAO 代表資料的拿法、VBO 代表資料 buffer、代表 index。
// vao vbo ebo unsigned int vao, vbo, ebo; glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glGenBuffers(1, &ebo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4*sizeof(GL_FLOAT), (void *)0); glEnableVertexAttribArray(0);
每一禎利用時間計算 sin 跟 cos 並設定顏色。
我們利用 glGetUniformLocation 取得變數然後用 glUniform4f 設定 uniform。因為 frag_color 是 vec4 所以用 4f 設定。
glViewport(0, 0, 800, 600); glClearColor(.1, .0, .3, 1.); while(!glfwWindowShouldClose(window)) { processInput(window); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(shaderProgram); double t = glfwGetTime(); float r = (sin(t) + 1.0) / 2.0; float g = (cos(t) + 1.0) / 2.0; unsigned int colorLocation = glGetUniformLocation(shaderProgram, "frag_color"); glUniform4f(colorLocation, r, g, 0., 1.); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glfwSwapBuffers(window); glfwPollEvents(); }
最後釋放所有資源。
// release glDeleteProgram(shaderProgram); glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo); glDeleteBuffers(1, &ebo); glfwTerminate(); return 0; }
2. Makefile:
簡單寫個 mac 的 makefile,linux 要微調 lib 的部分。
TARGET=main.out LIBS=-lglfw -lglew -framework OpenGL CFLAGS=-std=c++11 $(TARGET): main.cpp g++ $(CFLAGS) -o $@ $^ $(LIBS) .PHONY: clean clean: rm $(TARGET)
留言
張貼留言