반응형

OpenGL 렌더링 결과를 보여주기 위해 필요한 윈도우(UI)OpenGL 컨텍스트 생성을 MFC로 처리하는 방법을 설명합니다.


64비트 윈도우(x64)에서 OpenGL 2.x  API를 사용하여 프로그래밍을 하는 경우를 대상으로 하고 있습니다.

Visual Studio 2017 Community를 사용해서 진행했지만 다른 버전에서도 거의 동일하게 동작할 듯합니다.




이제 다이얼로그기반 MFC 프로젝트 생성부터 예제 코드 실행까지 단계별로 설명하겠습니다.

MFC 응용 프로그램 생성


GLEW 라이브러리 추가


UI 구성


OpenGL 관련 코드 추가


테스트


관련 포스팅


참고한 사이트



MFC 응용 프로그램 생성

Visual Studio 2017을 실행시키고 메뉴에서 파일 > 새로 만들기 > 프로젝트를 선택합니다.

MFC 응용 프로그램을 선택하고 프로젝트 이름을 지정해 줍니다.




MFC 응용 프로그램 마법사가 시작됩니다.

현재 프로젝트 설정을 보여주는데 추가 설정을 위해 다음을 클릭합니다.



대화 상자 기반을 선택하고 마침을 클릭합니다.



메뉴 아래에 보이는 솔루션 구성 Debug, 솔루션 플랫폼 x64로 변경합니다.

프로젝트에 추가하게 되는  GLEW 라이브러리가  Release용이지만  MFC 디버깅을 위해 Debug로 설정합니다.-




이제부터 Visual Studio 2017에서 OpenGL 개발을 하기위해 필요한 라이브러리를 프로젝트에 추가하는 방법을 설명합니다.

프로젝트 이름 OpenGL with MFC이고 프로젝트 위치  C:\Users\사용자이름\Documents\Visual Studio 2017\Projects\OpenGL with MFC인 경우로 가정하고 설명합니다.

사용하시는 환경에 맞추어 적절히 변경하시면 됩니다.



GLEW 라이브러리 추가

OpenGL 3.x 이상에서는 호출 가능한 OpenGL API 함수들이 런타임에 결정됩니다.

GLEW를 사용하여 런타임OpenGL API 함수를 호출합니다.  


아래 링크에서 GLEW를 다운로드 받을 수  있습니다.

http://glew.sourceforge.net/



Windows 32-bit and 64-bit를 클릭하여 미리 라이브러리를  컴파일해둔 바이너리를 다운로드 받습니다.



압축을 풀은 후, include 폴더를 복사하여



프로젝트 폴더의 경로  OpenGL with MFC\OpenGL with MFC붙여넣기해줍니다.

기존에 생성된 include 폴더에 추가로 복사되어 집니다.



압축을 풀은 폴더의 경로 glew-2.0.0-win32\glew-2.0.0\lib\Release\x64에 있는  glew32.lib, glew32.lib를 복사하여



프로젝트 폴더의 경로  OpenGL-Example\OpenGL-Example\lib에 붙여넣기 해줍니다.



GLEW 라이브러리를 사용하여 컴파일한 실행 파일과 같이 glew32.dll 파일을 배포해야 합니다.


아직 실행 파일이 저장되는 폴더가 생성되어 있지 않기 때문에 dll 파일을 복사해줄 위치가 아직 없습니다.

아직 코드를 추가하지 않았지만 Visual Studio에서 Ctrl + F7를 눌러 컴파일을 해주면 실행파일이 저장될 위치를 위한 폴더들이 생성됩니다.



압축을 풀은 폴더의 경로 glew-2.0.0-win32\glew-2.0.0\bin\Release\x64에 있는  glew32.dll 파일을  복사하여



프로젝트 폴더의 경로  OpenGL with MFC\x64\Debug에 붙여넣기 해줍니다.



UI 구성

OpenGL의 렌더링 결과가 보여질 영역이 필요합니다.

