OpenGL - Perspective vs Orthographic (투시투영 vs 직교투영)

OrthoGraphic (직교투영), Perspective (투시투영) projection


둘의 차이를 간단히 설명하자면 직교투영은 무한한 거리에서 바라보는 것이라고 생각하면 된다.


가까운 거리에 있는 물체는 크게, 멀리 있는 물체는 작게 보이는 실생활과는 달리, 같은 크기의 물체는 모두 같게 보이는 것이다.


즉 그 반대인 투시투영은 실생활에서 우리 보는 원근감을 그대로 표현하는 projection이라고 생각하면 된다.


예제를 통해서 그 둘을 비교해 본다. 이번 예제는 같은 큐브를 두개의 관점에서 본다.


(앞의 예제와 마찬가지로, 생략된 코드는 아래의 링크를 참조한다)


2017/09/12 - [SW/OpenGL] - OpenGL - 사각형 회전, 색바꾸기





소스코드


선언부

static int vi = 2;
static float viewer[3];
 
/// <summary>
/// The vertices {x, y, z}
/// </summary>
GLfloat vertices[8][3] = { { -1, -11 },{ -111 },
{ 111 },{ 1, -11 },{ -1, -1, -1 },
{ -11, -1 },{ 11, -1 },{ 1, -1, -1 } };
 
/// <summary>
/// The colors {R, G ,B]
/// </summary>
GLfloat colors[8][3] =
{ { 001 },{ 011 },
{ 111 },{ 101 },
{ 000 },{ 010 },
{ 110 },{ 100 } };
 
int W = 600H = 600;//width, height


키보드 이벤트

void menu(int item)
{
	keyboard((unsigned char)item00);
}
 
void keyboard(unsigned char keyint xint y)
{
	switch (key)
	{
	case 'q' | 'Q':
		exit(0); break;
	case VK_ESCAPE:
		exit(0); break;
	case 1://perspective
	{
		W += 1;
		vi = 1;
		glutReshapeWindow(WH);
	}	break;
	case 2://orthographic
	{
		vi = 2;
		W -= 1;
		glutReshapeWindow(WH);
	}break;
	}
}


초기화

void init(void)
{
	for (int i = 0i < 3i++) {
		viewer[i] = 2.5;
	}
}


사각형 draw

/// <summary>
/// draw square
/// </summary>
/// <param name="a">a.</param>
/// <param name="b">The b.</param>
/// <param name="c">The c.</param>
/// <param name="d">The d.</param>
void quad(int aint bint cint d)
{
	glBegin(GL_QUADS);
	glColor3fv(colors[a]); glVertex3fv(vertices[a]);
	glColor3fv(colors[b]); glVertex3fv(vertices[b]);
	glColor3fv(colors[c]); glVertex3fv(vertices[c]);
	glColor3fv(colors[d]); glVertex3fv(vertices[d]);
	glEnd();
}


렌더링함수

void RenderScene(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	if (vi == 1)//perspective
	{
		vi = 1;
		gluLookAt(viewer[0], viewer[1], viewer[2], 000010);
		glutReshapeFunc(ChangeSize);
	}
	else//orthographic
	{
		vi = 2;
		glutReshapeFunc(ChangeSize);
		gluLookAt(viewer[0], viewer[1], viewer[2], 000010);
	}
	//draw cube
	quad(0321);
	quad(2376);
	quad(3047);
	quad(1265);
	quad(4567);
	quad(5401);
	glutSwapBuffers();
}


결과영상



OpenGL - 쉐이딩(Shading, line, flat smooth)

설명

삼각형으로 만든 원을 LineStrip, FlatShading, SmoothShading 효과를 줘 차이를 본다.


main에 없는 함수는 아래의 링크를 참조한다 (수정 x)

2017/09/12 - [SW/OpenGL] - OpenGL - 사각형 회전, 색바꾸기


선언부

typedef GLfloat point3[3];
static float theta[3];
int num = 1;
void DrawTriangle(point3 &apoint3 &bpoint3 &c);
void Normalize(point3 &p);
void DivideTriangle(point3 &apoint3 &bpoint3 &cint n);
void CrossProduct(point3 &apoint3 &bpoint3 &cpoint3 &r);

Theta 초기화

void init(void) {
	for (int i = 0i < 3i++)
	{
		theta[i] = 0;
	}
}


렌더링 함수

void RenderScene(void) {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(002000010);
 
	glEnable(GL_LIGHTING);//turn on light
	glEnable(GL_LIGHT0);//light0 turn on
 
	glRotatef(theta[2], 001);
	glRotatef(theta[1], 010);
	glRotatef(theta[0], 100);
 
	point3 v[4] = { { 001 },{ 00.942809, -0.333333 },{ -.816497, -0.471405, -0.333333 },{ 0.816497, -0.471405, -0.333333 } };
	int n = 3;
	DivideTriangle(v[0], v[1], v[2], n);
	DivideTriangle(v[0], v[2], v[3], n);
	DivideTriangle(v[0], v[3], v[1], n);
	DivideTriangle(v[3], v[2], v[1], n);
 
	glutSwapBuffers();
}

