[C++] 1.2 기본적인 그리기 - 이동, 회전, 애니메이션
카테고리: C++ games
태그: Cpp Graphics OpenGL Programming
인프런에 있는 홍정모 교수님의 홍정모의 게임 만들기 연습 문제 패키지 강의를 듣고 정리한 필기입니다. 😀
🌜 공부에 사용된 홍정모 교수님의 코드들 보러가기
🌜 [홍정모의 게임 만들기 연습 문제 패키지] 강의 들으러 가기!
Chapter 1. 기본 기능 구현
1.2 기본적인 그리기 - 이동, 회전, 애니메이션
이번 실습 에서는 Game2D 클래스에서 draw_grid
값을 true 로 바꾸는 것을 권장!
원점에 검은 점 그리기
DrawFunction.h
using vec2 = Vector2<float>;
vector2.h
template<typename T>
class Vector2
{
public:
union {
struct { T x, y; };
struct { T v0, v1; };
T data[2];
};
main.cpp
namespace jm
{
class RotatingStarExample : public Game2D
{
public:
void update() override
{
const vec2 point = vec2(0.0f, 0.0f); // 점의 위치 지정 (원점)
drawPoint(Colors::black, point, 5.0f); // 점 그리기 5.0f 크기로
}
};
}
int main(void)
{
jm::RotatingStarExample().init("This is my digital canvas!", 1280, 960, false).run();
return 0;
}
선 그리기
class RotatingStarExample : public Game2D
{
public:
void update() override
{
const vec2 p0(0.0f, 0.0f); // 시작점 (vector2 생성자로 구현)
const vec2 p1(0.5f, 0.5f);// 끝점
drawLine(Colors::red, p0, Colors::blue, p1);
// 첫번재점 레드, 두번째점 블루 -> 빨강에서 시작해서 끝으로 갈수록 블루인 선이 됨
}
};
삼각형 그리기
삼각형은 선이 3개 !
class RotatingStarExample : public Game2D
{
public:
void update() override
{
const vec2 p0(0.0f, 0.0f);
const vec2 p1(0.5f, 0.5f);
const vec2 p2(0.5f, 0.0f);
drawLine(Colors::red, p0, Colors::blue, p1);
drawLine(Colors::red, p1, Colors::blue, p2);
drawLine(Colors::red, p2, Colors::blue, p0);
}
};
평행이동 방법 1. 각 좌표 파라미터에 값을 더해주기
각 좌표 파라미터에 이동시킬 만큼 실수 값을 더해주면 된다.
class RotatingStarExample : public Game2D
{
public:
void update() override
{
const float dx = 0.1f; // dy도 추가해서 y좌표에 더해주면 y 방향 평행이동도 가능
const vec2 p0(0.0f + dx, 0.0f);
const vec2 p1(0.5f + dx, 0.5f);
const vec2 p2(0.5f + dx, 0.0f);
drawLine(Colors::red, p0, Colors::blue, p1);
drawLine(Colors::red, p1, Colors::blue, p2);
drawLine(Colors::red, p2, Colors::blue, p0);
}
};
평행이동 방법 2. 좌표 자체를 넘겨주기 + translate함수 사용
- 각 파라미터에 적용시키는건 번거로우니까 좌표 자체인 vec2객체를 넘겨주기
translate 함수
: 누적 해서 좌표 현재위치를 변경시킨다.
class RotatingStarExample : public Game2D
{
public:
void update() override
{
translate(0.1f, 0.0f);
// 점의 시작 위치가 (0.1f, 0.0f) 가 되어 이 아래에 작성한 모든 도형들이 (0.1f, 0.0f) 위치에서 그려지게 된다.
const vec2 p0(0.0f , 0.0f);
const vec2 p1(0.5f , 0.5f);
const vec2 p2(0.5f , 0.0f);
drawLine(Colors::red, p0, Colors::blue, p1); // vec2 p1을 넘겨줌
drawLine(Colors::red, p1, Colors::blue, p2); // vec2 p2을 넘겨줌
drawLine(Colors::red, p2, Colors::blue, p0); // vec2 p0을 넘겨줌
// 이 아래 3개의 선은 이제 (0.2f, 0.0f) 위치에서 그려진다. (translate은 누적되니까 한번 더 translate을 해주니 (0.2f, 0.0f)가 됨)
translate(0.1f, 0.0f);
drawLine(Colors::red, p0, Colors::blue, p1);
drawLine(Colors::red, p1, Colors::blue, p2);
drawLine(Colors::red, p2, Colors::blue, p0);
}
};
평행이동 방법 3. 좌표 자체를 넘겨주기 + beginTransformation, endTransformation 사용
- 어느 일정 부분안에서만 누적되게 하고 싶을 때.
beginTransformation()
과endTransformation()
의 사이에서 이루어진 변환들이 이 범위를 벗어나면 초기화된다.
class RotatingStarExample : public Game2D
{
public:
void update() override
{
beginTransformation(); // 여기서부터
translate(0.1f, 0.0f); // (0.1f,0.0f)에 그려지는 아래 3개의 실선
const vec2 p0(0.0f , 0.0f);
const vec2 p1(0.5f , 0.5f);
const vec2 p2(0.5f , 0.0f);
drawLine(Colors::red, p0, Colors::blue, p1);
drawLine(Colors::red, p1, Colors::blue, p2);
drawLine(Colors::red, p2, Colors::blue, p0);
translate(0.1f, 0.0f); // (0.2f,0.0f) 에 그려지는 아래 3개의 실선
drawLine(Colors::red, p0, Colors::blue, p1);
drawLine(Colors::red, p1, Colors::blue, p2);
drawLine(Colors::red, p2, Colors::blue, p0);
endTransformation(); // 여기까지만 누적이 적용된다 ! 이제 여기를 벗어나면 다시 원점인 (0.0f,0.0f) 으로 돌아감
translate(-0.1f, 0.0f); // (-0.1f, 0.0f) 에 그려지는 아래 3개의 실선
drawLine(Colors::red, p0, Colors::blue, p1);
drawLine(Colors::red, p1, Colors::blue, p2);
drawLine(Colors::red, p2, Colors::blue, p0);
}
};
박스 그리기
class RotatingStarExample : public Game2D
{
public:
void update() override
{
drawWiredBox(Colors::gold, 0.5f, 0.25f);
}
};
회전 : 원점 회전
rotate
함수는 원점에 대해서 회전한다.- 회전 하는 중심이 원점 기준임.
class RotatingStarExample : public Game2D
{
public:
void update() override
{
drawWiredBox(Colors::gold, 0.5f, 0.25f);
rotate(30.0f); // (0.0f, 0.0f) 현재 위치인 원점에 대해서 30도 회전
drawWiredBox(Colors::blue, 0.5f, 0.25f);
}
};
회전 : 그래픽스는 내부적으로 역순으로 실행된다. ⭐
class RotatingStarExample : public Game2D
{
public:
void update() override
{
drawWiredBox(Colors::gold, 0.5f, 0.25f);
// 파란색 상자는 그냥 rotate만 적용된 것
beginTransformation();
rotate(30.0f);
drawWiredBox(Colors::blue, 0.5f, 0.25f);
endTransformation();
// 빨간 상자는 translate 후에 rotate까지 함께 적용된 것
beginTransformation();
translate(0.25f, 0.0f); // translate이 코드 상 rotate보다 먼저 등장
rotate(30.0f); // rotate이 translate 코드에서 아랫줄에 위치.
drawWiredBox(Colors::red, 0.5f, 0.25f);
endTransformation();
}
};
- 사진에서 빨간 상자 주목 ! 코드 상으로는 translate을 먼저 한 후에 rotate을 하므로 이동 후 원점에 대해서 회전하는 그림이 나와햐 하는데 실제로 실행해보면 rotate을 먼저 하고 난 후에 translate 평행이동 한 그림이 나온다.
- 컴퓨터 크래픽스 API는 내부적으로 코드의 역순으로 실행되기 때문. 코드상
평행이동 → 회전
이여도 내부적으론 역순으로회전 → 평행이동
으로 실행된다.
- 컴퓨터 크래픽스 API는 내부적으로 코드의 역순으로 실행되기 때문. 코드상
- 단 draw, 그림을 그리는건 코드 순서 그대로 그려진다!
- 이동, 회전, scale 같은 것들만 코드의 역순으로 진행되는 것.
drawWiredBox(Colors::gold, 0.5f, 0.25f);
// 블루 박스는 코드 상으론 **평행이동->회전** 순 : 그러나 실제론 **회전 -> 평행이동** 순으로 실행됨*
beginTransformation();
translate(0.25f, 0.0f);
rotate(30.0f);
drawWiredBox(Colors::blue, 0.5f, 0.25f);
endTransformation();
// 블루 박스는 코드 상으론 **회전 -> 평행이동** 순 : 그러나 실제론 **평행이동->회전** 순으로 실행됨*
beginTransformation();
rotate(30.0f);
translate(0.25f, 0.0f);
drawWiredBox(Colors::red, 0.5f, 0.25f);
endTransformation();
원점이 아닌 점에 대해서 회전하고 싶을 때
1. 원점이 아닌 점이 원점에 위치할 수 있도록 물체를 통째로 들어서 옮기기
2. 원점에 위치한 상태에서 원점에 대해서 회전 시키고
3. 다시 원래 자리로 되돌려 놓기
1 . 원점이 아닌 점이 원점에 위치할 수 있도록 물체를 통째로 들어서 옮기기
setLineWidth(3.0f);
const vec2 center_of_rotation(-0.25f, 0.0f); // 이 점에 대해서 회전시키고 싶어.
translate(-center_of_rotation); // ⭐ 실행순서 3. (+0.25f, 0.0f)만큼 이동시킨다. 원점으로 이동시키기 위해.
drawWiredBox(Colors::gold, 0.5f, 0.25f); // 실행순서 1.
drawPoint(Colors::black, center_of_rotation, 10.0f); // 실행순서 2. 회전 중점으로 하고 싶은 점을 시각적으로 보기 위해 그 점을 그림.
2 . 원점에 위치한 상태에서 원점에 대해서 회전 시키고
setLineWidth(3.0f);
const vec2 center_of_rotation(-0.25f, 0.0f);
rotate(45.0f); // ⭐ 실행순서 4.
translate(-center_of_rotation); // 실행순서 3.
drawWiredBox(Colors::red, 0.5f, 0.25f); // 실행순서 1.
drawPoint(Colors::black, center_of_rotation, 10.0f); // 실행순서 2.
3 . 다시 원래 자리로 돌려놓기
- 이제 (0.25f, 0.0f) 좌표에 대해서 45도 회전하는 그림이 나오게 됐다.
- draw는 코드 순서대로 실행되나 코드상으로는 rotate가 translate보다 먼저 나왔음에도 불구하고 translate이 먼저 실행되고 rotate이 그 다음에 실행된다.
setLineWidth(3.0f);
const vec2 center_of_rotation(-0.25f, 0.0f);
translate(center_of_rotation); // ⭐ 실행순서 5. 다시 원래 자리로 돌려 놓기.
rotate(45.0f); // 실행순서 4.
translate(-center_of_rotation); // 실행순서 3.
drawWiredBox(Colors::red, 0.5f, 0.25f); // 실행순서 1.
drawPoint(Colors::black, center_of_rotation, 10.0f); // 실행순서 2.
크기 바꾸기 scale
scale(a, b)
: x 방향으로 a 배, y 방향으로 b 배로 크기를 바꿈
void update() override
{
setLineWidth(3.0f);
scale(2.0f, 0.25f); // x방향으로 2배, y방향으로 1/4배
drawWiredBox(Colors::blue, 1.0f, 1.0f);
}
rotation & scale & translate 함께 쓰기
namespace jm
{
class RotatingStarExample : public Game2D
{
public:
float time = 0;
void update() override
{
setLineWidth(3.0f);
rotate(time*90.0f); // scale -> rotate 으로 역순으로 실행되게 된다.
scale(2.0f, 0.25f);
drawWiredBox(Colors::blue, 1.0f, 1.0f);
time += this->getTimeStep();
}
};
}
void update() override
{
setLineWidth(3.0f);
scale(2.0f, 0.25f); // rotate 먼저 하고 그 다음에 scale 하기 때문에 결과가 다르다.
rotate(time*90.0f);
drawWiredBox(Colors::blue, 1.0f, 1.0f);
time += this->getTimeStep();
}
rotate 두번 하면 마치 자전과 동시에 공전 하는 느낌으로 회전한다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기