OpenGL

코승호딩·2022년 9월 28일
0
post-thumbnail

📌개요

OpenGL이란 실리콘 그래픽스사에서 만든 2차원 및 3차원 그래픽스 표준 API이다. 이 API는 약 250여개 가량의 함수를 호출하여 단순 기하 도형부터 복잡한 삼차원의 도형 및 장면을 생성할 수 있다. 현재는 가상현실, 비행 시뮬레이션, 컴퓨터 게임 분야 등에서 널리 사용중이다. 이번 OpenGL을 공부하며 최종적으로 3차원의 게임 프로젝트를 진행할 예정이다. 주의할 점은 OpenGL은 오른손 좌표계를 사용하며 열벡터이다.


📌OpenGL 그래픽스 파이프라인


위 사진은 OpenGL의 파이프라인을 보여준다. 이 중 이번 프로젝트를 위해 우리는 버텍스 셰이더와 프레그먼트 셰이더를 중점으로 다룰 것이다.
이 두 셰이더의 특징은 프로그래머가 직접 프로그래밍을 할 수 있다는 점이다.
게임 공간 속 모든 모델은 정점을 가지고 있고 그에 따른 픽셀 값을 가지며 색을 표현하여 최종적으로 2D 스크린으로 보여준다.

모델의 정점, 좌표값을 조작하며 노말값, 텍스처 좌표값 등을 조작할 수 있는 기능을 수행해 주는 것이 버텍스 셰이더이다.
모델의 색상, 재질, 라이팅, 깊이 값을 결정하는 것이 프레그먼트 셰이더이다. 우리는 이 셰이더에서 색상을 결정할 수 있다.

이 두가지 셰이더를 메인 프로그램과 따로 분리하여 작성한다.
든 정점 및 속성 정보를 배열로 지정하며 Vertex Buffer Object와 Vertex Array Object를 사용한다.
이 배열을 GPU에 보내어 저장하고 렌더링에 사용하는 것이다.


📌Shader 프로그램 구조

#version version_number //--- 사용 버전 선언

in type in_variable_name; //--- 변수 선언
out type out_variable_name; 
uniform type uniform_variable_name; 

void main(void) //--- 메인 함수: 인자값 없음
{ 
	//--- 입력 값을 처리
	//--- 필요한 그래픽 작업 수행
	... 
	//--- 출력 변수 저장
	out_variable_name = output data; 
}

셰이더의 구조는 다음과 같으며 몇가지 특징이 있다.
1. C와 비슷한 기본 문법
2. 포인터의 개념이 없음 -> 동적 할당이 없음
3. C언어의 구조체 사용이 가능
4. 매트릭스나 벡터는 기본 형으로 함수에서 입력이나 반환으로 출력이 가능


Vertex Shader

#version 330 core

in vec3 vPos;

void main ()
{
	gl_Position = vec4 (vPos.x, vPos.y, vPos.z, 1.0);
}

정점 셰이더는 그리기 명령어에 의해 Vertex Array Object로부터 속성을 설정한다.
버텍스 변환 혹은 텍스처 좌표 설정을 담당하는 곳이다.


Fragment Shader

#version 330 core

out vec4 FragColor;

void main ()
{
	FragColor = vec4 (1.0, 0.0, 0.0, 1.0);
}

프래그먼트 셰이더는 레스터라이저 단계에서 생성된 프래그먼트를 일련의 색상과 깊이 값으로 처리한다.
색상을 설정하거나 조명을 설정한다.


GLSL 기본 문법

- 데이터 타입

  1. 기본 C언어 타입 : int, float, double, uint, bool
  2. 벡터 타입 : vecn / dvecn / bvecn / ivecn / uvecn (n은 인자 개수), 대응되는 구조체로 접근이 가능, 벡터의 요소들을 배열처럼 접근이 가능 ex) vec4 foo; -> float x = foo[0], 스위즐링(swizzling) : 특정 필드들을 묶어 벡터로 표현 가능
  3. 매트릭스 타입 : matn / matmxn / dmatn / dmatmxn (n, m은 행과 열의 개수), 열우선이다.
  4. 텍스처 샘플러 : 텍스처 값에 접근이 가능한 샘플러 타입이다. ex) sampler1D, sampler2D

- 생성자

  1. 변수의 초기화는 C++ 생성자 방식을 이용한다. ex) vec3 aPos = vec3(0.0f, 0.5f, 0.0f);
  2. 벡터 생성자는 저장할 값의 숫자를 지정한다. ex) vec3 position(1.0); -> vec3 position(1.0, 1.0, 1.0);
  3. 벡터는 하나의 스칼라 값을 지정하면 모든 요소에 할당함. ex) vec4 whiteColor = vec4(1.0); -> vec4 whiteColor(1.0, 1.0, 1.0, 1.0);
  4. 스칼라와 벡터, 행렬을 생성자 내에서 혼합해 사용할 수 있다. ex) vec4 aColor = vec4(r, vec2(g, b), a); -> vec4 aColor(r, g, b, a)
  5. 배열 생성자는 다음의 문법에 따라 생성자를 호출한다.
    const float array[3] = float[3] (2.5, 7.0, 1.5);
    const vec4 vertex[3] = vec4[3] (vec4(0.25, -0.25, 0.5, 1.0), vec4(-0.25, -0.25, 0.5, 1.0), vec4(0.25, 0.25, 0.5, 1.0));
  6. 행렬은 열 우선으로 구성되고, 단일 스칼라 값을 지정하는 경우 대각 행렬이 됨 (대각 요소 외에는 0으로 채워짐)
mat3 m = mat3 (
		1.1, 2.1, 3.1, //--- 첫번째 열
		1.2, 2.2, 3.2, //--- 두번째 열
		1.3, 2.3, 3.3, //--- 세번째 열
        );
mat3 m = mat3 (1.0); //--- 대각선이 1.0이고 다른 요소들은 0.0인 3x3 행렬 = 단위행렬

- 연산자

  1. 대부분의 연산자는 C언어의 우선순위 규칙과 동일하게 사용이 가능하다.
  2. 이항 연산은 요소별 연산으로 진행된다.
profile
코딩 초보 승호입니다.

0개의 댓글