CAFE

컴퓨터비전11(SCEA)

OpenGL 배워봅시다. - 삭제 예정

작성자한창호|작성시간17.04.06|조회수2,908 목록 댓글 0

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    

첨부파일 glutdlls37beta.zip


(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>
#include <GL/GL.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 )
{
 MSG msg          = {0};
 WNDCLASS wc      = {0};
 wc.lpfnWndProc   = WndProc;
 wc.hInstance     = hInstance;
 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
 wc.lpszClassName = L"oglversionchecksample";
 wc.style = CS_OWNDC;
 if( !RegisterClass(&wc) )  return 1;
 CreateWindowW(wc.lpszClassName,L"openglversioncheck",WS_OVERLAPPEDWINDOW|WS_VISIBLE,0,0,640,480,0,0,hInstance,0);

 while( GetMessage( &msg, NULL, 0, 0 ) > 0 )
  DispatchMessage( &msg );

 return 0;
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 switch(message)
 {
 case WM_CREATE:
  {
  PIXELFORMATDESCRIPTOR pfd =
  {
   sizeof(PIXELFORMATDESCRIPTOR),
   1,
   PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,    //Flags
   PFD_TYPE_RGBA,        // The kind of framebuffer. RGBA or palette.
   32,                   // Colordepth of the framebuffer.
   0, 0, 0, 0, 0, 0,
   0,
   0,
   0,
   0, 0, 0, 0,
   24,                   // Number of bits for the depthbuffer
   8,                    // Number of bits for the stencilbuffer
   0,                    // Number of Aux buffers in the framebuffer.
   PFD_MAIN_PLANE,
   0,
   0, 0, 0
  };


  HDC hdc = GetDC(hWnd);

  int  letWindowsChooseThisPixelFormat;


  // opengl context 생성

  letWindowsChooseThisPixelFormat = ChoosePixelFormat(hdc, &pfd);
  SetPixelFormat(hdc,letWindowsChooseThisPixelFormat, &pfd);

  HGLRC ourOpenGLRenderingContext = wglCreateContext( hdc );
  wglMakeCurrent ( hdc, ourOpenGLRenderingContext);


  //  opengl 명령어 수행

  MessageBoxA(0,(char*)glGetString(GL_VERSION), "OPENGL VERSION",0);


  // opengl context 소멸

  wglDeleteContext(ourOpenGLRenderingContext);
  PostQuitMessage(0);
  }
  break;
 default:
  return DefWindowProc(hWnd, message, wParam, lParam);
 }
 return 0;

}



(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)

 뷰 범위 지정

 원근 투상으로 시점을 기준으로 좌, 우, 상, 하, 전, 후가 어디까지 보이게 하는지 정한다.
glFrustum(double left, double right, double bottom, double top, double near, double far)


    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>
#include <GL/glut.h>

void setMaterial ( GLfloat ambientR, GLfloat ambientG, GLfloat ambientB,
   GLfloat diffuseR, GLfloat diffuseG, GLfloat diffuseB,
   GLfloat specularR, GLfloat specularG, GLfloat specularB,
   GLfloat shininess ) {

    GLfloat ambient[] = { ambientR, ambientG, ambientB };
    GLfloat diffuse[] = { diffuseR, diffuseG, diffuseB };
    GLfloat specular[] = { specularR, specularG, specularB };

    glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient);
    glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuse);
    glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,specular);
    glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,shininess);
}

void display () {
    /* clear window */
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    /* future matrix manipulations should affect the modelview matrix */
    glMatrixMode(GL_MODELVIEW);
    /* draw scene */
    glPushMatrix();

    // house
    glPushMatrix();
    setMaterial(0.0,0.5,1.0,0.0,0.5,1.0,1.0,1.0,1.0,1);
    glutSolidCube(2);                 // building

    glTranslatef(0,1,0);
      glPushMatrix();                   // roof
      glRotatef(-90,1,0,0);
      setMaterial(0.0,0.5,1.0,0.0,0.5,1.0,1.0,1.0,1.0,50);
      glutSolidCone(1.5,1,16,8);
      glPopMatrix();

    glTranslatef(.75,.5,-.75);        
      glPushMatrix();                   // chimney
      glScalef(1,3,1);
      setMaterial(1.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1);
      glutSolidCube(.25);
      glPopMatrix();
    glPopMatrix();


    // car
    glTranslatef(0,-.65,2);
    setMaterial(1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,50);
    glPushMatrix();
      glPushMatrix();                   // body
      glScalef(2,.5,1);
      glutSolidCube(.5);
      glPopMatrix();
    glTranslatef(0,0,.25);
      glPushMatrix();
      glTranslatef(-.4,-.2,0);
      glutSolidTorus(.05,.1,8,8);       // wheel
      glTranslatef(.8,0,0);
      glutSolidTorus(.05,.1,8,8);       // wheel
      glPopMatrix();
    glTranslatef(0,0,-.5);
      glPushMatrix();
      glTranslatef(-.4,-.2,0);
      glutSolidTorus(.05,.1,8,8);       // wheel
      glTranslatef(.8,0,0);
      glutSolidTorus(.05,.1,8,8);       // wheel
      glPopMatrix();
    glPopMatrix();

    glPopMatrix();    
    glFlush();   /* flush drawing routines to the window */
}

