3D 엔진을 내손으로 직접 만들어보는 프로젝트!
3D 드로잉은 좀 더 풀어서 설명하면, 3차원 공간을 2차원 평면에 표현하는 과정이고,
2D 드로잉은 2차원 공간을 2차원 평면에 표현하는 과정이다.
따라서 3D 드로잉이 2D보다 조금 어려운게 아니라 많이! 더 어렵다.
어려운점1 : 투사!
3D 드로잉은 3차원 공간을 2차원 평면에 표현하기 위해 아래처럼 투사라는 과정이 추가로 들어간다.
투사는 개념은 이해하기 쉽지만 막상 코딩을 하려고 하면 어질어질 해진다.
어려운점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;
}