벡터 정규화

/// <summary>
/// Normalizes vector
/// </summary>
/// <param name="p">The p.</param>
void Normalize(point3 &p) {
	double d = p[0] * p[0] + p[1] * p[1] + p[2] * p[2];
	if (d > 0) {
		float len = (float)(1.0 / sqrt(d));
		p[0] *= lenp[1] *= lenp[2] *= len;
	}
}


벡터 외적

/// <summary>
/// Cross product vector a, b
/// </summary>
/// <param name="a">a.</param>
/// <param name="b">The b.</param>
/// <param name="c">The c.</param>
/// <param name="r">The r.</param>
void CrossProduct(point3 &apoint3 &bpoint3 &cpoint3 &r) {
	r[0] = (b[1] - a[1])*(c[2] - a[2]) - (b[2] - a[2])*(c[1] - a[1]);
	r[1] = (b[2] - a[2])*(c[0] - a[0]) - (b[0] - a[0])*(c[2] - a[2]);
	r[2] = (b[0] - a[0])*(c[1] - a[1]) - (b[1] - a[1])*(c[0] - a[0]);
	Normalize(r);//normalize
}


삼각형으로 나누기

/// <summary>
/// Divides the triangle recursively
/// </summary>
/// <param name="a">a.</param>
/// <param name="b">The b.</param>
/// <param name="c">The c.</param>
/// <param name="n">The n.</param>
void DivideTriangle(point3 &apoint3 &bpoint3 &cint n) {
	if (n > 0) {
		point3 v1v2v3;
		for (register int i = 0i < 3i++) {
			v1[i] = a[i] + b[i];
			v2[i] = b[i] + c[i];
			v3[i] = c[i] + a[i];
		}
		Normalize(v1); Normalize(v2); Normalize(v3);
		DivideTriangle(av1v3n - 1);
		DivideTriangle(bv2v1n - 1);
		DivideTriangle(cv3v2n - 1);
		DivideTriangle(v1v2v3n - 1);
	}
	else {
		DrawTriangle(abc);
	}
}

삼각형들 그리기

