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)


留言
張貼留言