320 likes | 373 Views
Draw the basic Geometry Objects. Hanyang University Jungsik Park. VERTEX ATTRIBUTE AND GEOMETRIC PRIMITIVES. Vertex. Vertex 3D 공간상의 점 , 또는 기본 도형 ( 삼각형 , 폴리곤 등 ) 의 꼭지점 Vertex attributes Vertex coordinate Composition of primitives Vertex color Normal vector Texture coordinate.
E N D
Draw the basic Geometry Objects Hanyang University Jungsik Park
Vertex • Vertex • 3D 공간상의 점, 또는 기본 도형(삼각형, 폴리곤 등)의 꼭지점 • Vertex attributes • 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들이 반시계방향의 순서를 가지도록 지정되어야 한다.
폴리곤 구성의 규칙 폴리곤을 구성하는 모든 vertex는 한 평면상에 위치해야 한다. 폴리곤을 이루는 선들은 서로 교차해서는 안 되면, 폴리곤의 전체적인 모양은 볼록해야 한다. 위의 규칙을 항상 만족하는 삼각형을 많이 사용 Polygon construction rules
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 • 메모리 공간 절약 • 연산수 감소 및 그래픽 카드로의 데이터 전송 대역폭 절약 P2 P3 P0 P1 P4 P6 P5
Example code - GL_TRIANGLE_STRIP • GL_TRIANGLES 사용 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.3, -0.2); // P2 glVertex2f(-0.5, 0.2); // P1 glVertex2f(-0.2, 0.2); // P3 glVertex2f(-0.3, -0.2); // P2 glVertex2f(-0.2, 0.2); // P3 glVertex2f(0.0, -0.2); // P4 glVertex2f(0.0, -0.2); // P4 glVertex2f(-0.2, 0.2); // P3 glVertex2f(0.1, 0.2); // P5 glVertex2f(0.0, -0.2); // P4 glVertex2f(0.1, 0.2); // P5 glVertex2f(0.3, -0.2); // P6 glVertex2f(0.3, -0.2); // P6 glVertex2f(0.1, 0.2); // P5 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); 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); 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; if(key > 356.0f) yRot = 0.0f; if(key < -1.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 단위로 색상을 할당. • 선, 면의 색상은 구성하는 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 • 폴리곤 앞면의 법선 벡터. 폴리곤 단위가 아닌 vertex 단위로 지정. • glNormal*() • lighting, backface culling 등에 사용됨 • Texture coordinate • 폴리곤에 텍스쳐를 매핑할 때 폴리곤의 각 지점과 영상의 픽셀을 대응시키기 위한 좌표 • glTexcoord*()
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 • 점의 크기를 지정 • void glPointSize(GLfloat size); • 기본값은 1이고, 사용할 수 있는 값의 범위는 플랫폼에 따라 다르다. • Point size로 사용할 수 있는 값의 범위를 알아내는 법 • Line width • 선의 두께를 지정 • void glLineWidth (GLfloat width); • 기본값은 1이고, 사용할 수 있는 값의 범위는 플랫폼에 따라 다르다. • 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 glColor3f(0.0f, 1.0f, 1.0f); glVertex3f(0.3,0.3,-0.3); // Cyan glColor3f(1.0f, 1.0f, 1.0f); glVertex3f(0.3,0.3,0.3); // White 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 // Bottom Face 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 glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(-0.3,-0.3,0.3); // Red glColor3f(0.0f, 0.0f, 0.0f); glVertex3f(-0.3,-0.3,-0.3); // Black
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"); break; case 'w': case 'W': bWireFrame = !bWireFrame; if (bWireFrame) printf("draw wireframe\n"); else printf("fill face\n"); break; case 's': case 'S': bShadeSmooth = !bShadeSmooth; if (bShadeSmooth) printf("smooth shading\n"); else printf("flat shading\n"); break; case 'c': case 'C': bWindCCW = !bWindCCW; if (bWindCCW) printf("wind counter-clockwise\n"); else printf("wind clockwise\n"); break; } glutPostRedisplay(); } int main(int argc, char** argv){ glutCreateWindow("simple"); glutDisplayFunc(mydisplay); glutKeyboardFunc(mykeyboard); glutSpecialFunc(specialkeys); glutMainLoop(); }