Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 29 | 30 | 31 |
Tags
- 아트
- ShaderProgram
- opengl3.3
- opengl 3.3
- Texture2D
- string_view
- Codeforce
- Color struct
- gsls
- voronoi
- OpenGL
- shader
- C++
Archives
- Today
- Total
Longseabear DevLog
Shader program wrapper class 본문
Tutorial Shader code
기본적으로 opengl에서 사용할 shader code를 작성할 때 다음과 같이 작성한다.
- 각각의 Shader를 생성하고, comfile 한다.
- GLProgram 객체에 shader를 할당한다.
- 할당된 shader를 linking 한다.
- 기존 컴파일한 shader는 제거한다.
코드로는 다음과 같다.
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
현재 graphics 공부의 목표인 동적 shader 처리 구현을 위해서 해당 과정이 관리되어질 필요가 있다. 현재 사용중인 shader를 쉽게 관리할 수 있는 class가 있으면 좋을 것 같았다. 위의 과정을 ShaderProgram 이란 class로 새롭게 정리하여 구현하였다.
auto shaderProgramObject = LEapsGL::ShaderProgram();
shaderProgramObject.CompileFromFile( GL_VERTEX_SHADER, simpleVertexShaderPath)
.CompileFromFile(GL_FRAGMENT_SHADER, simpleFragmentShaderPath)
.MakeProgram();
-+원하는 목표는 위와 같이 chaning 형태의 method를 통하여 내가 원하는 shader를 할당하고, program을 만들도록 하는 것이다. 또한, 내부에서 현재 사용된 shader를 유지하고 있다가, 갈아 끼면서 다시 linking 할 수 있는 구조로 작성하고자 한다.
// ShaderManager.cpp
std::string LEapsGL::ReadFile(const char* filePath)
{
std::string content;
std::ifstream fileStream(filePath, std::ios::in);
if (!fileStream.is_open()) {
std::cerr << "Could not read file " << filePath << ". File does not exist." << std::endl;
return "";
}
std::stringstream buffer;
buffer << fileStream.rdbuf();
fileStream.close();
return buffer.str();
}
opengl 3.3에서 shader code 입력은 string으로 주어지기 때문에, source code를 string으로 리턴하는 코드를 우선 작성하였다.
ShaderManager.h
class ShaderProgram {
private:
struct ShaderInfo {
GLuint shaderType;
GLuint shaderId;
};
GLuint id = 0;
vector<ShaderInfo> registeredShader;
unsigned int getShaderIndex(GLuint shaderType);
public:
GLuint getID();
void setID(GLuint id);
friend void swap(ShaderProgram& a, ShaderProgram& b) {
using std::swap;
swap(a.id, b.id);
swap(a.registeredShader, b.registeredShader);
}
// Constructor
ShaderProgram() :id(glCreateProgram()){
}
ShaderProgram(GLuint _id) :id(_id) {
}
// Copy Constructor
ShaderProgram(const ShaderProgram& other) {
this->id = other.id;
registeredShader = other.registeredShader;
}
// Move constructor
ShaderProgram(ShaderProgram&& other) noexcept: ShaderProgram(0) {
swap(*this, other);
}
ShaderProgram& operator=(ShaderProgram other) {
swap(*this, other);
return *this;
}
ShaderProgram& operator=(ShaderProgram&& other) noexcept{
swap(*this, other);
return *this;
}
virtual ~ShaderProgram() {
DeleteShaderAll();
glDeleteProgram(id);
};
ShaderProgram& CompileFromFile(GLuint shaderType, const char* path);
ShaderProgram& CompileFromSourceCode(GLuint shaderType, const char* sourceCode);
ShaderProgram& MakeProgram();
ShaderProgram& DeleteShaderAll();
};
그 후, class를 구현하였다. class는 단순하게 생성되었을 때 opengl program id를 생성하고, vector를 통해 shader 정보를 관리한다.
Swap idiom을 통해 rule of five (생성자, 복사 생성자, 이동 생성자, 복사 할당자, 이동 할당자)를 구현하였다. 자세한 내용은 다음 링크를 확인하였다.
https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
ShaderManager.cpp
unsigned int LEapsGL::ShaderProgram::getShaderIndex(GLuint shaderType)
{
for (int i = 0; i < registeredShader.size(); i++) {
if (registeredShader[i].shaderType == shaderType) return i;
}
return -1;
}
ShaderProgram& LEapsGL::ShaderProgram::MakeProgram()
{
int state;
for (auto shaderInfo : registeredShader) {
glAttachShader(id, shaderInfo.shaderId);
}
glLinkProgram(id);
glGetProgramiv(id, GL_LINK_STATUS, &state);
if (!state) {
glGetProgramInfoLog(id, sizeof(infoLog), NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
return *this;
}
ShaderProgram& LEapsGL::ShaderProgram::DeleteShaderAll() {
for (auto shaderInfo : registeredShader) {
glDeleteShader(shaderInfo.shaderId);
}
return *this;
}
GLuint LEapsGL::ShaderProgram::getID() {
return id;
}
void LEapsGL::ShaderProgram::setID(GLuint id) {
this->id = id;
}
ShaderProgram& LEapsGL::ShaderProgram::CompileFromFile(GLuint shaderType, const char* path)
{
return LEapsGL::ShaderProgram::CompileFromSourceCode(shaderType, LEapsGL::ReadFile(path).c_str());;
}
ShaderProgram& LEapsGL::ShaderProgram::CompileFromSourceCode(GLuint shaderType, const char* sourceCode)
{
int state;
int idx = getShaderIndex(shaderType);
if (idx != -1) {
glDeleteShader(registeredShader[idx].shaderId);
}
else {
registeredShader.push_back({ shaderType, 0 });
idx = registeredShader.size() - 1;
}
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &sourceCode, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &state);
if (!state)
{
glGetShaderInfoLog(shader, sizeof(infoLog), NULL, infoLog);
std::cerr << "Compile fail!! ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
registeredShader[idx].shaderId = shader;
return *this;
}
정상 동작하는 것을 확인하였다.

'Graphics Project' 카테고리의 다른 글
| Voronoi noise 파헤치기 (0) | 2024.10.27 |
|---|---|
| 나만의 Texture2D class 만들기 (0) | 2023.02.01 |
| Color struct 만들기 (0) | 2023.01.31 |
| Opengl 3.3 시작 (0) | 2023.01.28 |