오른쪽 끝에 위치한 도구 상자를 클릭 후  Picture Control을 드래그하여 다이얼로그 추가합니다.



Picture Control을 배치한 결과입니다.

버튼은 이후 코드 수정시 사용하게 될 거 같아서 남겨두었습니다.



다이얼로그 위에 있는 Picture Control을 선택한 상태에서 속성을 클릭합니다.

ID IDC_PICTURE로 수정하고 엔터를 눌러 변경합니다.



다시 다이얼로그 위에 있는 Picture Control을 선택하고 마우스 오른쪽 버튼을 클릭하여 메뉴에서 변수 추가를 선택합니다.

멤버 변수 추가 마법사 창의 변수 이름 항목에 m_picture를 입력하고 마침을 클릭합니다.



OpenGL 관련 코드 추가

Ctrl + Shift + X를 눌러서 클래스 마법사를 실행합니다.

클래스 이름을 COpenGLwithMFCDlg로 변경합니다.

메시지 탭을 선택하고 메시지 리스트에서 WM_DESTROY를 선택 후 처리기 추가를 클릭합니다.



같은 방식으로 WM_TIMER도 선택해서 추가하고 확인을 클릭합니다.



OpenGL with MFCDlg.h 파일에 GLEW 헤더파 일과 라이브러리 파일를 지정해줍니다.

// OpenGL with MFCDlg.h : 헤더 파일
//

#pragma once
#include "afxwin.h"

//상대경로로 헤더파일을 지정합니다.
#include "./include/GL/glew.h"
#include "./include/GL/wglew.h"

//사용할 라이브러리를 지정해줍니다.
#pragma comment(lib, "OpenGL32.lib")
#pragma comment(lib, "./lib/glew32.lib")



OpenGL with MFCDlg.h 파일 끝에 필요한 멤버함수 및 멤버 변수를 추가해줍니다.

public:
CStatic m_picture;

public:
afx_msg void OnDestroy();
afx_msg void OnTimer(UINT_PTR nIDEvent);

protected:
virtual BOOL GetOldStyleRenderingContext(void);

private:
//OpenGL Setup
BOOL GetRenderingContext();
//Rendering Context and Device Context Pointers
HGLRC     m_hRC;
CDC*      m_pDC;

float angle;
};



OpenGL with MFCDlg.cpp 파일의 OnInitDialog 함수에 붉은색 줄을 추가합니다.

// TODO: 여기에 추가 초기화 작업을 추가합니다.
//OpenGL context 생성
if (!GetRenderingContext())
{
AfxMessageBox(CString("OpenGL 초기화중 에러가 발생하여 프로그램을 실행할 수 없습니다."));
return -1;
}

angle = 0;
SetTimer(1000, 30, NULL);

return TRUE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}



OnDestroy 함수에 다음 붉은색 줄을 추가합니다.

void COpenGLwithMFCDlg::OnDestroy()
{
CDialogEx::OnDestroy();

// TODO: 여기에 메시지 처리기 코드를 추가합니다.

if (FALSE == ::wglDeleteContext(m_hRC))
{
AfxMessageBox(CString("wglDeleteContext failed"));
}
}



OnTimer 함수에 붉은색 코드를 추가합니다.

void COpenGLwithMFCDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();

//z축을 중심으로 설정된 angle로 회전한다.
glRotatef(angle, 0.0f, 0.0f, 1.0f);

//중앙이 원점에 오도록 삼각형을 그린다.
glBegin(GL_TRIANGLES); //3점이 하나의 삼각형을 구성한다. 반시계 방향으로 3점의 vertex를 지정해줘야 한다.
glColor3f(1.0f, 0.0f, 0.0f); //빨간색 지정
glVertex3f(-0.5f, -0.5f, 0.0f);    // 왼쪽 아래 vertex
glColor3f(0.0f, 1.0f, 0.0f); //녹색 지정
glVertex3f(0.5f, -0.5f, 0.0f);    // 오른쪽 아래 vertex
glColor3f(0.0f, 0.0f, 1.0f); //파란색 지정
glVertex3f(0.0f, 0.5f, 0.0f);    // 위쪽 vertex
glEnd();

