본문 바로가기

Graphics Note

OpenGL 강좌 - 2. 삼각형 그리기(설정)

두번째 OpenGL 강좌로 남들 다 하는 삼각형 한번 그려보자. 삼각형 하나 그리는데 볼게 뭐가있나 싶겠지만, 삼각형만 그릴 줄 알면 사실 OpenGL 기초는 끝낸 샘이다. 머털도사가 머리털을 세울때 이미 모든 도법을 터득했던것 처럼...

처음 삼각형 그리는 방법에서 기본적으로 설명할 사항이 많아서 몇 번의 강좌에 걸쳐 설명하게될 것 같다. 우선 이번 강좌에서는 다음과 같은 내용을 배우게 될 것이다.


* 코드 구조

* OpenGL 어플리케이션 설정


기틀은 첫 번째 강좌에서 본 코드와 유사하며 조금씩 살을 붙여나갈 것이다. 먼저 메인 함수의 구조를 파악해보자.

(glfw 가 붙은 함수는 GLFW 라이브러리의 함수이다. 마찬가지로 glew는 GLEW, gl은 OpenGL의 함수.)

int main() {
	
	...

	// GLFW 초기화
	if (!glfwInit())
		exit(EXIT_FAILURE);

	// 윈도우 생성
	window = glfwCreateWindow(640, 480, "Tutorial 00: Test", NULL, NULL);
	...

	// 컨텍스트 생성
	glfwMakeContextCurrent(window);

	...

	// GLEW 초기화
	glewInit();

	// 어플리케이션의 초기화
	InitApp();

	// 주 렌더링 루프. 윈도우가 종료되기 전까지 반복한다.
	while (!glfwWindowShouldClose(window)) {
		...
	}

	// 윈도우 제거
	glfwDestroyWindow(window);

	// GLFW 종료
	glfwTerminate();

	return 0;
}

메인 함수의 핵심적인 코드만 남겨보았을 때, 코드는 크게 세 부분으로 나누어 생각할 수 있다.

- GLFW 윈도우 생성 및 앱 초기화

- 렌더링 루프

- 종료 코드


여기서 우리가 집중해야 할 부분은 InitApp 함수를 통한 앱 초기화 부분과 렌더링 루프 부분이다.

InitApp은 사용자 함수이며 어플리케이션에 종속적인 설정작업과 어플리케이션 실행에 필요한 여러 리소스를 생성하는 작업을 담당하며, 렌더링 루프에서는 이러한 설정 사항을 바탕으로 생성된 리소스들을 사용하여 렌더링을 한다.

이번 강좌에서는 어플리케이션 설정 방법과 그래픽 프로그램에서 핵심적인 역할을 하는 셰이더(shader)에 대해 소개할 것이므로 InitApp 함수만 살펴볼것이다.


그 전에 잠깐, 아까부터 자꾸 렌더링 렌더링 하는데... 렌더링(rendering)이 뭐란말인가? 사전적인 설명은

컴퓨터 프로그램을 사용하여 모델(또는 이들을 모아놓은 장면인 씬(scene) 파일)로부터 영상을 만들어내는 과정 - 위키

이다. 조금 쉽게 설명하자면 3D 모델들이 가상의 공간에 배치되어있을 때 가상의 카메라로 그 공간을 찍어서 '이미지'를 뽑아내는것을 렌더링이라 한다. 렌더링이 반복되고 3D 모델들이 움직인다면 '애니메이션'이 되는것이다.


이런 렌더링 과정에 대해서는 다음 강좌를 통해 소개하고.. 본격적으로 어플리케이션을 설정는 과정을 살펴보자.

bool InitApp() {
	// 클리어 색상(배경색) 지정
	glClearColor(1.f, 1.f, 1.f, 1.f);

	// 깊이 테스트 사용
	glEnable(GL_DEPTH_TEST);

	// 페이스 컬링 활성화. 앞면은 CCW방향
	glDisable(GL_CULL_FACE);
	glFrontFace(GL_CCW);

	// 폴리곤 모드 지정. 앞면은 폴리곤, 뒷면은 라인
	glPolygonMode(GL_FRONT, GL_FILL);
	glPolygonMode(GL_BACK, GL_LINE);

	...
}

위 코드는 InitApp 함수의 일부이다. OpenGL은 기본적으로 상태 기계(state machine)이다. 렌더링은 설정된 상태를 기반으로 이루어지므로 어떤 상태를 활성화 하거나 비활성화 하는것으로 렌더링 결과를 좌우할 수 있다. 한줄 한줄 잘 따라가보자.


glClearColor(1.f, 1.f, 1.f, 1.f);

우선 클리어 색상(배경색) 이라는것을 지정해줄 수 있다. OpenGL을 포함해서 대부분의 컴퓨터 그래픽스에서는 보편적으로 한 장면 혹은 한 프레임(frame)을 그리기 전에 화면을 지워주는 작업을 하는데, 이때 어떤 색상으로 지울지 지정하는 함수이다. Red/Blue/Green/Alpha의 0.0~1.0 범위의 실수값을 지정하면 된다.


glEnable(GL_DEPTH_TEST)

그려져야할 화면의 한 픽셀 색상값을 결정하는데 여러 도형이 후보가 된다면 가장 가까운 도형의 색상으로 픽셀의 색상을 결정하는것이 상식적인 결과이다. 아래 그림에서 검은 가로칸이 한 픽셀에 해당되는 부분이라 할 때, 도형을 어떤 순서로 그리든 화면의 픽셀은 빨간색이 나와야한다.



이것이 가능한 이유는 각 도형들이 가지고있는 깊이정보를 바탕으로 깊이 테스트를 하기 때문인데, 이러한 기능을 하기 위해서 GL_DEPTH_TEST를 활성화 해야 한다.


glDisable(GL_CULL_FACE);
glFrontFace(GL_CCW);

보편적인 컴퓨터 그래픽스 프로그램은 선/삼각형/사각형 등 기본 도형으로 모든것을 표현하는데, 성능 향상을 위해 도형의 뒷면은 그리지 않도록 설정할 수 있다. 이러한 기능을 은면 제거(back face culling)이라 하며 GL_CULL_FACE를 활성화 하거나 비활성화 하는것으로 설정 가능하다. 본 강좌에서는 명확한 확인을 위해 은면 제거는 하지 않는다. 대신 바로 아래서 설명할 폴리곤 모드로 앞면과 뒷면을 구분할 것이다.

그런데 어느쪽이 앞면인지 모호하다. 이를 지정해주는것이 glFrontFace 함수인데 시계방향(CW: Clockwise) 혹은 반시계방향(CCW: Counterclockwise)을 앞면으로 설정할 수 있다. OpenGL은 오른손좌표계를 사용하기 때문에 일반적으로 반시계방향을 앞면으로 지정한다.


glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_LINE);

폴리곤 모드란 도형(폴리곤)이 그려지는 모드를 말한다. 도형 내부를 채우거나(GL_FILL) 모서리 선만 그리거나(GL_LINE) 정점만 그릴 수 있다(GL_POINT). 본 강좌에서는 앞면은 채우고 뒷면은 선만 그리도록 해서 알아보기 쉽게 하였다.


GL함수를 통한 렌더링 설정은 훨씬 다양하고 상황에 따라 꽤 복잡하게 쓰이지만, 간단한 프로그램 수준에선 이정도로 충분하다.

이번 강좌는 여기서 끊고, 다음 강좌에서 셰이더 프로그램을 만드는 방법에 대해 소개하겠다.


강좌의 예제코드는 모두 github에 올려두었다.

https://github.com/alleysark/OpenGL-Tutorials