3D 엔진을 내손으로 직접 만들어보는 프로젝트!

 

3D 드로잉은 좀 더 풀어서 설명하면, 3차원 공간을 2차원 평면에 표현하는 과정이고,

2D 드로잉은 2차원 공간을 2차원 평면에 표현하는 과정이다.

따라서 3D 드로잉이 2D보다 조금 어려운게 아니라 많이! 더 어렵다.

 

어려운점1 : 투사!

3D 드로잉은 3차원 공간을 2차원 평면에 표현하기 위해 아래처럼 투사라는 과정이 추가로 들어간다.

투사를 표현한 그림. canvas라는 평면에 투사되어 우리눈에 보인다.

투사는 개념은 이해하기 쉽지만 막상 코딩을 하려고 하면 어질어질 해진다.

 

어려운점2 : 4x4 행렬연산 이해하기!

거기에다 물체의 회전, 이동등의 움직임을 효율적으로 계산하기 위해서 보통 행렬이 쓰이는데, 이게 또 난이도를 올리는 원인이된다. 게다가 3차원이면 3x3행렬이 쓰일거 같은데, "이동변환" 때문에 4x4행렬이 쓰이는점도 이해하기 쉽지 않다.

 

어려운점3 : 수많은 수학적인 용어들과 싸우기!

게다가 좌표계와 변환에 대한 내용이다 보니, 수학적으로 한없이 현학적으로 들어갈 수 있어, 관련자료를 공부하는 과정에서 쉽게 지치고 포기하게 되는 포인트가 된다.

오일러회전, 쿼터니언, 선형변환, 아핀변환, 물체좌표, 월드좌표, 카메라좌표, 스크린좌표, 직교좌표계, 호모지니어스(동차) 좌표계, 로컬좌표계, 글로벌좌표계, 포인트, 벡터 등등 이름만 들어도 어질어질 해진다 ㅠ

 

언어와 라이브러리 고르기

언어는 내 취향대로 C++을 골랐고,

아직 C++에서 native로 drawing을 지원하지 않기 때문에 SFML 라이브러리를 사용하기로 했다.

OS 및 개발환경에 따른 SFML초기환경 세팅은 여기를 참고하자. (필자는 Windows 10 / Visual Studio 2019 환경)

 

SFML로 기본적인 2D 드로잉 해보기

아래 코드를 입력해서 기본 drawing canvas를 띄워보자

#include <SFML/Graphics.hpp>
using namespace std;
using namespace sf;

int main(void)
{
	RenderWindow window(VideoMode(800, 600), "2D");

	while (window.isOpen())
	{
		Event e;
		while (window.pollEvent(e))
		{
			if (e.type == Event::Closed) window.close();
		}
		window.clear(Color::Blue);
		window.display();
	}
	return 0;
}

가장 간단한 기본 형태인데 왜 while문이 2개나 있는지 궁금하실 수 있는데, 아주 간단하게 언급하고 넘어가자면, while문 형태의 무한루프가 없으면 return 0;으로 프로그램이 바로 종료되어 버리기 때문이다, 그리고 움직임을 표현하려면 반복적으로 그려주는게 필요해서 기본적으로 while 무한루프형태가 필요하고, 창을 닫는등의 이벤트를 받기위해 간단한형태의 이벤트 루프가 필요하기 때문에  안쪽의 while루프 하나가 더 들어간다고 보면 된다. (이런 이벤트 루프가 없으면 창을 닫아도 c프로그램에서 알 방법이 없기 때문에 while문들을 다 벗어나서 return 0;으로 프로그램을 종료할 방법이 없다.)

실행결과

아래 코드를 입력해서, 랜덤색깔을 가진 점들을 랜덤위치에 표시해보자.

#include <SFML/Graphics.hpp>
using namespace std;
using namespace sf;

int main(void)
{
	RenderWindow window(VideoMode(800, 600), "2D");

	auto draw_dots = [&]()
	{
		for (int i = 0; i < 1000000; i++)
		{
			Vertex point(sf::Vector2f(rand()%800, rand()%600), Color(rand()%255, rand()%255, rand()%255));
			window.draw(&point, 1, Points);
		}
	};

	while (window.isOpen())
	{
		Event e;
		while (window.pollEvent(e))
		{
			if (e.type == Event::Closed) window.close();
		}
		window.clear(Color::Blue);
		draw_dots();
		window.display();
	}
	return 0;
}

랜덤 점찍기 실행결과

 

아래 코드를 입력해서, 랜덤색깔을 가진 선들을 랜덤위치에 표시해보자.

#include <SFML/Graphics.hpp>
using namespace std;
using namespace sf;

int main(void)
{
	RenderWindow window(VideoMode(800, 600), "2D");

	auto draw_lines = [&]()
	{
		for (int i = 0; i < 1000; i++)
		{
			Color c1 = Color(rand() % 255, rand() % 255, rand() % 255);
			Color c2 = Color(rand() % 255, rand() % 255, rand() % 255);
			sf::Vertex line[2] = { 
				{Vector2f(rand() % 800, rand() % 600), c1},
				{Vector2f(rand() % 800, rand() % 600), c2}, };
			window.draw(line, 2, Lines);

		}
	};

	while (window.isOpen())
	{
		Event e;
		while (window.pollEvent(e))
		{
			if (e.type == Event::Closed) window.close();
		}
		window.clear(Color::Blue);
		draw_lines();
		window.display();
	}
	return 0;
}

랜덤 선찍기 실행결과

 

반응형

+ Recent posts