//삼각형 회전각 증가
angle += 0.5f;

//화면 업데이트
SwapBuffers(m_pDC->GetSafeHdc());
}



OpenGL with MFCDlg.cpp 파일에 GetRenderingContext 함수를 추가합니다.

BOOL COpenGLwithMFCDlg::GetRenderingContext()
{
//픽처 컨트롤에만 그리도록 DC 생성
//참고 https://goo.gl/CK36zE
CWnd* pImage = GetDlgItem(IDC_PICTURE);
CRect rc;
pImage->GetWindowRect(rc);
m_pDC = pImage->GetDC();


if (NULL == m_pDC)
{
AfxMessageBox(CString("Unable to get a DC"));
return FALSE;
}


if (!GetOldStyleRenderingContext())
{
return TRUE;
}


//Get access to modern OpenGL functionality from this old style context.
glewExperimental = GL_TRUE;
if (GLEW_OK != glewInit())
{
AfxMessageBox(CString("GLEW could not be initialized!"));
return FALSE;
}


//참고 http://gamedev.stackexchange.com/a/30443
GLint attribs[] =
{
//OpenGL 2.0 사용
WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
WGL_CONTEXT_MINOR_VERSION_ARB, 0,
// Uncomment this for forward compatibility mode
//WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
// Uncomment this for Compatibility profile
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
// We are using Core profile here
//WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};


HGLRC CompHRC = wglCreateContextAttribsARB(m_pDC->GetSafeHdc(), 0, attribs);
if (CompHRC && wglMakeCurrent(m_pDC->GetSafeHdc(), CompHRC))
m_hRC = CompHRC;

return TRUE;
}




OpenGL with MFCDlg.cpp 파일에 GetOldStyleRenderingContext 함수를 추가합니다.

BOOL COpenGLwithMFCDlg::GetOldStyleRenderingContext()
{
//A generic pixel format descriptor. This will be replaced with a more
//specific and modern one later, so don't worry about it too much.
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW |            // support window
PFD_SUPPORT_OPENGL |            // support OpenGL
PFD_DOUBLEBUFFER,               // double buffered
PFD_TYPE_RGBA,                  // RGBA type
32,                             // 32-bit color depth
0, 0, 0, 0, 0, 0,               // color bits ignored
0,                              // no alpha buffer
0,                              // shift bit ignored
0,                              // no accumulation buffer
0, 0, 0, 0,                     // accum bits ignored
24,                        // 24-bit z-buffer
0,                              // no stencil buffer
0,                              // no auxiliary buffer
PFD_MAIN_PLANE,                 // main layer
0,                              // reserved
0, 0, 0                         // layer masks ignored
};

// Get the id number for the best match supported by the hardware device context
// to what is described in pfd
int pixelFormat = ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);

//If there's no match, report an error
if (0 == pixelFormat)
{
AfxMessageBox(CString("ChoosePixelFormat failed"));
return FALSE;
}

//If there is an acceptable match, set it as the current
if (FALSE == SetPixelFormat(m_pDC->GetSafeHdc(), pixelFormat, &pfd))
{
AfxMessageBox(CString("SetPixelFormat failed"));
return FALSE;
}

//Create a context with this pixel format
if (0 == (m_hRC = wglCreateContext(m_pDC->GetSafeHdc())))
{
AfxMessageBox(CString("wglCreateContext failed"));
return FALSE;
}

//Make it current.
if (FALSE == wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC))
{
AfxMessageBox(CString("wglMakeCurrent failed"));
return FALSE;
}
return TRUE;
}




테스트

F5를 눌러서 실행시켜 봅니다.






관련 포스팅

OpenGL과 MFC 연동 예제( GLEW 사용, Dialog 기반, OpenGL 3.x 코드)

