OpenGL: 2D 및 3D 그래픽을 렌더링하기 위한 크로스플랫폼 API
GLU (GL Utility library): gl 유틸리티
GLUT (OpenGL Utility Toolkit): 마우스와 키보드 컨트롤 라이브러리
GLSL (Graphic Library Shader Language): 쉐이더 제어
GLEW (OpenGL Extension Wrangler Library) :
OS | 확장 라이브러리 | Library |
MS windows | WGL (Windows graphics library) | opengl32.lib gl.h -> 기본 정의 glu32.lib glu.h -> gl 유틸리티 glaux.lib glaux.h -> 윈도우 제어 glut32.lib glut.h -> 제어 및 유틸리티 |
X windows (Linux) | GLX (GL for X window) | |
OS/2 (IBM) | PGL |
•GeForce 8 시리즈 이상 GPU에 대해 OpenGL 3.3 과 OpenCL 1.0 (Open Computing Language)을 지원
•GeForce 400 시리즈 이상 GPU에 대해 OpenGL 4.1을 지원
1. 설치하기
(1) 다운받기
OpenGL 공식사이트(https://www.opengl.org/)
GLUT for Win32 (https://user.xmission.com/~nate/glut.html)
Pre-compiled Win32 for Intel GLUT 3.7 DLLs for Windows 95 & NT
(2) Visual Studio 2015 (32bit)사용시 위 파일들을 다음 폴더에 옮긴다.
glut.h -> C:\Program Files (x86)\Windows Kits\8.1\Include\um\gl
*.lib -> C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86
glut32.dll -> C:\Windows\SysWOW64 (32비트 폴더)
glut64.dll -> C:\Windows\System32 (64비트 폴더)
(3) Visual Studio 2017 (x86)
*.h -> C:\Program Files (x86)\Windows Kits\8.1\Include\um\gl
*.lib -> C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86
*.dll -> C:\Windows\System32
(4) 프로젝트 속성 변경 (혹시 에러가 날 경우)
-> C/C++->일반->디버그 정보 형식 -> 없음 선택
-> C/C++->코드생성->함수수준 링크 사용-> 예(/Gy) 선택
-> C/C++->코드생성->최소 다시 빌드 가능-> 아니오(/Gm-) 선택
-> C/C++->전처리기->전처리기 정의-> " ;_CRT_SECURE_NO_WARNINGS" 추가
-> Link ->고급->이미지에 안전한 예외 처리기 포함-> 아니오(/SAFESEH:NO) 선택
2. 프로그램 실행하기
(1) Win32 프로젝트로 빈 프로젝트로 작성한다.
(2) glut.h glu.h 등을 위 해당 폴더에 복사한다.
(3) 프로젝트 속성에서 링커->입력->추가 종속성 : glu32.lib glut32.lib opengl32.lib
또는 소스코드에 추가가능 : #pragma comment(lib,"./gl/glut32.lib")
소스코드:
ogex1.zip - 라이브러리 미포함 (vs2015)
oglex2.zip - x86, x64 라이브러리 포함 (vs2015)
oglex3_vs2015.zip - glut 포함
그밖에 다양한 예제
http://soen.kr/lecture/library/opengl/opengl-1.htm (OpenGL 설명)
Teapot 예제 (Teapot 예제)
http://openglsamples.sourceforge.net/projects/index.php/blog/index/
https://www.opengl.org/archives/resources/code/samples/glut_examples/examples/examples.html
http://kuroikuma.tistory.com/113
https://yuns-helloworld.tistory.com/entry/OpenGL-쉐이딩Shading-line-flat-smooth (스무딩 쉐이딩)
gl_ex1.txt - 콘솔에서 띄우는 기본 프로그램
gl_ex2.txt - Idle() 콜백 함수 사용
gl_ex3-timer.txt - 타이머 콜백 함수 사용
gl_ex4-주전자.txt - 주전자 보여주기
gl_ex5-육면체회전.txt - 육면체 보여주기
OpenGL-육면체(WinAPI).cpp - WIn Api 동작
GLEx_Demo.zip - 테스트 프로그램
3. OpenGL 이해
(1) Rendering Context
- opengl에서 그림을 그리기 위해 PixelFormat이라는 DC (device context)를 생성하고 그리고 소멸하는 코드를 살펴보자.
#include <windows.h> #pragma comment (lib, "opengl32.lib") LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); int WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd ) while( GetMessage( &msg, NULL, 0, 0 ) > 0 ) return 0; LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) HDC hdc = GetDC(hWnd); int letWindowsChooseThisPixelFormat; // opengl context 생성 letWindowsChooseThisPixelFormat = ChoosePixelFormat(hdc, &pfd); HGLRC ourOpenGLRenderingContext = wglCreateContext( hdc ); // opengl 명령어 수행 MessageBoxA(0,(char*)glGetString(GL_VERSION), "OPENGL VERSION",0); // opengl context 소멸 wglDeleteContext(ourOpenGLRenderingContext); } |
(2) 조명 (참고: https://wjdgh283.tistory.com/entry/OpenGL로-배우는-컴퓨터-그래픽스-Chapter-03-그래픽-컬러처리-1)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0) - GL_LIGHT0 ~ GLLIGHT7 까지 8개의 광원 사용 가능
void glLight(GLenum light, GLeneum pnme, TYPEparam);
void glLightv(GLenum light, GLenum pname, TYPE *param);
Ambient, 주변광 | 실내에 균일한 광도를 주는 조명. 양과 색은 빛의 색과 재질 속성에 의해 결정된다. 주변광 조명은 장면의 모든 점에서 동일한 빛의 세기에 의해 규정된다. |
Diffuse, 분산광 | 일정한 방향으로 빛이 들어와서 객체의 표면에 여러 방향으로 분산되는 빛이다. 객체의 방향이나 광원으로 부터의 거리에 따라서 밝기가 변한다. |
Specular, 반사광 | 거울면 처럼 반질반질한 느낌을 나타내며, 표면이 매끄러워질수록 반사광은 완전 반사체의 반사각을 중심으로 좁은 각도 범위내에 집중되게된다. |
Shininess, 선명도 | 표면이 매끈매끈하게 보이게 만든다. |
Emission, 방사도 | 물체가 스스로 발광하게 되어, 광원이 없어도 물체가 보인다. |
(3) 재질
face = GL_FRONT, GL_BACK, GL_FRONT_AND_BACK
void glMaterialfv(GLenum face, GLenum pname, const GLfloat *params);
GLenum face | GL_FRONT(겉), GL_BACK(내면), GL_FORNT_AND_BACK(양면)중에 하나의 질감을 설정 |
GLenum pname | GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMMISSION, GL_SHININESS의 질감을 선택 |
GLfloat *params | RGBA형식으로 입력된 배열을 넘겨준다. 각각 -1부터 1의 범위내의 값을 넣습니다. GL_SHININESS에의 경우에는 넘겨주는 값은 한개로, 0부터 128까지의 범위의 값이 된다. |
(4) 투영 (GL_PROJECTION)
직교 투영 (orthographic projection) | 평면 투영으로 원근감이 전혀 없는 상태 glOrthof(x최소,x최대,y최소,y최대, near,far) |
원근 투영 (perspective projection) | 원근 투영 gluPerspectivef(시야각 , 종횡비(뷰포트 또는 창의 너비/높이), 앞면의 z ,뒷면의 z) |
뷰 범위 지정 | 원근 투상으로 시점을 기준으로 좌, 우, 상, 하, 전, 후가 어디까지 보이게 하는지 정한다. |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1, 1, -1, 1, 1, 10);
//gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 1.0, 30000.0);
//glFrustum(-1, 1, -1, 1, 1, 10);
(5) 모델 뷰 (GL_MODELVIEW)
//모델, 시점 좌표계
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,2, 0,0,0, 0,1,0);
//큐브 1
glTranslatef(1, 0, 0);
glutWireCube(1);
glFlush();
glBegin(GL_TRIANGLE_STRIP) ~ glEnd() 을 사용할때 삼각형을 구성하는 방법은 다음과 같다. 단, 주의할 것은 맨 오른쪽을 같은 값으로 추가하지 않으면 맨 왼쪽과 연결되는 감기는 현상(winding)이 발생한다.
참고: https://www.learnopengles.com/tag/triangle-strips/
다음과 같이 변경해야 감기는 현상이 제거된다.
indexBuffer = { 1, 6, 2, 7, 3, 8, 4, 9, 5, 10, ..., 6, 11, 7, 12, 8, 13, 9, 14, 10, 15 }
indexBuffer = { 1, 6, 2, 7, 3, 8, 4, 9, 5, 10, 10, 6, 6, 11, 7, 12, 8, 13, 9, 14, 10, 15 }
4. 모델 그리기 테스트
간단한 모델을 만들고 조명을 비추어 그려보자. (http://math.hws.edu/bridgeman/courses/324/s06/doc/opengl.html)
#include <GL/gl.h> // car { |
* 모델 Obj 파일을 읽어서 화면에 출력해보자.
- 모델 불러오는 소스: glm.cpp glm.h (vs2019 버전에 맞게 수정했음)
- 전체 소스: glObjView.zip (vs2019, glut 포함)
// OpenGL로 모델을 띄우는 소스코드: written by H.C.H 2020.06.08 #include <math.h> GLMmodel* pmodel = NULL; void drawmodel(void) void reshape(int width, int height) void display(void) int main(int argc, char** argv) |
5. OpenCV를 캡쳐한 영상을 OpenGL에서 보여주기
OpenCV3.1.0에서 실행하였다. OpenCV영상은 BGR이며 y축이 증가하지만, OpenGL에서는 RGB이며, y축이 감소한다. 따라서 다음과 같은 명령어로 영상을 변환한다. (출처: opelgl site)
다음 소스를 컴파일 하려면 다음과 같은 glut32와 glut64 라이브러리가 필요하다.
소스코드: oglCam.zip
// OpenCV에서 웹카메라 영상을 얻어 OpenGL에 출력하는 소스코드 // OpenCV와 OpenGL의 영상의 다른점 #include <opencv2/opencv.hpp> #include <gl/glut.h> // gl.h보다 먼저 선언 #pragma comment(lib,"glut64.lib") using namespace std; VideoCapture capture; int frame = 0;
if (!cameraInit()) return -1; // initialize the window glutIdleFunc(myIdle); // set the global idle callback glutMainLoop(); return 0; bool cameraInit() screenW = image.cols; return true; void myInit() // create a texture for the video void myIdle() flip(image, image, 0); // 영상을 위/아래로 뒤집는다. glutPostRedisplay(); // redisplay the window's normal plane void drawGraphics() glClear(GL_COLOR_BUFFER_BIT); // clear the screen glMatrixMode(GL_PROJECTION); // make a texture and set texture parameters // set texture environment parameters // specify a two-dimensional texture image // draw 2D square plane to be mapped by the texture glMatrixMode(GL_MODELVIEW); // draw a graphic object // glFlush(); // single buffer void myKeyboard(unsigned char key, int mousex, int mousey) void myReshape(int width, int height) |
6. 3D 그래프 그리기
참고: http://www.ucancode.net/3D-Plot-Chart-Graph-ActiveX-Control-with-OpenGL-codes.htm
소스: 3d_graph_activex_control_src.zip (ActiveX 소스코드)
데모: 3d_graph_activex_control_demo.zip (demo 소스코드)
위 소스코드는 Vsiau C++ 6.0 으로 작성되었다. 따라서 VS2017에서 실행하려면, 수정해야할 내용이 많은데 다음과 같이 수정해보자.
ActiveX 소스코드 생성 및 레지스터 등록
1) glaux.h 추가 (glaux 다운받기) opengl_lib.zip
소스에서 gl/glu가 있는 부분을 검색해 보면 다음과 같이 여러곳이다. 버전마다 위치가 다를 수 있으니 실험을 해봐야 한다.
C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\gl C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\SDK\ScopeCppSDK\SDK\include\um\gl C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\um\gl C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\um\gl C:\Program Files (x86)\Windows Kits\8.1\Include\um\gl C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\gl |
C:\Program Files (x86)\Windows Kits\8.1\Include\um\gl 폴더에 glaux.h 복사
C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86 폴더에 glaux.lib 복사
2) 윈도우 버전 문제로 인한 에러 다수 발생
:\Program Files\Microsoft Visual Studio 10.0\VC\atlmfc\include\atlwin.h(2089): error C2065: 'MONITORINFO' : undeclared identifier
stdafx.h 에서 버전 숫자를 바꾼다.
#define _WIN32_WINNT 0x0500
3) error D8016: '/ZI'과(와) '/Gy-' 명령줄 옵션이 호환되지 않습니다.
project 속성 - 구성속성 - C/C++ - 코드생성 - 함수 수준 링크 사용 좌측의 값 변경(예(/Gy))
4) #include <atlimpl.cpp> 가 없다고 발생
삭제 한다. // #include <atlimpl.cpp>
5) ConvertBSTRToString link error
GraphCtl.cpp 파일에 #include "comdef.h" 를 추가한다.
6) NTGraph3D.def 수정 (골뱅이 제거)
DllCanUnloadNow @1 PRIVATE => DllCanUnloadNow PRIVATE
DllGetClassObject @2 PRIVATE => DllGetClassObject PRIVATE
...
7) 속성 - 링커 - 고급 - 이미지에 안전한 예외 처리기 포함 -> 아니오(/SAFESEH:NO) 로 변경
8) 실행 에러
레지스터를 등록하기 위해서는 관리자 권한 CMD를 실행해야한다. 그리고 NTGraph3D.DLL 파일이 있는 곳으로 이동해서 등록한다.
cd C:\Users\liberman\Desktop\NTGraph3D_src_vs2017\Debug
regsvr32 NTGraph3D.dll (등록설정)
regsvr32 /u NTGraph3D.dll (등록해제)
데모소스코드에서의 에러 문제 해결
1) Assertion Failed!
이유는 ActiveX가 등록이 되지 않아서 그렇다. 리소스뷰에서 다이얼로그를열어 보면 다음과 같은 에러가 발생한다. 만약 발생하지 않으면 제대로 등록이 된 것이다.
최종 수정된 소스코드 (VS2017에서 컴파일 함, x86 버전)
1) OpenGL 라이브러리를 설치 (파일은 위에 있음)
C:\Program Files (x86)\Windows Kits\8.1\Include\um\gl 폴더에 glaux.h 복사
C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86 폴더에 glaux.lib 복사
2) ActiveX 파일(DLL)을 컴파일 - NTGraph3D.dll을 생성한 후, 레지스터 등록해야 한다.
컴파일 후에 다음과 같은 에러가 발행하면 정상이다. 그리고 다음과 같이 레지스터 등록한다.
관리자모드 CMD> RegSvr32 NTGraph3D.DLL
3) Demo 소스 컴파일 후, 실행
7. OpenGL로 만든 3D 그래프
- 무려 1 주일이나 걸려, 겨우 완성 했네요. 위 소스를 완전히 바꿔서 가볍게 만들었어요. 여러가지 테스트가 가능하게 버튼에 다양한 그래프를 출력해 보았으니, 참고하시어 잘 활용하시길 바랍니다.
사용법
개발 환경 | Visual Studio 2017. GLUT32 비트 (64비트는 freeglut 참고) - 사용법 블로그 |
Header File | CglGraphWnd m_Graph3D; |
Source File | m_Graph3D.Create(NULL, _T("3D Graph"), |
실행 함수 | float x, y, z; |
실행소스코드: Graph3D_vs2017-190730.zip