처음에는 Bezier 커브를 만드는것이 목적이였는데,
시간이 지나고 보니,
아무리 봐도 이것이 베지에 커브라는 생각이 들지 않아서 제목을 '곡선'이라고 정정했습니다.
하지만 게시글 내부의 알고리즘은 그대로 두었으니, 그냥 그러려니~ 하고 봐주세요 ㅠ
<그림 1>
제목이 C::OpenGL로 되어있어서 C만 사용한 것 같지만, 굳이 따지자면 C만 사용한 것은 아니다.
Frame이 MFC이기 때문에 C++의 구조가 기본으로 깔려있기 때문이다.
일단 이 프로젝트를 설명하기 전에, 독자가 독자적으로 OpenGL을 띄울 수 있다는 전제를 깔 것이다.
<그림 2>
먼저, <그림 2>와 같이 '좌표선언'과 좌표를 담을 수 있는 '구조체 배열 선언'을 해주었다.
<그림 3>
굳이 보여줄 것 까지는 없는데, 콜백 함수겸 사용하는 GLRenderScene 함수를 선언했다.
모든 그리기 코드는 GLRenderScene 함수에 포함되어 있다.
<그림 4>
GLRenderScene 함수는 다음의 두 함수를 포함하고 있다.
먼저 Bezier_Ellipse 함수는 <그림 2>에서 선언한 좌표를 큰 점으로 찍어주는 역할을 한다.
그 다음으로 선언된 Bezier_Lines는 베지에 커브를 그려주는 역할을 한다.
<그림 5>
Bezier_Ellipse 에서 이상한 점이 있다면 <그림 5>의 붉은색 테두리가 진 곳일 것이다.
이것은 y축의 범위가 너무 짧기 때문에, 그래프의 성향을 보기 힘들것을 고려하여 일부러 크기를 키운것이다.
<그림 6>
다음은 Bezier_Lines함수의 내부 모습이다.
일단, for문을 통해 제어값을 0 값에서 1 값 까지 돌게 했다.
베지에 커브는 0~1까지의 수를 통해 라인의 시작과 끝이 표현되기 때문이다.
<그림 6>의 붉은 색 테두리 안의 내용에는 Bezier 커브의 선언이 들어있다.
Bezier 커브는 x, y, z 좌표를 구조체로 전달하고, 그 구조체를 통해 선을 그리고 있다.
핵심은 Bezier 커브가 어떻게 좌표를 출력하느냐다.
<그림 7>
고백하건데, 이 함수는 내가 만든 것이 아니다.
Google에서 가져온 것이다. 아무튼 이렇게까지 해주면 베지에가 그려진다. ㅎㅎ (이것이 사실 베지에인지도 모른다.)
아래는 CodeBlocks (C기반) 으로 제대로 옮겨 보았던 코드다.
c++개념의 method들을 c개념으로 옮기느라 골머리가 조금 아프긴 했지만, 불가피하게 버전을 2개 만들 일이 있어서 이렇게 했다.
C++를 아록 있는 사람들에게는 위의 내용이 사실 더 간편한데, MFC 개념이 없다면 이해가 안될 수 있다.
그래서 굳이 C기반의 코드를 아래와 같이 첨부한다.
주석은 달지 않았다.
사실 이 코드를 찾았다는 것 자체가,
프로그램의 이해 보다, 프로그램의 구동에 더 관심이 있는 사람이라는 말이니까.
#include
<windows.h>
#include
<gl/gl.h>
#include "math.h"
LRESULT CALLBACK WindowProc(HWND, UINT,
WPARAM, LPARAM);
void EnableOpenGL(HWND hwnd, HDC*,
HGLRC*);
void DisableOpenGL(HWND, HDC,
HGLRC);
double Draw_x, Draw_y;
double Point_x[21] = {0, 2, 4, 6, 8, 10, 12,
14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40};
double Point_y[21] =
{0,0.3274,1.0679,1.9333,2.6834,3.0956,2.9862,2.2815,1.1091,-0.1624,-1.0242,-1.099,
-0.4533,0.3409,0.608,0.2052,-0.2967,-0.282,0.1048,0.2135,-0.0527};
void Be_Point(void)
{
int i, j, k;
double di, dj;
int kn, nn, nkn,
n;
double blend, mu, muk,
munk;
glPointSize(5.0f);
glColor3f(1, 1,
1);
glColor3f(0, 1,
0);
glBegin(GL_POINTS);
for(i=0; i<21;
i++)
glVertex3f(Point_x[i] * 2 / 40.0f -
1.0f , Point_y[i] / 4.0f , 0);
glEnd();
glColor3f(1, 1,
1);
glPointSize(1.0f);
glBegin(GL_POINTS);
for(di=0.0; di<=1.0;
di+=0.001)
{
n = 20;
mu = di;
muk = 1;
munk =
pow(1-mu,(double)n);
Draw_x = 0.0f;
Draw_y = 0.0f;
for (k=0; k<=n;
k++)
{
nn = n; // 개수 값
kn = k; // k값
nkn = n - k; //n-1값
blend = muk * munk;
//
muk *= mu;
munk /=
(1-mu);
while (nn
>= 1)
{
blend *= nn;
nn--;
if
(kn > 1)
{
blend /=
(double)kn;
kn--;
}
if
(nkn > 1)
{
blend /=
(double)nkn;
nkn--;
}
}
Draw_x += Point_x[k] * blend
;
Draw_y += Point_y[k] * blend
;
}
glVertex3f(Draw_x * 2 / 40.0f -
1.0f, Draw_y / 4.0f, 0);
}
glEnd();
glColor3f(0, 0,
0);
glPointSize(1.0f);
}
int WINAPI WinMain(HINSTANCE
hInstance,
HINSTANCE
hPrevInstance,
LPSTR
lpCmdLine,
int
nCmdShow)
{
WNDCLASSEX wcex;
HWND hwnd;
HDC hDC;
HGLRC hRC;
MSG msg;
BOOL bQuit =
FALSE;
// float theta =
0.0f;
/* register window class
*/
wcex.cbSize =
sizeof(WNDCLASSEX);
wcex.style =
CS_OWNDC;
wcex.lpfnWndProc =
WindowProc;
wcex.cbClsExtra =
0;
wcex.cbWndExtra =
0;
wcex.hInstance =
hInstance;
wcex.hIcon = LoadIcon(NULL,
IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL,
IDC_ARROW);
wcex.hbrBackground =
(HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszMenuName =
NULL;
wcex.lpszClassName =
"GLSample";
wcex.hIconSm = LoadIcon(NULL,
IDI_APPLICATION);;
if
(!RegisterClassEx(&wcex))
return 0;
/* create main window
*/
hwnd =
CreateWindowEx(0,
"GLSample",
"KNU :: 2005
02219 ",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
500,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd,
nCmdShow);
/* enable OpenGL for the window
*/
EnableOpenGL(hwnd, &hDC,
&hRC);
/* program main loop
*/
while (!bQuit)
{
/* check for messages
*/
if (PeekMessage(&msg, NULL, 0,
0, PM_REMOVE))
{
/* handle or dispatch messages
*/
if (msg.message ==
WM_QUIT)
{
bQuit =
TRUE;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
/* OpenGL animation code goes
here */
glOrtho(40, 40, 40, 40, 40,
40);
glClearColor(0.0f, 0.0f, 0.0f,
0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
Be_Point();
glPopMatrix();
SwapBuffers(hDC);
}
}
/* shutdown OpenGL
*/
DisableOpenGL(hwnd, hDC,
hRC);
/* destroy the window explicitly
*/
DestroyWindow(hwnd);
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT
uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
PostQuitMessage(0);
break;
case
WM_DESTROY:
return 0;
case
WM_KEYDOWN:
{
switch
(wParam)
{
case
VK_ESCAPE:
PostQuitMessage(0);
break;
}
}
break;
default:
return DefWindowProc(hwnd, uMsg,
wParam, lParam);
}
return 0;
}
void EnableOpenGL(HWND hwnd, HDC* hDC,
HGLRC* hRC)
{
PIXELFORMATDESCRIPTOR
pfd;
int iFormat;
/* get the device context (DC)
*/
*hDC =
GetDC(hwnd);
/* set the pixel format for the DC
*/
ZeroMemory(&pfd,
sizeof(pfd));
pfd.nSize =
sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW
|
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
pfd.iPixelType =
PFD_TYPE_RGBA;
pfd.cColorBits =
24;
pfd.cDepthBits =
16;
pfd.iLayerType =
PFD_MAIN_PLANE;
iFormat = ChoosePixelFormat(*hDC,
&pfd);
SetPixelFormat(*hDC, iFormat,
&pfd);
/* create and enable the render context
(RC) */
*hRC =
wglCreateContext(*hDC);
wglMakeCurrent(*hDC,
*hRC);
}
void DisableOpenGL (HWND hwnd, HDC hDC,
HGLRC hRC)
{
wglMakeCurrent(NULL,
NULL);
wglDeleteContext(hRC);
ReleaseDC(hwnd,
hDC);
}
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
8 |
[OpenGL] OpenGL 표현에 필요한 파일들...
![]() | simpled | 2013.09.22 | 3090 |
» |
[C :: OpenGL] 곡선
![]() | simpled | 2013.08.05 | 4347 |
6 |
[C :: OpenGL] 프로젝션을 사용하지 않은 그림자 생성
![]() | simpled | 2013.08.05 | 6536 |
5 |
[C :: OpenGL] 2D 프로젝션 코드 (그림자 생성 원리)
![]() | 심플디 | 2013.08.05 | 8205 |
4 |
[C :: OpenGL] 삼각형 그리기
![]() | simpled | 2013.08.05 | 3915 |
3 |
[C :: OpenGL] cosin^n (Θ)의 3D 그래프
![]() | 심플디 | 2013.08.05 | 3224 |
2 |
[C :: OpenGL] 움직이는 4각형 :: OpenGL
![]() | simpled | 2013.08.05 | 3723 |
1 |
[C :: OpenGL] OpenGL utility toolkit. zip
![]() | simpled | 2013.08.05 | 3456 |