티스토리 뷰
0. 개요
opengl에서 uniform variable을 이용하여 띄운 삼각형의 위치를 계속 바꾸어본다.
1. Uniform Variable이란
Uniform Variable은 전역 셰이더 변수다.
각 shader stage별로 값이 변하지 않기 때문에 uniform이라는 이름이 붙었다.
shader 내부에서 값을 변경할 수는 없고 선언 및 이용만 할 수 있다.
값 변경은 C++ 코드 사이드에서 진행한다.
2. Uniform Variable의 이용 흐름
다음과 같은 큰 흐름을 따른다.
- 셰이더 내부에서 Uniform Variable의 선언
- Uniform Variable의 location 가져오기
- Uniform variable에 접근하여 값 변경하기
여기서는 uniform variable을 이용하여 삼각형을 translate 해보겠다.
2.1. 셰이더 내부에서 Uniform Variable의 선언
Uniform Variable은 다음과 같이 셰이더 코드 내에서 정의할 수 있다.
uniform 커맨드를 붙여야 한다.
vertex shader 쪽에서 4x4 matrix를 선언하여 삼각형에 곱해 간단히 translate 하는 연산을 만들겠다.
// Shader 소스 코드 정의
const char* TriangleTranslationRunner::vShader =
"#version 330\n"
"layout (location = 0) in vec3 pos;\n"
"uniform mat4 model;\n"
"void main()\n"
"{\n"
" gl_Position = model * vec4(0.4 * pos.x, 0.4 * pos.y, 0.4 * pos.z, 1.0);\n"
"}\n";
2.2. Uniform Variable Location 가져오기
이제 우리가 작성할 CPU쪽에서 GPU에 선언된 model의 location을 가져와야 한다.
우선 다음과 같이 GLuint의 자료형을 가진 uniformModel을 선언하고
GLuint TriangleTranslationRunner::uniformModel = 0;
아래와 같이 model 명을 이용하여 location을 가져와야 한다.
(shaderProgram 컴파일 시점 이후에 진행 필요)
uniformModel = glGetUniformLocation(shaderProgram, "model");
2.3. Uniform variable에 접근하여 값 변경하기
이제 그러면 CPU쪽 코드에서 location에 접근하여 값을 할당할 수 있다.
나는 translate matrix를 계산하고 uniform model에 할당하는 식으로 구현했다.
glm::mat4 translateMatrix(1.0f); // identity matrix.
translateMatrix = glm::translate(translateMatrix, glm::vec3(triOffset, triOffset, 0.0f));
glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(translateMatrix));
이 때 glUniform~ 머시기 함수는 gpu쪽 uniform에 값을 할당하는 함수인데uiniform의 자료형에 따라 맞춰서 쓰면 된다.
https://registry.khronos.org/OpenGL-Refpages/gl4/html/glUniform.xhtml
과정을 요약하여 나타내면 다음과 같다.
전체 코드는 다음과 같다.
헤더 파일
//
// Created by ypp06 on 2025-02-14.
//
#ifndef TRIANGLETRANSLATIONRUNNER_H
#define TRIANGLETRANSLATIONRUNNER_H
#include "../base/IBaseRunner.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
class TriangleTranslationRunner : public IBaseRunner
{
public:
bool Run() override;
~TriangleTranslationRunner() override = default;
private:
GLFWwindow* ReadyGlfwGlewEnv();
void MoveTriangle();
void CreateTriangle();
void AddShader(GLuint targetProgram, const char* rawShaderCode, GLenum shaderType);
void CompileShaders();
static const GLint WIDTH, HEIGHT;
static GLuint VAO, VBO, shaderProgram;
static GLuint uniformModel;
static bool direction;
static float triOffset, triMaxOffset, triIncrement;
static const char* vShader;
static const char* fShader;
};
#endif //TRIANGLETRANSLATIONRUNNER_H
소스 파일
//
// Created by ypp06 on 2025-02-02.
//
#include "TriangleTranslationRunner.h"
#include <iostream>
#include <string.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
// 전역 변수 정의
const GLint TriangleTranslationRunner::WIDTH = 800;
const GLint TriangleTranslationRunner::HEIGHT = 600;
GLuint TriangleTranslationRunner::VAO = 0;
GLuint TriangleTranslationRunner::VBO = 0;
GLuint TriangleTranslationRunner::shaderProgram = 0;
GLuint TriangleTranslationRunner::uniformModel = 0;
bool TriangleTranslationRunner::direction = true;
float TriangleTranslationRunner::triOffset = 0.0f;
float TriangleTranslationRunner::triMaxOffset = 0.7f;
float TriangleTranslationRunner::triIncrement = 0.005f;
// Shader 소스 코드 정의
const char* TriangleTranslationRunner::vShader =
"#version 330\n"
"layout (location = 0) in vec3 pos;\n"
"uniform mat4 model;\n"
"void main()\n"
"{\n"
" gl_Position = model * vec4(0.4 * pos.x, 0.4 * pos.y, 0.4 * pos.z, 1.0);\n"
"}\n";
const char* TriangleTranslationRunner::fShader =
"#version 330\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
" color = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
// Add Shader to Program.
// Shader에 대해 1. source 지정, 2. compile, 3. targetProgram에 attach.
void TriangleTranslationRunner::AddShader(GLuint targetProgram, const char* rawShaderCode, GLenum shaderType)
{
GLuint targetShader = glCreateShader(shaderType);
const GLchar* code[1];
code[0] = rawShaderCode;
GLint codeLength[1];
codeLength[0] = strlen(rawShaderCode);
glShaderSource(targetShader, 1, code, codeLength);
glCompileShader(targetShader);
GLint result = 0;
GLchar eLog[1024] = { 0 };
glGetShaderiv(targetShader, GL_COMPILE_STATUS, &result);
if (!result)
{
glGetShaderInfoLog(targetShader, sizeof(eLog), NULL, eLog);
printf("Error compiling the %d shader: '%s'\n", shaderType, eLog);
return;
}
glAttachShader(targetProgram, targetShader);
return;
}
void TriangleTranslationRunner::CompileShaders()
{
shaderProgram = glCreateProgram();
if (!shaderProgram)
{
printf("Error creating shader program!\n");
return;
}
AddShader(shaderProgram, vShader, GL_VERTEX_SHADER);
AddShader(shaderProgram, fShader, GL_FRAGMENT_SHADER);
GLint result = 0;
GLchar eLog[1024] = { 0 };
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &result);
// 제대로 링크되지 않았다면.
if (!result)
{
glGetProgramInfoLog(shaderProgram, sizeof(eLog), NULL, eLog);
printf("Error linking program: '%s'\n", eLog);
return;
}
// Validate program.
glValidateProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_VALIDATE_STATUS, &result);
if (!result)
{
glGetProgramInfoLog(shaderProgram, sizeof(eLog), NULL, eLog);
printf("Error validating program: '%s'\n", eLog);
return;
}
uniformModel = glGetUniformLocation(shaderProgram, "model");
}
void TriangleTranslationRunner::CreateTriangle()
{
// NDC 좌표계에서 삼각형을 구성하는 vertex들의 위치.
GLfloat vertices[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
// VAO 생성 및 Bind - 이 밑에 생성되는 VBO들을 VAO에 자동으로 Bind.
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
// VBO 생성 및 Bind.
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Attribute 선언 및 활성화
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
// VBO binding 다시 정리해주기
glBindBuffer(GL_ARRAY_BUFFER, 0);
// VAO binding 다시 정리해주기
glBindVertexArray(0);
}
// return NULL if failed.
GLFWwindow* TriangleTranslationRunner::ReadyGlfwGlewEnv()
{
// init GLFW.
if(!glfwInit())
{
printf("GLFW init fail");
glfwTerminate();
return NULL;
}
// Setup GLFW window properties.
// OpenGL Version.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Core profile = No Backwards Compatible.
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Allow forward compatible.
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* mainWindow = glfwCreateWindow(WIDTH, HEIGHT, "Hello Window", NULL, NULL);
if (!mainWindow)
{
printf("glfwCreateWindow failed!");
glfwTerminate();
return NULL;
}
// Get Buffer Size Info.
int bufferWidth, bufferHeight;
glfwGetFramebufferSize(mainWindow, &bufferWidth, &bufferHeight);
// Set Context for GLEW to use.
glfwMakeContextCurrent(mainWindow);
// Allow modern extension feats.
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
printf("glew init failed");
glfwDestroyWindow(mainWindow); // 이 시점에서 window가 생성되었으니 지워야 한다.
glfwTerminate();
return NULL;
}
// Setup Viewport size.
glViewport(0, 0, bufferWidth, bufferHeight);
return mainWindow;
}
void TriangleTranslationRunner::MoveTriangle()
{
if (direction)
{
triOffset += triIncrement;
}
else
{
triOffset -= triIncrement;
}
if (abs(triOffset) >= triMaxOffset)
{
direction = !direction;
}
glm::mat4 translateMatrix(1.0f); // identity matrix.
translateMatrix = glm::translate(translateMatrix, glm::vec3(triOffset, triOffset, 0.0f));
glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(translateMatrix));
}
bool TriangleTranslationRunner::Run()
{
GLFWwindow* mainWindow = ReadyGlfwGlewEnv();
if (!mainWindow)
{
return false;
}
CreateTriangle();
CompileShaders();
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
// loop til window closed.
while (!glfwWindowShouldClose(mainWindow))
{
// Get + handle user input events.
glfwPollEvents();
// Clear window.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
MoveTriangle();
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(mainWindow);
}
glBindVertexArray(0);
glUseProgram(0);
return true;
}
Refs
https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetUniformLocation.xhtml
'그래픽스' 카테고리의 다른 글
[그래픽스] OpenGL Indexed Draw & Index Buffer (0) | 2025.02.18 |
---|---|
[그래픽스]Hello Triangle - OpenGL에서 삼각형 띄워보기 (0) | 2025.02.12 |
[그래픽스] Rendering Pipeline 개요 (2) | 2025.02.09 |
[그래픽스] Hello Window - GLEW/GLFW 이용하여 창 띄우기 (0) | 2025.02.06 |
[그래픽스] OpenGL과 GLEW/GLFW (0) | 2025.02.03 |
- Total
- Today
- Yesterday
- 밑바닥부터 시작하는 딥러닝
- RGB이미지
- 영상처리
- Andrew ng
- 자연어 처리
- 인덱스 이미지
- 컴퓨터 과학
- NLP
- 매트랩 함수
- 매트랩
- CS
- ML
- 영상구조
- 컴퓨터과학
- gradient descent
- 딥러닝
- CNN
- Neural Network
- 순환 신경망
- 사진구조
- 이미지
- 머신러닝
- 이미지처리
- rnn
- 신호 및 시스템
- 머신 러닝
- 이산 신호
- 신경망
- 연속 신호
- Logistic Regression
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |