본문 바로가기

카테고리 없음

OpenGL을 사용한 로봇 그리기

    if(_ogl_wnd) {
        _ogl_wnd->OnDestroy ();

        delete _ogl_wnd;
        _ogl_wnd = NULL;
    }

Windows에서 3D로 뭔가를 표현하고자 할 때 OpenGL 아니면 DirectX를 사용하게 됩니다. 여기서는 OpenGL을 사용하여 로봇의 주행을 3D로 표현해 보도록 하겠습니다. 먼저 예제 코드를 참조하시기 바랍니다.    

ExOpenGL.zip
0.07MB

 

예제 코드에서 로봇을 그리는 부분을 수정하면 다양한 로봇 모양들을 만들어 낼 수 있습니다. 분 예제코드는 로봇의 형태를 보여주기만 하며, 로봇의 움직임을 시뮬레이션 하지는 않습니다. 로봇의 움직임을 시뮬레이션 하기위해서는 ODE나 PhysX같은 물리 라이브러리가 필요합니다.

 

 

 

OpenGL 윈도우 조작 명령

 

마우스를 사용하여 OpenGL 윈도우를 조작하는 방법은 다음과 같습니다.

  • 마우스 왼쪽 버튼 클릭 후 이동 – 로봇을 좌우, 상하로 회전합니다.
  • 마우스 오른쪽 버튼 클릭 후 이동 – 로봇을 좌우, 상하로 이동합니다.
  • 마우스 스크롤 이동 – 로봇의 원근을 조절합니다.

OpenGL 관련 파일

 

예제코드에서 OpenGL과 관련된 파일은 아래 5개 파일입니다.

 

OglCommon.h - OpenGL을 사용하기 위한 일반적인 것들을 정의해 둡니다.

OglObjects.h/cpp - 입체 도형들(큐브, 실린더, 캡슐, 구 등등...)을 그리기 위한 함수들이 있습니다.

OglWnd.h/cpp - OpenGL 윈도우를 만들고 마우스 이벤트에 따라 뷰를 변환하는 함수들이 정의/구현된 클래스입니다.

 

사용자 클래스의 정의

 

상기 파일을 사용할 때는 COglWnd 클래스를 상속받아 사용자 클래스를 만듭니다.

 

OglWndExt.h

#pragma once
#include "OglWnd.h"

class COglWndExt : public COglWnd
{
public:
    COglWndExt (double eyeDist, double rotHor, double rotVer);
    virtual ~COglWndExt ();

    void TransformAxis(double x, double y, double z, double yaw, double pitch, double roll);

    virtual void OnDraw ();
    virtual void OnHits (int name);

public:
    // 로봇의 위치와 방향
    double _x, _y, _theta;
};

 

COglWnd 클래스에는 virtual 함수가 2개 있습니다. 첫번째 onDraw() 함수는 사용자가 그려야 할 것들을 오버라이딩 하는 가상함수입니다. 두 번째 onHist() 함수는 마우스 클릭으로 객체를 선택하였을 때 선택된 객체의 이름(ID)를 리턴하는 가상함수입니다.

 

OglWndExt.cpp 

void COglWndExt::OnDraw()
{
    int ID = 1;

    // 뷰포트를 설정한다.
    SetViewport ();

    // 바닥의 격자를 10 x 10 m, 눈금 1m로 그린다.
    oglPlane (10., 1.);

    // 여기서부터 Robot을 그린다.

    // 로봇의 위치(_x, _y, _theta)로 좌표계를 변환한다.
    TransformAxis (_x, _y, 0, _RAD2DEG*_theta, 0, 0);

    // 로봇의 좌표계를 그린다.
    oglCoordinate (1.0);

    // 로봇의 몸체(box)를 그린다.
    glLoadName (ID++);
    glPushMatrix();
        glTranslated (-0.2, 0., 0.4);
        glColor3d(0.5, 0.5, 1.0);
        oglBox (1.0, 0.7, 0.5);
    glPopMatrix();

    ...
}

void COglWndExt::OnHits (int name)
{
    TRACE ("Name of the hit(glLoadName): %d \n", name);
}

 

 OnDraw() 함수 내부에서는 뷰포트를 설정하고 바닥의 격자를 그립니다. 그리고 로봇의 위치와 방위(_x, _y, _theta)로 좌표를 변환하고 로봇을 그립니다. onHits() 함수에서는 클릭된 객체의 이름(ID)를 Visual Studio의 Output 창에 출력 하도록 합니다.

 

사용자 클래스의 사용

 

사용자 클래스는 COglWndExt 클래스입니다. 먼저 사용자 클래스를 생성하는 부분입니다.

#include "OglWinExt.h"

COglWndExt  *_ogl_wnd = NULL;

...

    CRect rect;
    GetDlgItem(IDC_OPENGL_VIEW)->GetWindowRect(rect);
    GetDlgItem(IDC_OPENGL_VIEW)->DestroyWindow();

    ScreenToClient(rect);

    _ogl_wnd = new COglWndExt(5., 0, 35);
    _ogl_wnd->CreateEx(0, "#32770", "Robot View", WS_TABSTOP | WS_CHILD | WS_VISIBLE, rect, this, IDC_OPENGL_VIEW);
    _ogl_wnd->ShowWindow(SW_SHOW);
    _ogl_wnd->SetFocus ();

상기 소스에서 IDC_OPENGL_VIEW로 정의된 윈도우즈 객체의 영역을 얻어와 OpenGL 윈도우를 생성하는 것을 볼 수 있습니다. 그리고 COglWndExt의 객체를 new로 생성할 때 첫번째 인자는 y축 음의 방향에서 바라보는 눈의 위치이고 두번째와 세번째 인자는 수평과 수직으로 물체를 회전한 각도(degree)입니다.

 

이제 윈도우즈 타이머 이벤트를 받아서 로봇의 위치와 방위를 업데이트 하고 OpenGL로 그려줍니다.

    double dt = 0.03;
    static double theta = 0;
    static double v = 1.5;

    theta += 1.0*dt;

    _ogl_wnd->_x += v*cos(theta)*dt;
    _ogl_wnd->_y += v*sin(theta)*dt;
    _ogl_wnd->_theta = theta;

    _ogl_wnd->UpdateWnd();
 

마지막으로 윈도우가 종료되는 시점에서 생성한 객체를 삭제하면 됩니다.

 

COglWnd 클래스는 따로 설명하지 않겠습니다.

 

* 2012/2/6 버그 수정사항

윈도우 생성시 획득한 DC를 SwapBuffers() 함수로 넘겨주면 OpenGL 화면이 업데이트 되지 않는 경우가 있습니다.

그래서 OglWnd.cpp 파일 내의 SwapBuffers(_dc->m_hDC); 를 SwapBuffers(dc.m_hDC); 로 수정하였습니다.