Draw the basic Geometry Objects Hanyang University Jungsik Park
VERTEX ATTRIBUTE AND GEOMETRIC PRIMITIVES
Vertex Vertex Vertex attributes 3D 공간상의 점, 또는 기본 도형(삼각형, 폴리곤 등)의 꼭지점 Vertex coordinate Composition of primitives Vertex color Normal vector Texture coordinate
Vertex coordinate glVertex*() vertex의 3D/2D 좌표를 지정. vertex 속성 중 가장 중요한 속성으로 glBegin() ~ glEnd() 사이에 위치시킴으로써 frame buffer에 도형을 그리게 된다. 그 외의 속성은 지정하지 않아도 도형을 그릴 수 있으나 vertex 좌표를 지정하지 않으면 도형을 그릴 수 없다. glFlush()를 호출함으로써 frame buffer의 내용을 화면에 출력한다.
Vertex coordinate OpenGL coordinate system 3D cartesian coordinate system x, y, z 축 각각 [-1.0, 1.0]의 범위를 갖는 정규화된 직육면체의 view volume 내의 물체를 그린다. 일반적으로 더 큰 view volume, 혹은 원근감을 표현할 수 있는 frustum view volume 내의 물체를 그리기 위해 view volume 변환을 먼저 수행한다. 2D의 경우 z=0인 평면상의 물체를 그린다.
Primitives Geometric primitives vertex들로 구성되며, vertex의 좌표는 glVertex*()로 지정 면을 가지는 도형의 경우 vertex들이 반시계 방향의 순서를 가지도록 지정되어야 한다.
Polygon construction rules 폴리곤 구성의 규칙 폴리곤을 구성하는 모든 vertex는 한 평면상에 위치해야 한다. 폴리곤을 이루는 선들은 서로 교차해서는 안 되면, 폴리곤의 전체적인 모양은 볼록해야 한다. 위의 규칙을 항상 만족하는 삼각형을 많이 사용
Polygon construction rules 다음 도형을 하나의 폴리곤으로 그리는 경우 잘못된 결과가 나타난다. glBegin(GL_QUADS); glVertex2f(-0.5, -0.5); glVertex2f(0.5, 0.5); glVertex2f(-0.5, 0.5); glVertex2f(0.5, -0.5); glEnd();
Example code #include <GL/glut.h> int primitive[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP , GL_POLYGON, GL_QUADS, GL_TRIANGLES}; int index; void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT); glBegin(primitive[index]); glVertex2f(-0.5, 0.0); glVertex2f(-0.3536, 0.3536); glVertex2f(0.0, 0.5); glVertex2f(0.3536, 0.3536); glVertex2f(0.5, 0.0); glVertex2f(0.3536, -0.3536); glVertex2f(0.0, -0.5); glVertex2f(-0.3536, -0.3536); glEnd(); glFlush(); } void mykeyboard(unsigned char key, int x, int y) { if (key == 'n' || key == 'N') index++; else if (key == 'p' || key == 'P') index--; if (index < 0) index = 6; if (index > 6) index = 0; glutPostRedisplay(); } int main(int argc, char** argv){ glutCreateWindow(“primitives"); glutDisplayFunc(mydisplay); glutKeyboardFunc(mykeyboard); glutMainLoop();
Drawing with fewer vertices GL_TRIANGLE_STRIP, GL_QUAD_STRIP GL_TRIANGLE_FAN Advantages to using fewer vertices 메모리 공간 절약 연산수 감소 및 그래픽 카드로의 데이터 전송 대역폭 절약 P0 P1 P2 P3 P4 P5 P6
Example code - GL_TRIANGLE_STRIP void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_TRIANGLES); glVertex2f(-0.6, -0.2); // P0 glVertex2f(-0.5, 0.2); // P1 glVertex2f(-0.3, -0.2); // P2 glVertex2f(-0.2, 0.2); // P3 glVertex2f(0.0, -0.2); // P4 glVertex2f(0.1, 0.2); // P5 glVertex2f(0.3, -0.2); // P6 glVertex2f(0.4, 0.2); // P7 glEnd(); glFlush(); } GL_TRIANGLE_STRIP 사용 void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_TRIANGLE_STRIP); glVertex2f(-0.6, -0.2); // P0 glVertex2f(-0.5, 0.2); // P1 glVertex2f(-0.3, -0.2); // P2 glVertex2f(-0.2, 0.2); // P3 glVertex2f(0.0, -0.2); // P4 glVertex2f(0.1, 0.2); // P5 glVertex2f(0.3, -0.2); // P6 glVertex2f(0.4, 0.2); // P7 glEnd(); glFlush(); }
Example code – GL_TRIANGLE_FAN #include <math.h> #include <GL/glut.h> #define PI 3.141592 void mydisplay(){ GLfloat x, y, angle; glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_TRIANGLE_FAN); glVertex2f(0.0f, 0.0f); for(angle = 0.0f; angle < (2.0f*PI); angle += (PI/8.0f)) { x = 0.5f*sin(angle); y = 0.5f*cos(angle); glVertex2f(x, y); } glEnd(); glFlush(); int main(int argc, char** argv){ glutCreateWindow("simple"); glutDisplayFunc(mydisplay); glutMainLoop();
Draw 3D object glVertex3*()로 3차원 좌표 지정(z축 추가) 아래 그림은 cube를 그린 예제 입체감을 표현하기 위해선 다음의 요소가 필요 perspective projection lighting & shading
Example code - Draw 3D object void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f); glBegin(GL_QUADS); glVertex3f(0.3,0.3,0.3); glVertex3f(0.3,-0.3,0.3); glVertex3f(-0.3,-0.3,0.3); glVertex3f(-0.3,0.3,0.3); glVertex3f(0.3,0.3,-0.3); glVertex3f(0.3,-0.3,-0.3); glVertex3f(-0.3,-0.3,-0.3); glVertex3f(-0.3,0.3,-0.3); glEnd(); glPopMatrix(); glFlush(); } void specialkeys(int key, int x, int y) { if(key == GLUT_KEY_UP) xRot-= 5.0f; if(key == GLUT_KEY_DOWN) xRot += 5.0f; if(key == GLUT_KEY_LEFT) yRot -= 5.0f; if(key == GLUT_KEY_RIGHT) yRot += 5.0f; if(key > 356.0f) xRot = 0.0f; if(key < -1.0f) xRot = 355.0f; yRot = 0.0f; yRot = 355.0f; // Refresh the Window glutPostRedisplay(); } int main(int argc, char** argv){ glutCreateWindow("simple"); glutDisplayFunc(mydisplay); glutSpecialFunc(specialkeys); glutMainLoop();
Vertex color OpenGL에서는 vertex 단위로 색상을 할당. glColor*() 선, 면의 색상은 구성하는 vertex들의 색을 interpolation하여 결정 glColor*() 색상은 인자의 수에 따라 RGBA, RGB로 지정 void glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void glColor3f (GLfloat red, GLfloat green, GLfloat blue); 각 채널의 값의 범위 인자가 실수인 경우 [0.0, 1.0] 인자가 정수인 경우 [0, 255]
Example code – vertex color #include <GL/glut.h> int primitive[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP , GL_POLYGON, GL_QUADS, GL_TRIANGLES}; int index; void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT); glBegin(primitive[index]); glColor3f(1.0, 0.0, 0.0); // red glVertex2f(-0.5, 0.0); glColor3f(0.0, 1.0, 0.0); // green glVertex2f(-0.3536, 0.3536); glColor3f(0.0, 0.0, 1.0); // blue glVertex2f(0.0, 0.5); glColor3f(0.5, 0.5, 0.5); // gray glVertex2f(0.3536, 0.3536); glColor3f(1.0, 1.0, 0.0); // yellow glVertex2f(0.5, 0.0); glColor3f(1.0, 0.0, 1.0); // magenta glVertex2f(0.3536, -0.3536); glColor3f(0.0, 1.0, 1.0); // cyan glVertex2f(0.0, -0.5); glColor3f(1.0, 1.0, 1.0); // white glVertex2f(-0.3536, -0.3536); glEnd(); glFlush(); } void mykeyboard(unsigned char key, int x, int y) { if (key == 'n' || key == 'N') index++; else if (key == 'p' || key == 'P') index--; if (index < 0) index = 6; if (index > 6) index = 0; glutPostRedisplay(); } int main(int argc, char** argv){ glutCreateWindow(“primitives"); glutDisplayFunc(mydisplay); glutKeyboardFunc(mykeyboard); glutMainLoop();
Other attributes Normal vector Texture coordinate 폴리곤 앞면의 법선 벡터. 폴리곤 단위가 아닌 vertex 단위로 지정. glNormal*() lighting, backface culling 등에 사용됨 Texture coordinate 폴리곤에 텍스쳐를 매핑할 때 폴리곤의 각 지점과 영상의 픽셀을 대응시키기 위한 좌표 glTexcoord*()
MANIPULATION OF THE OPENGL STATES
States Point size & line width Winding Backface culling Depth test Polygon mode Fill face Wireframe Point Shade model
States State를 변화시키는 방법 on/off 로 사용되는 state variable glEnable() / glDisable() depth test, lighting, texture mapping 등 그 외의 값을 가지는 state variable을 변화시키는 경우 glFrontFace(), glLineWidth() 등 해당 state variable 전용 함수
Point size & line width Point size Line width 점의 크기를 지정 void glPointSize(GLfloat size); 기본값은 1이고, 사용할 수 있는 값의 범위는 플랫폼에 따라 다르다. Point size로 사용할 수 있는 값의 범위를 알아내는 법 Line width 선의 두께를 지정 void glLineWidth (GLfloat width); Line width로 사용할 수 있는 값의 범위를 알아내는 법 GLfloat sizes[2]; GLfloat step; glGetFloatv(GL_POINT_SIZE_RANGE,sizes); glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step); GLfloat sizes[2]; GLfloat step; glGetFloatv(GL_LINE_WIDTH_RANGE,sizes); glGetFloatv(GL_LINE_WIDTH_GRANULARITY,&step);
Example – line width void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); GLfloat y; GLfloat fSizes[2]; GLfloat fCurrSize; glGetFloatv(GL_LINE_WIDTH_RANGE,fSizes); fCurrSize = fSizes[0]; for(y = -0.9f; y < 0.9f; y += 0.2f) { glLineWidth(fCurrSize); glBegin(GL_LINES); glVertex2f(-0.8f, y); glVertex2f(0.8f, y); glEnd(); fCurrSize += 1.0f; } glFlush();
Winding 폴리곤을 구성하는 vertex들의 순서를 지정 폴리곤의 앞면과 뒷면을 결정하기 위한 방법 glFrontFace(GL_CCW); 반시계 방향으로 vertex 지정(디폴트) glFrontFace(GL_CW); 시계 방향으로 vertex 지정 앞면과 뒷면을 결정함으로써 보이지 않는 부분을 그리지 않거나, 앞면과 뒷면에 각각 다른 색상,재질을 지정할 수 있다.
Backface culling 폴리곤의 보이지 않는 면(뒷면)을 제거하는 옵션 glEnable(GL_CULL_FACE); glDisable(GL_CULL_FACE); 불필요한 면을 그리지 않음으로써 성능상의 이득을 얻을 수 있다. 종이 같은 얇은 평면, 유리와 같은 투명한 물체는 뒷면도 그려져야 하므로 backface culling을 사용하지 않는다.
Depth test 어떤 물체가 다른 물체의 앞에 있는 경우, 뒤의 물체가 그려지지 않도록 한다. glEnable(GL_DEPTH_TEST); depth buffer를 이용하여 픽셀을 그릴 때마다 z값을 비교하여 높은 z값을 갖는 픽셀로 갱신함으로써 뒤의 물체가 보이지 않도록 한다. glDisable(GL_DEPTH_TEST); z값과 관계없이 나중에 그려지는 물체를 그린다. backface culling과 달리 z값을 비교하여 그려지는지 여부를 결정하기 때문에 depth test로 인한 성능 이득은 없지만 사실적인 표현을 위해 필요한 요소. backface culling : 아예 그리지 않음 depth test : 그렸지만 보이지 않음
Polygon mode 폴리곤을 색칠된 면으로 그리거나, wireframe으로 그리는 옵션 void glPolygonMode (GLenum face, GLenum mode); face : GL_FRONT, GL_BACK, GL_FRONT_AND_BACK mode : GL_FILL, GL_LINE, GL_POINT 예 : 물체의 앞면을 wireframe으로 그릴 경우 glPolygonMode(GL_FRONT, GL_LINE);
Shade model 폴리곤의 면을 색칠하는 방법 지정 glShadeModel(GL_SMOOTH); vertex 색상을 interpolation하여 면의 각 부분을 색칠 glShadeModel(GL_FLAT); 폴리곤을 구성하는 vertex 중 마지막 vertex의 색상으로 면을 색칠
Example code #include <stdio.h> #include <GL/glut.h> bool bBackfaceCull = false; bool bDepthTest = false; bool bWindCCW = false; bool bShadeSmooth = false; bool bWireFrame = false; static GLfloat xRot = 0.0f; static GLfloat yRot = 0.0f; void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); if (bBackfaceCull) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); if (bDepthTest) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); if (bWindCCW) glFrontFace(GL_CCW); else glFrontFace(GL_CW); if (bShadeSmooth) glShadeModel(GL_SMOOTH); else glShadeModel(GL_FLAT); if (bWireFrame) glPolygonMode(GL_FRONT, GL_LINE); else glPolygonMode(GL_FRONT, GL_FILL); glPushMatrix(); glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f);
Example code(cont’d) glBegin(GL_QUADS); // Front Face glColor3f(1.0f, 1.0f, 1.0f); glVertex3f(0.3,0.3,0.3); // White glColor3f(1.0f, 1.0f, 0.0f); glVertex3f(0.3,-0.3,0.3); // Yellow glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(-0.3,-0.3,0.3); // Red glColor3f(1.0f, 0.0f, 1.0f); glVertex3f(-0.3,0.3,0.3); // Magenta // Back Face glColor3f(0.0f, 1.0f, 1.0f); glVertex3f(0.3,0.3,-0.3); // Cyan glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(0.3,-0.3,-0.3); // Green glColor3f(0.0f, 0.0f, 0.0f); glVertex3f(-0.3,-0.3,-0.3); // Black glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(-0.3,0.3,-0.3); // Blue // Top Face // Bottom Face
Example code(cont’d) // Left face glColor3f(1.0f, 1.0f, 1.0f); glVertex3f(0.3,0.3,0.3); // White glColor3f(0.0f, 1.0f, 1.0f); glVertex3f(0.3,0.3,-0.3); // Cyan glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(0.3,-0.3,-0.3); // Green glColor3f(1.0f, 1.0f, 0.0f); glVertex3f(0.3,-0.3,0.3); // Yellow // Right face glColor3f(1.0f, 0.0f, 1.0f); glVertex3f(-0.3,0.3,0.3); // Magenta glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(-0.3,0.3,-0.3); // Blue glColor3f(0.0f, 0.0f, 0.0f); glVertex3f(-0.3,-0.3,-0.3); // Black glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(-0.3,-0.3,0.3); // Red glEnd(); glPopMatrix(); // Show the graphics glFlush(); } void specialkeys(int key, int x, int y) { if(key == GLUT_KEY_UP) xRot-= 5.0f; if(key == GLUT_KEY_DOWN) xRot += 5.0f; if(key == GLUT_KEY_LEFT) yRot -= 5.0f; if(key == GLUT_KEY_RIGHT) yRot += 5.0f; if(key > 356.0f) xRot = 0.0f; if(key < -1.0f) xRot = 355.0f; if(key > 356.0f) yRot = 0.0f; if(key < -1.0f) yRot = 355.0f; glutPostRedisplay();
Example code(cont’d) void mykeyboard(unsigned char key, int x, int y) { switch (key) case 'b': case 'B': bBackfaceCull = !bBackfaceCull; if (bBackfaceCull) printf("backface culling : on\n"); else printf("backface culling : off\n"); break; case 'd': case 'D': bDepthTest = !bDepthTest; if (bDepthTest) printf("depth test : on\n"); else printf("depth test : off\n"); case 'w': case 'W': bWireFrame = !bWireFrame; if (bWireFrame) printf("draw wireframe\n"); else printf("fill face\n"); case 's': case 'S': bShadeSmooth = !bShadeSmooth; if (bShadeSmooth) printf("smooth shading\n"); else printf("flat shading\n"); case 'c': case 'C': bWindCCW = !bWindCCW; if (bWindCCW) printf("wind counter-clockwise\n"); else printf("wind clockwise\n"); } glutPostRedisplay(); int main(int argc, char** argv){ glutCreateWindow("simple"); glutDisplayFunc(mydisplay); glutKeyboardFunc(mykeyboard); glutSpecialFunc(specialkeys); glutMainLoop();