OpenGL 쉐이더 프로그래밍 - Hello Shader

타입·2025년 7월 21일

컴퓨터 그래픽스

목록 보기
4/24

GLSL: OpenGL Shader Language

C와 비슷한 High Level 언어 - main() 함수로 Shader Program 시작

  • 새로운 자료형 GLM
    GL Math 라이브러리

쉐이더 프로그래밍

OpenGL 쉐이더 프로그래밍 전체 과정

OpenGL 프로그램 컴파일 하여 exe 파일 생성
exe 파일 실행 후 Vertex Shader, Fragment Shader 소스코드 각자 컴파일
GPU는 각 Shader Program을 2개 동시 실행
메모리에서 user data를 vertex input으로 들어오면, 결국 framebuffer로 화면 출력

Shader Program 구조

Vertex Shader의 소스파일을 컴파일하여 obj 파일 생성
Fragment Shader의 소스파일을 컴파일하여 obj 파일 생성
Shader Program에서 각 obj 파일을 attach 후 Link하여 exe 파일 생성
Use하여 GPU에서 exe 파일 실행

vertex data를 제공하면 실행된 Vertex Shader Program과 Fragment Shader Program을 거쳐 결과 출력

쉐이더 프로그램 설계

Vertex Shader Program

vertex data를 정의하기 위해선 좌표계 필요
OpenGL에서 디폴트로 사용하는 좌표계는 x와 y 값이 (-1 ~ +1)로 제한

  • in: attribute register
  • out: varying register
  • gl_Position: pre-defined out
// OpenGL 3.3 버전의 코어 피쳐만 사용하는 Shader Program
#version 330 core

// input 레지스터 중 하나를 vertexPos라는 이름으로 사용
// vec4 타입으로 4개의 구성요소를 모두 사용
in vec4 vertexPos;

// input 레지스터의 vertexPos로 들어오는 내용을
// output 레지스터의 gl_Position으로 그대로 보냄
void main(void) {
	gl_Position = vertexPos; // gl_Position: vertex의 위치
}
  • layout 키워드
    레지스터 위치 강제 할당
    똑같은 레지스터를 두 변수가 사용하려고 하면 컴파일 에러 발생
// attribute 레지스터의 5번 위치에 할당
layout (location = 5) in vec4 vertexPos;

Vertex Shader 실행

(x,y,z,w) 4개씩 묶어 병렬 처리로 실행
동시에 실행하여 Vertex Shader 처리 후 Primitive Assembly 단계에서 삼각형으로 결합
이후 Rasterization 단계에서 삼각형 내부의 픽셀에 대해 Fragment Shader로 전달

GLfloat vertPos[] = {
	-0.5F, -0.5F, 0.0F, 1.0F, // processor #1 실행
	+0.5F, -0.5F, 0.0F, 1.0F, // processor #2 실행
	-0.5F, +0.5F, 0.0F, 1.0F, // processor #3 실행
};

Fragment Shader Program

  • in: varying registers
  • out: framebuffer update
  • gl_FragCoord: pre-defined in (Fragment Coordinate)
#version 330 core

// output 레지스터를 FragColor라는 이름으로 사용
// vec4(4차원) 타입으로 설정
out vec4 FragColor;

void main(void) {
	FragColor = vec4(1.0, 0.0, 0.0, 1.0); // Red Color (RGBA)
}

Fragment Shader 실행

여러 픽셀에 대해서 동시에 병렬 처리
각 픽셀마다 Fragment Shader를 가져다 붙여 똑같은 프로그램이 실행
결국 모든 픽셀이 빨간색으로 보이게 됨

예제 코드 분석

initFunc()

  • 각 Shader 프로그램의 소스코드를 C++에서 넘겨주기 위해 문자열로 작성
const char* vertSource = 
"#version 330 core \n\
in vec4 vertexPos; \n\
void main(void) { \n\
	gl_Position = vertexPos; \n\
}";

const char* fragSource = 
"#version 330 core \n\
out vec4 FragColor; \n\
void main(void) { \n\
	FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n\
}";

GLuint vert = 0; // vertex shader ID number
GLuint frag = 0; // fragment shader ID number
GLuint prog = 0; // shader program ID number
  • Vertex Shader와 Fragment Shader를 컴파일하여 실행하는 과정
void initFunc(void) {
	// vert: vertex shader
	vert = glCreateShader(GL_VERTEX_SHADER); // 어느 타입의 Shader 오브젝트를 만들지 결정, shaderID를 반환
	glShaderSource(vert, 1, &vertSource, NULL); // 문자열 형태의 소스코드를 다운로드
	glCompileShader(vert); // 컴파일하여 obj 파일 생성
    
	// frag: fragment shader
	frag = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(frag, 1, &fragSource, NULL);
	glCompileShader(frag);
    
	// prog: program
	prog = glCreateProgram(); // Shader Program 생성, programID를 반환
	glAttachShader(prog, vert); // 프로그램에 Shader를 연결
	glAttachShader(prog, frag); // 한 프로그램엔 Vertex/Fragment Shader 필요
	glLinkProgram(prog); // obj 파일을 exe파일로 제작
    
	// execute it!
	glUseProgram(prog); // 프로그램을 GPU에서 실행
}

drawFunc()

  • GPU에 vertex data를 전달하여 실제로 draw하는 과정
void drawFunc(void) {
	// clear in gray color
	glClear(GL_COLOR_BUFFER_BIT);
    
	// provide the vertex attributes
	GLuint loc = glGetAttribLocation(prog, "vertexPos"); // vertexPos 이름을 쓰는 레지스터의 위치 반환
	glEnableVertexAttribArray(loc); // 해당 위치의 레지스터 활성화
	glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, 0, vertPos); // Vertex Shader의 input으로 전달
    
	// draw a triangle
	glDrawArrays(GL_TRIANGLES, 0, 3); // 0번째부터 3개의 데이터를 삼각형으로 해석
    
	// done
	glFinish(); // 커맨드 큐의 모든 명령 실행
}

OpenGL Manuals
https://www.opengl.org
https://registry.khronos.org/OpenGL-Refpages/gl4/

profile
주니어 언리얼 프로그래머

0개의 댓글