이번에는 화면상의 물체(점, 선, 폴리곤, 그리고 이들의 조합으로 이루어진 것들)을 움직여 보고 회전 시켜 보며 크기를 변경하는 것에 대해서 살펴보자. 이 장은 1장의 소스에서 출발을 한다.
먼저 이동과 회전 그리고 크기를 조절할 대상이 되는 간단한 물체를 생성해 보자. 뭐가 좋을까? 정육면체로 하자. 정육면체는 면이 6개이며 꼭지점이 8개인 물건(?)이다. 꼭지점이 8개 이므로 우리는 8개의 좌표를 알고 있어야 한다. 다음의 코드는 화면상에 정육면체를 그려주는 glDrawGLScene 함수의 코드이다.
int DrawGLScene(GLvoid) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f,0.0f,-10.0f); glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_LINE_LOOP); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glEnd(); glBegin(GL_LINE_LOOP); glVertex3f(-1.0f, 1.0f, -1.0f); glVertex3f(1.0f, 1.0f, -1.0f); glVertex3f(1.0f, -1.0f, -1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glEnd(); glBegin(GL_LINES); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glVertex3f(1.0f, 1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); glVertex3f(1.0f, -1.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glEnd(); return TRUE; }
2장을 충분이 이해하고 있다면 전혀 어려운 부분이 없다. 이해가 가지 않는 독자가 있다면 2장을 보기 바란다. 코딩을 끝마친후 실행해보자. 다음은 그 실행 결과이다.
혹시 이런 질문을 던지는 독자가 있을지도 모르겠다. 정육면체라고 했는데 앞면과 뒷면의 크기가 다르지 않는가?라고… 답부터 말하자면 앞면과 뒷면의 크기는 분명이 동일하다. 달라보이는 이유는 좀더 사실적인 연출을 위해 원근감이 적용되었기 때문이다.
자, 이제 물체의 이동, 회전, 크기조절(스케일)을 할 물체가 준비되었다.
먼저 독자에게 주지 시켜야 할것이 있다. 그것은 필자가 말한 물체의 이동, 물체의 회전, 물체의 크기조절이라는 말에서 풍기는 의미전달의 오류를 바로 잡고자 한다. OpenGL에서는 이러한 작업을 좌표체계를 변경함으로써 이루어진다는 것이다. 즉 물체의 이동에 있어서 실제로 물체를 이동하는 것이 아니고 좌표축을 이동시킨후에 물체를 그려주는 것이다. 회전도 마찬가지이다. 먼저 좌표축을 지정된 각으로 회전시킨후에 그 회전 좌표축 상에 물체를 그려주는 것이다. 결국 우리가 원하는 상태의 물체를 얻을 수 있다는 것이다. 자 지금까지의 모든 것을을 이해했다면 이제 실제 우리가 원하는 것들을 해보자!!
먼저 물체를 이동시켜보자. 왼쪽으로 1.0만큼, 위쪽으로 1.0만큼 좌표체계를 이동시키는 것은 어떻게 될까? 바로 다음 한줄의 코드가 그러한 일을 한다.
glTranslatef(1.0f, 1.0f, 0.0f);
glTranslatef 함수의 첫번째 인자는 X축으로 이동값, 두번째와 세번째는 각각 Y축과 Z축으로의 이동값이다. 이 함수를 어디에 위치시켜야 하는가? 바로 물체를 그려주기 바로 전에 사용하면 되겠다. 다음 코드의 <*> 코드가 그 주인공이다.
int DrawGLScene(GLvoid) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f,0.0f,-10.0f); glColor3f(1.0f, 1.0f, 1.0f); glTranslatef(1.0f, 1.0f, 0.0f); // <*> glBegin(GL_LINE_LOOP); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glEnd(); . . . return TRUE; }
아래는 실행 결과이다. 우리가 원하는 대로 물체가 이동되었음을 알수있다.
이제 물체를 회전시켜보는 것을 알아보자. Z축으로 45도 회전시켜보는 것으로 예를 들어보자. 다음은 좌표축을 Z축으로 45도 회전시키는 코드이다.
glRotatef(45.0f, 0.0f, 0.0f, 1.0f)
첫번째 인자는 회전각(60도)이고 나머지 인자들은 X,Y,Z축상의 값들이다. (0.0, 0.0, 1.0)이 Z축을 기준으로 회전한다는 의미데 회전을 할때는 반드시 회전축이 필요하다. 바로 (0.0, 0.0, 1.0)이 회전축을 지정해 주는 것이다. 원점에서 (0.0, 0.0, 1.0)을 잇는 선, 바로 이 선이 회전축인 것이다. 그렇다면 이 코드의 위치는 어디인가? 마찬가지로 물체를 그려주기 바로 전에 위치하면 되겠다.
int DrawGLScene(GLvoid) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f,0.0f,-10.0f); glColor3f(1.0f, 1.0f, 1.0f); glRotatef(45.0f, 0.0f, 0.0f, 1.0f); // <*> glBegin(GL_LINE_LOOP); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glEnd(); . . . return TRUE; }
다음은 실행 결과의 화면이다.
어떤가 생각했던 대로 회전이 이루어 졌는가?
이제 다음으로 물체의 크기조절에 대한 것에 대해 알아보도록 하겠다. 물체를 Y축으로 2배 늘려보자. 다른 좌표축보다 Y축으로 2배의 값으로 증가하는 좌표축을 구성하면 물체도 그에 따라 Y축으로 2배 늘어날 것이다. 바로 아래가 그러한 일을 하는 코드이다.
glScalef(1.0, 2.0f, 1.0f);
첫번째 인자는 X축 좌표값의 증가배수값이고 두번째와 세번째가 각각 Y, Z축의 좌표값의 증가 배수이다. 두번째 값을 2.0으로 잡아줌으로써 Y축의 좌표축 값을 다른 축에 비해 2배로 증가하게 되는 것이다. 이 코드의 위치해야할 곳은 또 어디인가? 마찬가지로 물체를 그리기 바로 전에 위치하면 된다.
int DrawGLScene(GLvoid) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f,0.0f,-10.0f); glColor3f(1.0f, 1.0f, 1.0f); glScalef(1.0, 2.0f, 1.0f); glBegin(GL_LINE_LOOP); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glEnd(); . . . return TRUE; }
또 다음은 그 실행 결과이다.
어떤가. 우리가 원하는 대로 물체가 Y축으로 2배 길어졌다.
이로써 물체의 이동, 회전, 스케이링에 대한 장을 마치겠다.
open gl 어렵기만 했는데 많이 배웁니다. 감사합니다.
softjung님, 도움되셨다니 좋구요, 아울러 댓글 감사합니다~ ^^
앗 댓글 쓰는데가 여기 있었구나… 쓰는데를 몰라서 메일로 보냈는데
다시한번 감사의 인사를 드립니다.
운영자님 엄청난 고수이신듯… 많은 조언 바랍니다.
태환님, 메일 확인했습니다. 궁금하신 점은 댓글을 통해 해주시면 가장 빠르게 답변 해드릴 수 있을듯합니다. 그리고, 저보다 잘하시는 분들이 많답니다. 그럼 좋은 좋은 성과 있으시길 바랍니다~ ^^
많이 배우고 갑니다.
glscal 같은 경우 원점을 기준으로만 확대 축소가 되는데요..
특정 영역 가령 위의 정육면체에서 모서리을 기준으로 확대할려면 어떻게 해야하나요??
이리저리 해바도 계속 원점만 기준으로 해서 확대가 되서요..
아침바다님, 댓글 감사합니다.
먼저 확대 중심 위치로 glTranslatef를 사용해서 이동하시구요. glScale로 확대하고, 처음 glTranslatef로 이동한 만큼 다시 glTranslatef로 복구해주면 될듯합니다.
형준님 말씀대로 테스트 해보고 있는데 생각보다는 쉽지가 않네요.
glTranslaterf한후에 glScale로 확대한 후에 처음 glTranslatef로 ‘-‘ 값만 붙이면 될줄 알았는데, glScale값이 적용되서 그런지 원위치로 돌아오지 않네요..^^”,
좀 더 연구를 해봐야겠습니다..^^
아침바다님, 오브젝트의 위치가 (x,y, z)라고 한다면, 일단 glTranslatef(-x, -y, -z) 한 후에.. 원하는 glScalef로 변환한후.. 다시 glTranslatef(x, y, z)로 해 보시기 바랍니다~
말씀하신데로 하니 잘되네요..^^ 감사 합니다.
마우스 선택 부분을 중심으로 확대/축소를 추가하고있는데 덕분에 삽질의 끝이 보입니다.
그런데 약간의 문제가 있어서, 또 글을 올립니다.
scale 변경 후에 다른 지점을 중심을 확대 할려니 영상이 이동을 하네요.
아무래도 수학 공부를 다시 해야겠네요…ㅋ
아침바다님, 잘되신다니 다행입니다. 이때를 위해 glPushMarix와 glPopMatrix가 필요합니다. 하나의 오브젝트에 대한 변형이 끝나면 다시 변환행렬을 이전 단계로 되돌릴 필요가 있습니다.
알려주신데로 이렇게 해봤는데요.
glPushMatrix();
glTranslatef(-x,0.0f,0.0f);
glScalef(0.0f + m_fScale,0.0f +1,0);
glTranslatef(x,0.0f,0.0f);
TestLine();
glPopMatrix();
생각처럼 되지 않네요..
X값이 변경 될 때마다 이동해서 scale 바뀌네요…음.
넘 1차원적 생각인가요?
좀더 많은 힌트 부탁드립니다..
감사합니다..진짜 도움이 많이되네요
네, 도움되셨다니 다행입니다. 댓글 감사드리구요.
많은 참고가 되는것 같습니다. 좋은 포스팅 해주셔서 감사합니다^^
네, 좋은 댓글 감사드립니다~
감사합니다 ^^;
많은 도움되었습니다. 언제나 감사합니다.
좋은 댓글, 저 역시 감사합니다.
이해가 쏙쏙 되네요.. 흑
꼭 사각형이 아니 임의의 모양대로 생긴 폴리곤의 경우 제자리에서 스케일을 하기 위해서 중점의 위치를 알아야 하는데 이 중점은 어떻게 구하죠?
무게 중심점(centroid)가 적당하겠지만.. 경험상으로 MBR(최서 경계 사각형)에 대한 중심점에 대해 회전해도 어색하지 않더군요.
항상감사드립니다.. 혹시라도 이 페이지 접으실 일 생기시면 백업좀 해주세여 ㅠㅠ
진짜 이렇게 좋은 오픈지엘강의 보기 힘듬..
댓글 감사드립니다..
정말 재미있게 배우고 갑니다.. 좋은 글 고맙습니다^^
OpenGL에 관심있어서 찾아다니다가 발견했습니다.
정말 정리를 잘해놓으셨네요.
감사합니다.~
좋은 말씀 감사드립니다 ^^