void reshape ( int width, int height ) {
    /* define the viewport transformation */
    glViewport(0,0,width,height);
}

int main ( int argc, char * argv[] )

{
    /* initialize GLUT, using any commandline parameters passed to the program */
    glutInit(&argc,argv);

    /* setup the size, position, and display mode for new windows */
    glutInitWindowSize(500,500);
    glutInitWindowPosition(0,0);
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH);

    /* create and set up a window */
    glutCreateWindow("house2");
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);

    /* set up depth-buffering */
    glEnable(GL_DEPTH_TEST);

    /* set up lights */
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    GLfloat lightpos[] = { 0.0, 15.0, 15.0 };
    GLfloat lightcolor[] = { 0.5, 0.5, 0.5 };
    GLfloat ambcolor[] = { 0.2, 0.2, 0.0 };

    glEnable(GL_LIGHTING);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambcolor);
    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0,GL_POSITION,lightpos);
    glLightfv(GL_LIGHT0,GL_AMBIENT,lightcolor);
    glLightfv(GL_LIGHT0,GL_DIFFUSE,lightcolor);
    glLightfv(GL_LIGHT0,GL_SPECULAR,lightcolor);

    /* define the projection transformation */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(40,1,4,20);

    /* define the viewing transformation */
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(5.0,5.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0);

    /* tell GLUT to wait for events */
    glutMainLoop();



* 모델 Obj 파일을 읽어서 화면에 출력해보자.


- 모델과 재질 파일 : 첨부파일 al.mtl  첨부파일 al.obj  

- 모델 불러오는 소스:    첨부파일 glm.cpp  첨부파일 glm.h   (vs2019 버전에 맞게 수정했음)

- 전체 소스: 첨부파일 glObjView.zip  (vs2019, glut 포함)



 // OpenGL로 모델을 띄우는 소스코드:  written by H.C.H  2020.06.08

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <GL/glut.h>
#include "glm.h"
#pragma comment( linker, "/entry:\"mainCRTStartup\"" )  // set the entry point to be main()


GLMmodel* pmodel = NULL;


void drawmodel(void)
{
    if (!pmodel) {
        pmodel = glmReadOBJ("al.obj");   // 모델을 불러온다.
        if (!pmodel) exit(0);
        glmUnitize(pmodel);
        glmFacetNormals(pmodel);
        glmVertexNormals(pmodel, 90.0);
    }    
    glmDraw(pmodel, GLM_SMOOTH | GLM_MATERIAL);  // 모델을 그린다.
}


void reshape(int width,  int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(80.0, 1.0, 1.0, 10.0);
    //glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 3.5);
    //glOrtho(-1.0, 1.0, -1.0, 1.0, 1.0, 3.5);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glClearColor(0.2, 0.2, 0.2, 0.0);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
}


void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    drawmodel();
    glutSwapBuffers();
}


int main(int argc, char** argv)
{
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
    glutInitWindowSize(512, 512);
    glutInitWindowPosition(50, 50);
    glutInit(&argc, argv);   
    glutCreateWindow("ModelView");
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);   
    glutMainLoop();   
    return 0;
}






5. OpenCV를 캡쳐한 영상을 OpenGL에서 보여주기


OpenCV3.1.0에서 실행하였다. OpenCV영상은 BGR이며 y축이 증가하지만, OpenGL에서는 RGB이며, y축이 감소한다. 따라서 다음과 같은 명령어로 영상을 변환한다. (출처: opelgl site)




다음 소스를 컴파일 하려면 다음과 같은 glut32와 glut64 라이브러리가 필요하다.


첨부파일 glut32.dll

첨부파일 glut32.lib

첨부파일 glut64.dll

첨부파일 glut64.lib


소스코드: 첨부파일 oglCam.zip


// OpenCV에서 웹카메라 영상을 얻어 OpenGL에 출력하는 소스코드
// opencv에서 웹캠 영상 읽을 때 x64에서는 VideoCapture 클래스를 사용해야 영상을 읽기도 한다.

// OpenCV와 OpenGL의 영상의 다른점
//  BRG   ->  RGB
//  Y축   ->  꺼꾸로

#include <opencv2/opencv.hpp>

#include <gl/glut.h> // gl.h보다 먼저 선언
#include <gl/gl.h>

#pragma comment(lib,"glut64.lib")

using namespace std;
using namespace cv;


VideoCapture capture;
Mat image;
GLuint texture;  // array in which the generated texture names are stored

int frame = 0;
int screenW;
int screenH;