http://webnautes.tistory.com/1109


참고한 사이트

http://www.cs.uregina.ca/Links/class-info/315/WWW/Lab1/MFC/


반응형

포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

유튜브 구독하기


제가 쓴 책도 한번 검토해보세요.

  1. velvet 2017.08.04 16:43

    안녕하세요. 덕분에 프로그램 작성하는데 큰 도움이 되었습니다. 그런데 프로그램을 배포하는 과정에서 문제가 생겨 덧글을 남깁니다. 원래 프로그램을 작성했었던 pc에서는 위 예제가 잘 작동되었지만, 다른 pc 2대에서는 selectPixelFormat Failed 에러가 발생하여 예제를 실행할 수 없다는 것을 알고 2.0.0 버전 예제와 2.1.0 버전 예제를 둘다 해봐도 문제가 해결되지 않아서.. 혹시 이 경우에 어떻게 대처하면 되는지를 알고 싶습니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2017.08.04 17:04 신고

      처음 작성한 PC와 다른 2대의 PC의 그래픽 카드가 다른가 봅니다.

      SetupPixelFormat 함수에서 아래부분에 차이가 있을 수 있습니다.

      const int attribList[] =
      {
      WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
      WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
      WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
      WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
      WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
      WGL_COLOR_BITS_ARB, 32,
      WGL_DEPTH_BITS_ARB, 24,
      WGL_STENCIL_BITS_ARB, 8,
      0, 0 //End
      };


      우선 WGL_COLOR_BITS_ARB를 24로 수정해보세요.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2017.08.04 17:07 신고

      답변 출처는 아래 주소입니다.
      https://www.gamedev.net/forums/topic/601212-wglchoosepixelformatarb-problem/



  2. velvet 2017.08.04 19:14

    처음 작성했던 pc는 m코어를 사용하는 그래픽카드없는 노트북이었고, 나중에 테스트한 2대의 pc는 ndivia 그래픽카드를 사용하는 일반 데스크탑이었습니다. 물론 3대 다 윈도우 10 x64 기반 프로세서를 사용하구요. 데스크탑의 경우가 더 일반적일 것이라고 생각되는데요. 작성해주신 답변을 보고 코드를 수정해보았으나 오류는 그대로 발생하였습니다. 해서
    file:///C:/Users/pkss1/Documents/glew-2.1.0/doc/install.html
    http://stevendebock.blogspot.kr/2013/07/nvidia-optimus.html

    이런 것들을 참조하여 문제를 해결하려고 시도 중입니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2017.08.04 19:57 신고

      옛날 글이라 요즘은 어떤지 모르겠지만 제가 드린 링크에 nVidia에선 Depth Buffer 32를 지원안한다는 말이 있어서요

      이 문제가 아닌가 봅니다..
      저도 확인해볼께요

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2017.08.05 01:39 신고

      확인해봤는데 GetRenderingContext() 함수에서 아래 부분을 삭제하시면 해결됩니다.

      //Get a new style pixel format
      if (!SetupPixelFormat())
      {
      return FALSE;
      }

    • velvet 2017.08.05 16:33

      그 부분을 지우니까 문제가 해결되었습니다. 감사합니다.

  3. 하아. 2017.09.14 22:04

    안녕하세요 많은 참고를 하고 싶은데 시작부터 막히는 부분이있네요..Ui 구성 부분쪽에서 도구모음에서 picture control을 설정하시는 부분이 있는데 제가 아무리 도구모음을 열어봐도 아무것도 나오지 않습니다. 제가 평가판이라서 안나오는건가요..???ㅠㅠ 어떻게든 연동을 하고싶은데 조언 부탁드립니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2017.09.15 14:17 신고

      Visual Studio 2017 Community 버전을 사용하고 있습니다.

      picture control을 선택하고 마우스 우클릭하여 보이는 메뉴에서 속성을 선택하면 보일겁니다.

+ Recent posts