/// <summary>
/// Draws the triangle.
/// </summary>
/// <param name="a">point a.</param>
/// <param name="b">point b</param>
/// <param name="c">point c</param>
void DrawTriangle(point3 &apoint3 &bpoint3 &c) {
	if (num == 1// line strip
	{
		glDisable(GL_LIGHT0);//turn off light
		glBegin(GL_LINE_STRIP); {
			glNormal3fv(a); glVertex3fv(a);
			glNormal3fv(b); glVertex3fv(b);
			glNormal3fv(c); glVertex3fv(c);
		}glEnd();
	}
	else if (num == 2//flat shading
	{
		point3 n;
		CrossProduct(abcn);
		glBegin(GL_TRIANGLES);
		glNormal3fv(n);
		glVertex3fv(a);
		glVertex3fv(b);
		glVertex3fv(c);
		glEnd();
	}
	else //smooth shading
	{
		glBegin(GL_TRIANGLES); {
			glNormal3fv(a); glVertex3fv(a);
			glNormal3fv(b); glVertex3fv(b);
			glNormal3fv(c); glVertex3fv(c);
		}glEnd();
	}
}


각 shading마다 이벤트를 받는다.

void keyboard(unsigned char keyint xint y)
{
	switch (key)
	{
	case 1://line strip
	{
		num = 1;
	}break;
 
	case 2://flat shading
	{
		num = 2;
	}break;
	case 3://smooth shading
	{
		num = 3;
	}break;
	default:
		break;
	}
	RenderScene();
}
 
void shape(int item)
{
	keyboard((unsigned char)item00);
}

메인함수

void main(int argccharargv[]) {
	glutInit(&argcargv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(600600);
	glutCreateWindow("Shading");
	glutDisplayFunc(RenderScene);
	glutReshapeFunc(ChangeSize);
 
	//show menu when right click
	glutCreateMenu(shape);
 
	//bind with key event
	glutAddMenuEntry("Wire frame"1);
	glutAddMenuEntry("Flat"2);
	glutAddMenuEntry("Smooth"3);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
 
	init();
	SetupRC();
	glutMainLoop();
}

결과물


OpenGL - 16개의 움직이는 랜덤 티팟

설명 : 16개의 teapot이 랜던한 색과 방향으로 회전한다.

이번에는 빛을 줘서 그림자 효과도 준다.


생략된 부분은 링크된 부분을 참고하세요(소스동일)

2017/09/12 - [SW/OpenGL] - OpenGL - 사각형 회전, 색바꾸기


선언부

GLUquadricObj *p; void getaxis(int index); double getcolor(); int axi[16]; double colR[16]; double colG[16]; double colB[16]; static float theta[3]; GLdouble angle;


렌더링 함수

void RenderScene(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(02.02.000001.00); //view point
 
	glEnable(GL_LIGHTING); //light on
	glEnable(GL_LIGHT0); //0th light
 
	GLfloat position0[4] = { 1001001001 };
	GLfloat ambient0[4] = { 000.6,0 };
	GLfloat diffuse0[4] = { 1.01.001 };
	GLfloat specular0[4] = { 1111 };
 
	glLightfv(GL_LIGHT0GL_POSITIONposition0);
	glLightfv(GL_LIGHT0GL_AMBIENTambient0);
	glLightfv(GL_LIGHT0GL_DIFFUSEdiffuse0);
	glLightfv(GL_LIGHT0GL_SPECULARspecular0);
 
	glColorMaterial(GL_FRONTGL_AMBIENT_AND_DIFFUSE);//light attributes is ambient, diffuse
	glEnable(GL_COLOR_MATERIAL);
 
	//set teapots attributes
	GLfloat mat_specular[4] = { 1,1,1,1 };
	GLfloat mat_shininess = 25.0f;
	glMaterialfv(GL_FRONTGL_SPECULARmat_specular);
	glMaterialf(GL_FRONTGL_SHININESSmat_shininess);
	double xp = -1.6;
	double yp = 2.4;
	int a = 0;
	int b = 0;
 
	for (int i = 0i < 4i++)
	{
		xp = -1.6// teapot move 1.6 with x-axis
		for (int k = 0k < 4k++)
		{
			glPushMatrix();//push
			glTranslatef(xpyp0.0);
 
			if (axi[a] == 0)
				glRotatef(angle100);
			else if (axi[a] == 1)
				glRotatef(angle010);
			else
				glRotatef(angle001);
			glColor3f(colR[b], colG[b], colB[b]);
			glutSolidTeapot(0.2);
			glPopMatrix();//pop
			a++;
			b++;
			xp = xp + 0.8;
		}
		yp = yp - 0.8;
	}
	glutSwapBuffers();
}


랜덤한 방향으로 회전하도록 x,y,z 방향을 제시해주는 함수

/// <summary>
/// set rotate direction random
/// </summary>
/// <param name="index">The index.</param>
void getaxis(int index)
{
	if (index == 0)
		glRotatef(angle100);
	else if (index == 1)
		glRotatef(angle010);
	else
		glRotatef(angle001);
}

주전자가 2도씩 회전함

/// <summary>
/// rotate teapot 2 degree
/// </summary>
/// <param name="value">The value.</param>
void rtimer(int value)
{
	angle += 2;
	glutTimerFunc(30rtimer0);
	glutPostRedisplay();
}


티팟에 줄 랜덤한 색을 제시

/// <summary>
/// Get random colors this instance.
/// </summary>
/// <returns></returns>
double getcolor(void)
{
	double c;
	c = (double)rand() / RAND_MAX;
	return c;
}


색과 방향 초기화

void init(void)
{
	srand(time(NULL));
	theta[0] = 0;
	theta[1] = 0;
	theta[2] = 0;
	for (int t = 0t < 16t++)
	{
		axi[t] = rand() % 3;
		colR[t] = (double)rand() / RAND_MAX;
		colG[t] = (double)rand() / RAND_MAX;
		colB[t] = (double)rand() / RAND_MAX;
	}
}


메인함수

void main(int argccharargv[])
{
	glutInit(&argcargv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(800800);
	glutCreateWindow("Ex4");
	glutDisplayFunc(RenderScene);
	glutReshapeFunc(ChangeSize);
	glutTimerFunc(30rtimer1);
	init();
	SetupRc();
	glutMainLoop();
}


결과


OpenGL - 로봇 팔 만들기

설명

로봇의 팔을 만들어서 회전하고 꺽을수 있다.


이번에도 마찬가지로 소스에 대한 설명은 주석을 참조하세요

또한 생략된 소스는 맨 앞의 글을 참조하세요

2017/09/12 - [SW/OpenGL] - OpenGL - 사각형 회전, 색바꾸기



로봇의 base

void base(void)
{
	glPushMatrix();//push
	{
		glColor3f(100);//red
		glTranslatef(0, -0.80);//y axis
		glRotatef(-90100);//x axis
		glRotatef(Base_Angle001);//z axis
		gluCylinder(p0.50.50.3201);//draw cylinder
	}
	glPopMatrix();//pop
}


로봇의 lower

/// <summary>
/// arm's lower
/// </summary>
void lower_arm(void)
{
	glPushMatrix();//push
	{
		glColor3f(010);//green
		glRotatef(Base_Angle010);//rotate with y axis
		glTranslatef(0, -0.70);//translate with axis
		glRotatef(Lower_Arm_Angle001);//rotate with z axis
		glTranslatef(00.50);//translate with y axis
		glScalef(0.210.2);//scaling
		glutWireCube(1);//draw cube
	}
	glPopMatrix();//pop
}


로봇의 upper

/// <summary>
/// arm's upper
/// </summary>
void upper_arm(void)
{
	glPushMatrix(); //push
	{
		glColor3f(001); // blue
		glRotatef(Base_Angle010); //rotate y axis
		glTranslatef(0, -0.70);//translate y axis
		glRotatef(Lower_Arm_Angle001);//rotate z axis
		glTranslatef(01.00);//translate y axis
		glRotatef(Upper_Arm_Angle001);//rotate z axis
		glTranslatef(00.40);//translate y axis
		glScalef(0.20.80.2);//scaling
		glutWireCube(1);//draw cube
	}
	glPopMatrix();//pop
}


렌더링 함수

void RenderScene(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.50.50.5000010);//setting camera viewpoint
	base(); //draw base
	lower_arm(); //draw lower part
	upper_arm(); //draw upper part
	glutSwapBuffers();
}


스페셜 키 이벤트 (화살표4개, home, end)

/// <summary>
/// Special key event
/// </summary>
/// <param name="key">Special key.</param>
/// <param name="x">The x</param>
/// <param name="y">The y</param>
void specialkeys(int keyint xint y)
{
	switch (key)
	{
	case GLUT_KEY_UP//up arrow
		Lower_Arm_Angle += 2;
		break;
	case GLUT_KEY_DOWN//down arrow
		Lower_Arm_Angle -= 2;
		break;
	case GLUT_KEY_LEFT//left arrow
		Base_Angle -= 2;
		break;
	case GLUT_KEY_RIGHT//right arrow
		Base_Angle += 2;
		break;
	case GLUT_KEY_HOME//home key
		Upper_Arm_Angle += 2;
		break;
	case GLUT_KEY_END//end key
		Upper_Arm_Angle -= 2;
		break;
	default:
		break;
	}
}


메인함수

void main(int argccharargv[])
{
	glutInit(&argcargv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(500500);
	glutCreateWindow("Simple");
	glutDisplayFunc(RenderScene);
	glutReshapeFunc(ChangeSize);
	glutSpecialFunc(specialkeys); //Special key event
	glutMouseFunc(mouseButton);
	glutMotionFunc(mouseMotion);
	glutTimerFunc(1000 / 30timer1);
	glutKeyboardFunc(keyboard);
	init();
	SetupRc();
	glutMainLoop();
}


타이머 함수

void timer(int value)
{
	if (rot)
	{
		theta += 2.0;
		if (theta >= 360.0)
			theta -= 360.0;
	}
	else
	{
		theta -= 2.0;
		if (theta <= 360.0)
			theta += 360.0;
	}
	glutTimerFunc(1000 / 30timer1);
	glutPostRedisplay();
}


결과


OpenGL - 정육면체 xyz축 회전


설명


정육면체를 'X'를 눌렀을때는 X축 회전, 'Y'를 눌렀을땐 Y축회전, 'Z'를 눌렀을때는 Z축 회전시킨다.



소스설명


앞의 소스와 중복되는 부분은 변경이 있기전까진 생략한다.

궁금하신분은 맨 앞의 게시물을 확인바랍니다.

2017/09/12 - [SW/OpenGL] - OpenGL - 사각형 회전, 색바꾸기



선언

static bool mouseLeftDown;//checking mouse click
static float point[2][2];
void mouseButton(int buttonint stateint xint y);
void mouseMotion(int xint y);
void keyboard(unsigned char keyint xint y);
void timer(int value);
void quad(int aint bint cint d);
static bool R = true;
static bool G = true;
static bool B = true;
static float theta;
bool rot = true;
int rx_axis = 0y_axis = 1z_axis = 0;


점8개와 색8개

/// <summary>
/// eight point to draw a cube
/// </summary>
GLfloat vertices[8][3] = { { -1, -11 },{ -111 },
{ 111 },{ 1, -11 },{ -1, -1, -1 },
{ -11, -1 },{ 11, -1 },{ 1, -1, -1 } };
 
 
 
/// <summary>
/// eight color each points
/// </summary>
GLfloat colors[8][3] =
{ { 001 },{ 011 },
{ 111 },{ 101 },
{ 000 },{ 010 },
{ 110 },{ 100 } };

colors는 r,g,b 값으로 색을 조합한다.



x,y,z 키에 대한 이벤트(x축, y축, z축)

void keyboard(unsigned char keyint xint y)
{
	switch (key)
	{
	case 'q' | 'Q':
		exit(0); break;
	case VK_ESCAPE:
		exit(0); break;
	case 1:
		exit(0); break;
	case 2:
		exit(0); break;
	case 'x' | 'X':
	{
		x_axis = 1;
		y_axis = 0;
		z_axis = 0;
		break;
	}
	case 'y' | 'Y':
	{
		x_axis = 0;
		y_axis = 1;
		z_axis = 0;
		break;
	}
	case 'z' | 'Z':
	{
		x_axis = 0;
		y_axis = 0;
		z_axis = 1;
		break;
	}
	default:
		break;
	}
}


렌더링함수

void RenderScene(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.50.50.5000010); //view point
	glRotatef(thetax_axisy_axisz_axis);//rotate cube
 
	//draw a cube with 6 quadrature
	quad(0321);
	quad(2376);
	quad(3047);
	quad(1265);
	quad(4567);
	quad(5401);
	glEnd();
	glutSwapBuffers();
}


사각형을 그린다 위의 함수에서 6개의 사각형을 그리는데 사용하는 함수 quad

void quad(int aint bint cint d)
{
	glBegin(GL_QUADS);
	glColor3fv(colors[a]); glVertex3fv(vertices[a]);
	glColor3fv(colors[b]); glVertex3fv(vertices[b]);
	glColor3fv(colors[c]); glVertex3fv(vertices[c]);
	glColor3fv(colors[d]); glVertex3fv(vertices[d]);
}


마우스 클릭, 모션 함수 (마우스 왼쪽 클릭하면 회전방향이 바뀐다.)

void mouseButton(int buttonint stateint xint y)
{
	//mouse left button click
	if (button == GLUT_LEFT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			if (!mouseLeftDown)
			{
				if (rot)
					rot = false;
				else
					rot = true;
			}
		}
		else if (state == GLUT_UP)
		{
			if (mouseLeftDown)
				mouseLeftDown = false;
		}
	}
	//mouse right button click
	else if (button == GLUT_RIGHT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
 
		}
		else if (state = GLUT_UP)
		{
 
		}
	}
	glutPostRedisplay();
}
 
void mouseMotion(int xint y)
{
	if (mouseLeftDown)
	{
		double viewport[4];
		glGetDoublev(GL_VIEWPORTviewport);
 
		point[1][0] = x / (float)viewport[2] * 500;
		point[1][1] = (viewport[3] - y) / (float)viewport[3] * 500;
	}
	glutPostRedisplay();
}


정육면체를 회전하기 위한 타이머

void timer(int value)
{
	if (rot)
	{
		theta += 2.0;
		if (theta >= 360.0)
			theta -= 360.0;
	}
	else
	{
		theta -= 2.0;
		if (theta <= 360.0)
			theta += 360.0;
	}
	glutTimerFunc(1000 / 30timer1);
	glutPostRedisplay();
}




초기화

void init(void)
{
	theta = 0.0f;
	glutTimerFunc(10timer1);
}
 
void SetupRc(void)
{
	glClearColor(1.0f1.0f1.0f1.0f);
	glEnable(GL_DEPTH_TEST);
}



결과



OpenGL - 3점을 찍어 삼각형 그리기


설명


마우스로 폼위의 3점을 찍으면 그 점을 꼭지점으로 삼각형을 그린다.




소스설명


설명은 주석으로 대체하였다.


parameter

#define POINTS 100
 
GLfloat pos[POINTS][2];//point array
GLfloat Width = 600.0//form width
GLfloat Height = 600.0//form height
GLint n = 0//number of points


렌더링함수

/// <summary>
/// Renders the scene.
/// </summary>
void RenderScene(void)
{
	int i;
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(100);//red color
	glPointSize(10.0f);//size 10
	glEnableClientState(GL_VERTEX_ARRAY);// enable array
 
	
	for (i = 0i < 3i++)
	{
		glBegin(GL_POINTS);//dot
		glVertex2f(pos[i][0], pos[i][1]);//dot position
	}
	if (i>2 && (pos[2][0] != 0))//draw triangle when the number of points are greater than two
	{
		glBegin(GL_TRIANGLES);
		glVertex2f(pos[0][0], pos[0][1]);
		glVertex2f(pos[1][0], pos[1][1]);
		glVertex2f(pos[2][0], pos[2][1]);
	}
	glEnd();
	glFlush();//flush
}


마우스 클릭 이벤트

/// <summary>
/// Mouse button event.
/// </summary>
/// <param name="button">The button.</param>
/// <param name="state">The state.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
void mousebutton(int buttonint stateint xint y)
{
	if (button == GLUT_LEFT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			pos[n][0] = x / Width;
			pos[n][1] = (Height - y) / Height;
			if (n > 2)//when then number of points greater than two
			{
				pos[n % 3][0] = pos[n][0];//x
				pos[n % 3][1] = pos[n][1];//y
			}
			n++;
			RenderScene();//rendering
		}
	}
}


