직사각형에 색상 입히기 예제
지난 글에 작성했던 내용을 한번 코드로 실습해보고자 한다.
우선 아래와 같이 색상을 입힌 직사각형 코드를 준비했다.
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "Shader_s.h"
#include <iostream>
float vertex_data[] = {
-0.5, -0.5, 1.0, 0.2, 0.2, 0.2, // 왼쪽 아래
0.5, -0.5, 1.0, 0.3, 0.3, 0.3, // 오른쪽 아래
-0.5, 0.5, 1.0, 0.4, 0.4, 0.4, // 왼쪽 위
0.5, 0.5, 1.0, 0.5, 0.5, 0.5, // 오른쪽 위
};
unsigned int index_data[] = {
0, 1, 2,
1, 2, 3
};
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 600, "Colored Rectangle", NULL, NULL);
glfwMakeContextCurrent(window);
// glad load
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "GLAD 로드 중 에러 발생\n";
return -1;
}
// Shader 생성
Shader shader("vertex_shader.vs", "fragment_shader.fs");
// VAO, VBO, EBO
unsigned int VAO, VBO, EBO;
// VAO 생성 & Context에 바인딩
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
// VBO 생성, VAO에 바인딩, 데이터 소스 연결
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
// EBO 생성, VAO에 바인딩, EBO 소스 연결
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index_data), index_data, GL_STATIC_DRAW);
// Vertex Attribute 데이터 연결
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)0); // 위치
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float)*3)); // 색상
glEnableVertexAttribArray(1);
while (!glfwWindowShouldClose(window)) {
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
shader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
/*glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawArrays(GL_TRIANGLES, 1, 3);*/
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
셰이더 프로그램은 아래와 같이 작성했다.
// vertex_shader.vs
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out vec3 fragColor;
void main() {
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
fragColor = aColor;
}
// fragment_shader.fs
#version 330 core
in vec3 fragColor;
out vec3 aColor;
void main() {
aColor = fragColor;
}
이 소스코드를 컴파일하면 아래와 같은 직사각형이 나온다.
지난번 삼각형 예제와 다른점은 색상이 추가된 점 하나이다.
float vertex_data[] = {
-0.5, -0.5, 1.0, 0.2, 0.2, 0.2, // 왼쪽 아래
0.5, -0.5, 1.0, 0.3, 0.3, 0.3, // 오른쪽 아래
-0.5, 0.5, 1.0, 0.4, 0.4, 0.4, // 왼쪽 위
0.5, 0.5, 1.0, 0.5, 0.5, 0.5, // 오른쪽 위
};
vertex_data 에서 정점 정보에 더해 색상 RGB 정보도 같이 전달하였다.
물론 이에 맞게 AttribPointer도 코드를 수정했다.
// Vertex Attribute 데이터 연결
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)0); // 위치
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float)*3)); // 색상
glEnableVertexAttribArray(1);
Attrib 번호 0에는 위치정보를, 1에는 색상정보를 저장하였다.
이 값은 vertex shader로 넘어간다.
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
지난 글에서 설명했듯, Attirb 번호가 그대로 location으로 들어간다.
out vec3 fragColor;
void main() {
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
fragColor = aColor;
}
vertex_shader가 입력받은 색상 벡터는 그대로 fragColor 라는 변수를 통해 내보내진다.
#version 330 core
in vec3 fragColor;
out vec3 aColor;
void main() {
aColor = fragColor;
}
그리고 이 변수는 fragment_shader의 입력값으로 들어와 그대로 색상값을 출력하도록 한다.
(fragColor 라는 동일한 이름을 사용한 것에 주목하자!)
Uniform 변수 사용해보기
이제 이 직사각형의 색상을 시간이 지날 때마다 실시간으로 바꿔보자.
시간이 지날 때마다 실시간으로 색상을 바꾸려면 시간의 변화에 따라 색상값을 실시간으로 바꿔야한다.
이를 위해서는 CPU에서 시간에 따라 색상값을 생성하여 이 값을 GPU에 넘겨야 한다.
이때 활용하는 것이 바로 uniform 변수이다.
// Uniform 변수 생성 & 색상 초기값 세팅
int colorUniformLoc = glGetUniformLocation(shader.ID, "uniformColor");
glUniform3f(colorUniformLoc, 0.0, 0.0, 0.0);
main 함수에서 위와 같이 셰이더 프로그램에 uniform 변수를 정의해준다.
glCreateProgram 함수를 사용하면 그 반환값이 int 형이므로 그대로 사용하면 되고, Shader 클래스를 사용하는 경우, shader.ID를 사용하여 매개변수로 넘겨주면 된다.
변수에 값을 할당할 때는 glUniform3f() 와 같은 함수로 타입을 지정하고, 함수 매개변수로 값을 넘기면 된다.
shader.use();
glUniform3f(colorUniformLoc, 1.0, 0.0, 0.0); // 렌더링 루프에서 uniform 변수값을 지정해야 함.
유니폼 변수에 값을 할당하는 작업은 꼭 렌더링 루프 안에서 실행하자.
렌더링 루프 밖에서만 실행하고, 루프 안에서 실행하지 않으면 색상값이 입혀지지 않는다.
#version 330 core
// in vec3 fragColor;
out vec3 aColor;
uniform vec3 uniformColor;
void main() {
// aColor = fragColor;
aColor = uniformColor;
}
색상값을 사용할 fragment_shader 소스코드는 위와같이 바꿔주었다.
다음은 실행결과이다.
아주 쨍한 빨간색이 잘 나온다.
이제 시간이 지나면서 이 색이 동적으로 바뀌게 해보자.
시간에 따라 RGB 중 R 값을 다르게 설정해야 한다.
double time = glfwGetTime();
float redColor = abs(sin(time));
glUniform3f(colorUniformLoc, redColor, 0.0, 0.0); // 렌더링 루프에서 uniform 변수값을 지정해야 함.
해당 코드는 위와 같이 쓸 수 있다.
시간 값을 X축으로 하는 sin 함수를 그리고, 음수값을 무시하기 위해 절댓값을 취해준다.
시간이 지날 때마다 사각형의 색상이 바뀐다.
'CS > HCI 윈도우즈프로그래밍' 카테고리의 다른 글
[OpenGL] 11. Shader (7) - Texture Wrapping, Filtering, MipMaps (1) | 2024.04.12 |
---|---|
[OpenGL] 10. Shader (6) - Texture (0) | 2024.04.11 |
[OpenGL] 8. Shader (4) - GLSL (0) | 2024.04.09 |
[OpenGL] 7. Shader (3) - EBO (Element Buffer Object) (0) | 2024.04.08 |
[OpenGL] 6. Shader (2) - VAO (1) | 2024.04.07 |