int main(int argc, char * argv[])
{
 // initialize glut
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

 if (!cameraInit()) return -1;

 // initialize the window
 glutInitWindowSize(screenW, screenH);
 glutInitWindowPosition(100, 100);
 glutCreateWindow("test");
 myInit();

 glutIdleFunc(myIdle);   // set the global idle callback
 glutDisplayFunc(drawGraphics); // set the display callback for the current window
 glutKeyboardFunc(myKeyboard); // setup other callbacks
 glutReshapeFunc(myReshape);  // setup reshpae callback

 glutMainLoop();

 return 0;
}


bool cameraInit()
{
 capture.open(0);   // initialize capture from a camera
 if (!capture.isOpened()) { printf("Could not capture a camera\n"); return false; }
 capture >> image;     // grab and return a frame from a camera

 screenW = image.cols;
 screenH = image.rows;

 return true;
}


void myInit()
{
 //gluOrtho2D(0, screenW, 0, screenH);
 glViewport(0, 0, screenW, screenH);

 // create a texture for the video
 glGenTextures(1, &texture); // generate texture names
 glBindTexture(GL_TEXTURE_2D, texture); // bind a named texture to a texturing target
}


void myIdle()
{
  capture >> image;          // 영상 캡쳐하기
  //imshow("capture", image);

  flip(image, image, 0);       // 영상을 위/아래로 뒤집는다.
  cvtColor(image, image, CV_BGR2RGB);    // Convert RGB image to Gray

  glutPostRedisplay();       // redisplay the window's normal plane
}


void drawGraphics()
{
 cout << endl << "frame #" << frame << endl;

 glClear(GL_COLOR_BUFFER_BIT); // clear the screen
 glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // background color

 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();


 // make a texture and set texture parameters
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);


 // set texture environment parameters
 // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);


 // specify a two-dimensional texture image
 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.cols, image.rows, 0, GL_RGB, GL_UNSIGNED_BYTE, image.data);


 // draw 2D square plane to be mapped by the texture
 glEnable(GL_TEXTURE_2D);
 glColor3f(1.0f, 1.0f, 1.0f); // the drawing color
 glBegin(GL_QUADS);
 {
  glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f);
  glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, 0.0f);
  glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 0.0f);
  glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);
 }
 glEnd();

 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();


 // draw a graphic object
 glDisable(GL_TEXTURE_2D);
 glColor3f(.5f, 1.0f, 0.0f);
 glutSolidTeapot(0.2);

 // glFlush();  // single buffer
 glutSwapBuffers(); // swap framebuffer
 frame++;
}


void myKeyboard(unsigned char key, int mousex, int mousey)
{
 switch (key) { case 27:  exit(0); }
}


void myReshape(int width, int height)
{
 glViewport(0, 0, width, 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)\Windows Kits\8.1\Lib\winv6.3\um\x86

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을 생성한 후, 레지스터 등록해야 한다. 


첨부파일 NTGraph3D_DLL_vs2017.zip


컴파일 후에 다음과 같은 에러가 발행하면 정상이다. 그리고 다음과 같이 레지스터 등록한다. 



관리자모드 CMD> RegSvr32 NTGraph3D.DLL


3) Demo 소스 컴파일 후, 실행


첨부파일 NTGraph3D_demo_vs2017.zip





7. OpenGL로 만든 3D 그래프


- 무려 1 주일이나 걸려, 겨우 완성 했네요. 위 소스를 완전히 바꿔서 가볍게 만들었어요. 여러가지 테스트가 가능하게 버튼에 다양한 그래프를 출력해 보았으니, 참고하시어 잘 활용하시길 바랍니다.





사용법

 개발 환경

 Visual Studio 2017. GLUT32 비트  (64비트는 freeglut 참고) - 사용법 블로그

 Header File

 CglGraphWnd m_Graph3D;

 Source File

 m_Graph3D.Create(NULL, _T("3D Graph"),
   WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(12, 12, 423, 338), this, 1234);

 실행 함수

  float x, y, z;
  m_Graph3D.InitGraph();
  m_Graph3D.m_nGraphType = G3D_SURFACE;
  m_Graph3D.m_NumVertexX = 40;
  m_Graph3D.m_NumVertexY = 40;
  for (int i = 0; i < 40; i++) {
   x = ((i - 20.0f) / 20.0f) * 3.15f;
   for (int j = 0; j < 40; j++) {
    y = ((j - 20.0f) / 20.0f) * 3.15f;
    z = sin(x) * cos(y) + 2.0f;
    m_Graph3D.addXYZ(x, y, z);
   }
  }
  m_Graph3D.SetViewRange();
  m_Graph3D.Invalidate();


실행소스코드: 첨부파일 Graph3D_vs2017-190730.zip




다음검색
현재 게시글 추가 기능 열기
  • 북마크
  • 공유하기
  • 신고하기

댓글

댓글 리스트
맨위로

카페 검색

카페 검색어 입력폼