윈폼 크기 변경 함수

/// <summary>
/// winform size changed
/// </summary>
/// <param name="w">width</param>
/// <param name="h">height</param>
void ChangeSize(int wint h)
{
	GLfloat asepectRatio;
 
	Width = w;
	Height = h;
 
	if (Height == 0)
		Height = 1;
	glViewport(00wh);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	
	gluOrtho2D(0.01.00.01.0);
}
void main(int argcchar *argv[])
{
	glutInit(&argcargv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowSize(WidthHeight);
	glutInitWindowPosition(00);
	glutCreateWindow("ex2");
	glClearColor(1.0f1.0f1.0f1.0f);
	glMatrixMode(GL_PROJECTION);
 
	glutDisplayFunc(RenderScene);
	glutReshapeFunc(ChangeSize);
	glutMouseFunc(mousebutton);
 
	glutMainLoop();
}


결과물


OpenGL - 사각형 회전, 색바꾸기

OpenGL의 기초적인 함수를 사용해본다.


설명

r을 누르면 사각형의 회전방향이 바뀌고, 폼을 클릭하면 사각형의 색이 랜덤으로 바뀐다.


소스설명


키보드 입력등록

void menu(int item)
{
	keyboard((unsigned char)item00);
}


키보드 이벤트 등록

/// <summary>
/// key event registration
/// </summary>
/// <param name="key">The key.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
void keyboard(unsigned char keyint xint y)
{
	switch (key)
	{
	case 'q' | 'Q':
		exit(0); break;
	case VK_ESCAPE:
		exit(0); break;
	case 1:
		exit(0); break;
	case 2:
		exit(0); break;
	case 'R' | 'r'//change rotate direction
		rotate(); break;
	default:
		break;
	}
}


렌더링함수

/// <summary>
/// Renders the scene.
/// </summary>
void RenderScene(void)
{
	glClear(GL_COLOR_BUFFER_BIT);
 
	float cos_th = cos(theta * 3.14159 / 180.0);
	float sin_th = sin(theta * 3.14159 / 180.0);
 
	glColor3f(abc);
 
	//draw polygon
	glBegin(GL_POLYGON);
	{
		glVertex2f(cos_thsin_th);
		glVertex2f(-sin_thcos_th);
		glVertex2f(-cos_th, -sin_th);
		glVertex2f(sin_th, -cos_th);
	}
	glEnd();
	glutSwapBuffers();
}


초기화함수

void init(void)
{
	mouseLeftDown = false;
 
	point[0][0] = 0;
	point[0][1] = 0;
	point[1][0] = 0;
	point[1][1] = 0;
 
	theta = 0;
}
void SetupRc(void)
{
	glClearColor(1.0f1.0f1.0f1.0f);
}


윈폼의 크기가 변할때를 계산

/// <summary>
/// Changes the size.
/// when form size change
/// </summary>
/// <param name="w">width</param>
/// <param name="h">height</param>
void ChangeSize(int wint h)
{
	GLfloat aspectRatio;
 
	if (h == 0)
		h = 1;
 
	glViewport(00wh);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
 
	aspectRatio = (GLfloat)w / (GLfloat)h;
	if (w <= h)
	{
		gluOrtho2D(-2.02.0, -2.0*(float)h / (float)w2.0*(float)h / (float)w);
	}
	else
	{
		gluOrtho2D(-2.0*(float)w / (float)h2.0*(float)w / (float)h, -2.02.0);
	}
 
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}


사각형 회전을 위한 타이머

void timer(int value)
{
	if (rot)//rotate right
	{
		theta += 2.0;
		if (theta >= 360.0)
			theta -= 360.0;
	}
	else//rotate left
	{
		theta -= 2.0;
		if (theta <= 360.0)
			theta += 360.0;
	}
	glutTimerFunc(1000 / 30timer1);
	glutPostRedisplay();
}
 
void rotate()//exchange rotate direction
{
	if (rot)
		rot = false;
	else
		rot = true;
}


마우스 위치 함수

/// <summary>
/// Mouses the motion.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
void mouseMotion(int xint y)
{
	if (mouseLeftDown)
	{
		double viewport[4];
		glGetDoublev(GL_VIEWPORTviewport);
 
		point[1][0] = x / (float)viewport[2] * 500;
		point[1][1] = (viewport[3] - y) / (float)viewport[3] * 500;
	}
	glutPostRedisplay();
}


마우스 클릭 이벤트

/// <summary>
/// Mouse click event
/// </summary>
/// <param name="button">The button.</param>
/// <param name="state">button state.</param>
/// <param name="x">mouse's x</param>
/// <param name="y">mouse's y</param>
void mouseButton(int buttonint stateint xint y)
{
	int r;
	if (button == GLUT_LEFT_BUTTON//mouse left button
	{
		if (state == GLUT_DOWN)//clicked
		{
			if (!mouseLeftDown)
			{
			}
			r = rand() % 3;
			if (r == 0)
			{
				if (a == 0)
					a = 1;
				else
					a = 0;
				glutPostRedisplay();
			}
			else if (r == 1)
			{
				if (b == 0)
					b = 1;
				else
					b = 0;
				glutPostRedisplay();
			}
			else
			{
				if (c == 0)
					c = 1;
				else
					c = 0;
				glutPostRedisplay();
			}
		}
		else if (state == GLUT_UP)//unclicked
		{
			if (mouseLeftDown)
				mouseLeftDown = false;
		}
	}
}


가장 중요한 메인함수

/// <summary>
/// Mains the specified argc.
/// </summary>
/// <param name="argc">The argc.</param>
/// <param name="argv">The argv.</param>
void main(int argccharargv[])
{
	glutInit(&argcargv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(600600);//form's size
	glutCreateWindow("ex1");//form's name
	glutDisplayFunc(RenderScene);//display function registration
	glutReshapeFunc(ChangeSize);//reshape function registration
 
	glutMouseFunc(mouseButton);//mouse click function
	glutMotionFunc(mouseMotion);//mouse move function
	glutTimerFunc(1000 / 30timer1); //timer
	glutKeyboardFunc(keyboard);//keyboard functiom
 
	glutCreateMenu(menu);//when right mouse clicked
	glutAddMenuEntry("1"1);
	glutAddMenuEntry("2"2);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
 
	init();
	SetupRc();
	srand(time(NULL));
	glutMainLoop();
}




비주얼 스튜디오 단축키 모음

VS의 단축키들을 각 버전별로 보여주고 있는 사이트를 알게되어 게시한다.


http://visualstudioshortcuts.com/2017/

Template Method Pattern (템플릿메소드패턴)

Template Method Pattern

 


정의


상위 class에서 처리의 흐름을 제어하고, 하위class에서 처리의 내용을 구체화 한다


여러 class에서 공통되는 사항은 상위 추상 class에서 구현하고, 각각의 세부내용은 하위 class에서 구현한다


그 결과 코드의 중복을 줄이고, Refactoring에 유리한 패턴으로 상속을 통한 확장 개발 방법으로 Strategy Pattern과 함께 많이 사용되는 pattern이다.


 

Hook method


필수적이지 않은 부분으로 필요에 따라 선택적으로 sub-class에서 구현할 경우 사용한다


Abstract class에서 정의된 어떠한 행도 하지 않을 수 있고, sub-class의 공통된 동작을 할 수도 있다


또한, sub-class에서 hook method를 재정의 하여 사용하는 방법도 있다


Sub-class에 따라 algorithm에 원하는 내용을 추가할 수 있도록 하는 것이 hook-method의 존재 이유다.


 

요구사항


1.    멤버 함수들의 접근 범위 지정을 명확히 한다.


2.    가상함수, 일반함수로 선언 하는 것 에 대한 기준이 필요


3.    Virtual 함수의 수를 최소화한다.



l  Hollywood Principle

Sub-classupper-class에 구성요소로써 활용될 수 있지만, sub-class upper-class를 호출하여 자신을 호출하게 하면 안된다는 것이다


Template Method Pattern에서도 이러한 원칙을 따르고 있는데


설명을 더하면, abstract class에서는 sub-class에 있는 기능을 호출할 수 있지만


sub-class에서는 abstract-class template method를 호출하거나 수정할 수 없다는 것이다.

 


장점


상위위 class template method에서 알고리즘이 기술되어 있으므로,


하위 class에서는 알고리즘을 일일이 기술할 필요가 없다.


 

소스코드


상위클래스

public abstract class CaffeineBeverageWithHook {

         void prepareRecipe(){

                 boilWater();

                 brew();

                 pourInCup();

                 if(customerWantsCondiments()){

                          addCondiments();

                 }

         }

 

         abstract void brew();

         abstract void addCondiments();

 

         void boilWater(){

                 System.out.println("Boiling water");

         }

 

         void pourInCup(){

                 System.out.println("Pouring into cup");

         }

 

         boolean customerWantsCondiments(){

                 return true;

         }

}

 

하위클래스(coffee)

public class CoffeeWithHook extends CaffeineBeverageWithHook{
         @Override
         void brew() {
                 // TODO Auto-generated method stub
                 System.out.println("Dripping Coffee through filter");
         }
 
         @Override
         void addCondiments() {
                 // TODO Auto-generated method stub
                 System.out.println("Adding Sugar and Milk");
         }
         @Override
         public boolean customerWantsCondiments() {
                 // TODO Auto-generated method stub
                 String answer = getUserInput();
 
                 if(answer.toLowerCase().startsWith("y")){
                          return true;
                 }else{
                          return false;
                 }
         }
 
         private String getUserInput(){
                 String answer = null;
 
                 System.out.println("would you like milk&sugar with your coffee (y/n) ?");
                 BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
 
                 try {
                          answer = in.readLine();
                 } catch (Exception e) {
                          // TODO: handle exception1
                          System.err.println("IO error trying to read your answer");
                 }
 
                 if(answer==null){
                          return "no";
                 }
                 return answer;
         }
}

 

하위클래스(tea)

public class TeaWithHook extends CaffeineBeverageWithHook{
 
         @Override
         void brew() {
                 // TODO Auto-generated method stub
                 System.out.println("Steeping the tea");
         }
 
         @Override
         void addCondiments() {
                 // TODO Auto-generated method stub
                 System.out.println("Adding Lemon");
         }
         @Override
         public boolean customerWantsCondiments() {
                 // TODO Auto-generated method stub
                 String answer = getUserInput();
 
                 if(answer.toLowerCase().startsWith("y")){
                          return true;
                 }else{
                          return false;
                 }
         }
 
         private String getUserInput(){
                 String answer = null;
 
                 System.out.println("would you like lemon with your tea (y/n) ?");
                 BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
 
                 try {
                          answer = in.readLine();
                 } catch (Exception e) {
                          // TODO: handle exception1
                          System.err.println("IO error trying to read your answer");
                 }
 
                 if(answer==null){
                          return "no";
                 }
                 return answer;
         }
 
}

 

Main

public class BeverageTestDrive {
         public static void main(String[] args) {
                 TeaWithHook teaWithHook = new TeaWithHook();
                 CoffeeWithHook coffeeWithHook = new CoffeeWithHook();
                 
                 System.out.println("\n Making tea");
                 teaWithHook.prepareRecipe();
                 
                 System.out.println("\nMaking coffee");
                 coffeeWithHook.prepareRecipe();
         }
}

 

 

결과

Making tea

Boiling water

Steeping the tea

Pouring into cup

would you like lemon with your tea (y/n) ?

y

Adding Lemon

 

Making coffee

Boiling water

Dripping Coffee through filter

Pouring into cup

would you like milk &sugar with your coffee (y/n) ?

y

Adding Sugar and Milk



UML


'SW > DesignPattern' 카테고리의 다른 글

Composite Pattern (컴포지트 패턴)  (0) 2017.09.15
Iterator Pattern (반복자 패턴)  (0) 2017.09.14
Facade Pattern (퍼사드 패턴)  (0) 2017.09.07
Adapter Pattern (어댑터 패턴)  (0) 2017.09.07
Command Pattern (커맨드 패턴)  (0) 2017.09.07

Facade Pattern (퍼사드 패턴)

Facade Pattern


 

정의


어떤 sub-systeminterface에 대한 통합된 interface를 제공하고 facade에서 고수준 interface를 정의하기 때문에 sub-system을 쉽게 사용할 수 있다.



 

장점


더욱 더 간단한 interface를 만들 수 있다는 것이다


또한 client부와 sub-system을 분리할 수도 있다


만약 clientfacade로 만들었다고 하면 interface가 달라졌을 때 client는 변경할 필요 없이 facade만 변경하면 된다


그리고 표면에 드러나 있는 interface를 사용하고 그 내부는 알 필요가 없다.


 

l  최소지식원칙(=Law of Demeter)


system design에 있어서 어떤 object든 그 object와 상호작용하는 class의 수에 주의해야 하며, object들과 어떤 식으로 상호작용하는지도 주의해야 한다는 원칙이다.


위 원칙을 지키기 위해서는 4 종류의 object method만 호출하면 되는데, 다음과 같다.


1.    객체 자체


2.    Methodparameter로 전달된 object


3.    method에서 생성하거나 instance를 만든 object


4.    object에 속하는 구성요소 (A has B)




Adapter Pattern, Facade Pattern, Decorator Pattern의 차이점


l  Adapter Pattern : interface를 다른 interface로 변환하는 것이다. Interface를 변경해서 client에서 필요로 하는 interface로 적응시키는 위한 용도로 호환성을 위한다.


l  Facade Pattern : interface를 간단하게 바꾸는 것으로, 어떤 sub-system에 대한 간단한 interface를 제공하기 위한 용도로 사용되며 간편할 때 사용한다.


l  Decorator Pattern : interface를 바꾸지 않고 기능만 추가하는 것으로 Object를 감싸서 새로운 기능을 추가하기 위해서 사용한다.



 

정리


1.    기존 class를 사용하려고 하는데 interface가 맞지 않으면 adapter pattern을 사용한다.


2.    interface 또는 여러 interface를 단순화 시키거나 통합시켜야 한다면 facade pattern을 사용한다.


3.    Adapter Patterninterfaceclient가 원하는 interface로 바꾸는 역할을 하고 Facade Pattern은 복잡한 sub-system과 분리하는 역할을 한다.


4.    Adapter Pattern은 다중 Adapter로 만들 수 있고 Façade Pattern은 한 sub-system에 여러 개 만들 수 있다.

'분류 전체보기'에 해당되는 글 125건

1 ··· 3 4 5 6 7 8 9 ··· 13 →