1 / 42

Compose and render the scene

Learn about model setup, rendering processes, and optimization techniques using OpenGL for faster complex model rendering. Explore immediate mode, display lists, and vertex arrays.

pbrandi
Download Presentation

Compose and render the scene

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Compose and render the scene Hanyang University Jungsik Park

  2. 모델의 배치 • 장면에 모델을 구성하는 기본적인 코드 순서는 다음과 같다. • 1. 모델뷰 행렬 초기화(glIdentity) • 2. 시점이동(gluLookat 혹은 glTranslate,glRotate) • 3. 현재의 모델뷰행렬 스택에 저장(glPushMatrix) • 4. 모델 배치(glTranslate,glRotate) • 5. 모델 그리기 • 6. 모델뷰행렬 스택으로부터 모델을 배치해기 이전의 모델뷰행렬 복원 (glPopMatrix) • 3~6 반복

  3. 모델의 배치 void RenderScene(void) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, 1.0f, 1.0f, 1000.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 200.0, 200.0, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); glViewport(0, 0, windowWidth, windowHeight); // Clear the window with current clearing color glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Draw objects in the scene DrawModels(); // Flush drawing commands glutSwapBuffers(); } void DrawModels(void) { // Draw plane that the objects rest on glColor3f(0.0f, 0.0f, 0.90f); // Blue glNormal3f(0.0f, 1.0f, 0.0f); glBegin(GL_QUADS); glVertex3f(-100.0f, -25.0f, -100.0f); glVertex3f(-100.0f, -25.0f, 100.0f); glVertex3f(100.0f, -25.0f, 100.0f); glVertex3f(100.0f, -25.0f, -100.0f); glEnd(); // Draw red cube glColor3f(1.0f, 0.0f, 0.0f); glutSolidCube(48.0f); // Draw green sphere glColor3f(0.0f, 1.0f, 0.0f); glPushMatrix(); glTranslatef(-60.0f, 0.0f, 0.0f); glutSolidSphere(25.0f, 50, 50); glPopMatrix(); // Draw yellow cone glColor3f(1.0f, 1.0f, 0.0f); glPushMatrix(); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); glTranslatef(60.0f, 0.0f, -24.0f); glutSolidCone(25.0f, 50.0f, 50, 50); glPopMatrix(); // Draw magenta torus glColor3f(1.0f, 0.0f, 1.0f); glPushMatrix(); glTranslatef(0.0f, 0.0f, 60.0f); glutSolidTorus(8.0f, 16.0f, 50, 50); glPopMatrix(); // Draw cyan octahedron glColor3f(0.0f, 1.0f, 1.0f); glPushMatrix(); glTranslatef(0.0f, 0.0f, -60.0f); glScalef(25.0f, 25.0f, 25.0f); glutSolidOctahedron(); glPopMatrix(); }

  4. 복잡한 모델의 렌더링을 위한 빠른 처리 방법

  5. OpenGL의 렌더링 방식 • Immediate mode • Display List • Vertex array

  6. Immediate mode • glBegin() ~ glEnd() 를 이용하는 방법 • glVertex*() 등의함수를 한 번 호출할 때마다 하나의 버텍스 정보와 명령을 그래픽 하드웨어에 전달하므로 다음과 같은 단점이 있다. • 함수 호출 횟수가 많다. • 전송 대역폭을 제대로 활용하지 못한다. • 그래픽 하드웨어에 작은 데이터를 여러 번 보내기 때문 • 그래픽 하드웨어의 병렬 처리능력을 제대로 활용하지 못한다. • 기하 요소를 그리기 위한 버텍스 정보가 모일 때까지 기다려야 한다. • 적은 수의 폴리곤을 갖는 간단한 모델을 그리는 경우엔 문제가 되지 않지만, 수많은 폴리곤으로 구성되는 복잡한 모델을 그리는 경우엔 상당한 속도 저하 발생.

  7. Display List • 렌더링 명령 및 버텍스 정보를 미리 low-level 하드웨어 명령으로 컴파일하여 사용하는 방법. • 복잡한 모델을 그리기 위한 일련의 명령과 계산을 컴파일해 둠으로써렌더링 시 빠르게 일괄 처리할 수 있다. • 컴파일된 명령의 재사용이 가능하므로 불필요한 반복 작업을 피할 수 있다. • 정적인 모델에 대해서만 적용이 가능하다.

  8. Display List • voidglNewList (GLuintlist, GLenummode) • glNewList() ~ glEndList() 사이의 OpenGL 명령들을 묶어 컴파일하여 display list로 만든다. • list : display list의 이름 • mode • GL_COMPILE : 컴파일만 수행 • GL_COMPILE_AND_EXECUTE : 컴파일 후 한 번 그리기 수행

  9. Display List • Gluint glGenLists (GLsizei range) • 현재 사용가능한 display list 이름의 범위를 예약하고 시작 값을 리턴 • a = glGenLists(b); 를 실행할 경우 • a ~ a+b-1 의 display list 이름이 예약되고 범위 내의 값으로 display list를 만들어 사용할 수 있다. • void glDeleteLists (GLuint list, GLsizei range) • 사용중이거나 예약되어 있는 display list 이름을 반납한다. • glDeleteLists(a, b); 를 실행한 경우 • a ~ a+b-1 의 display list 이름을 반납한다. • void glCallList (GLuint list) • list를 이름으로 갖는 display list를 실행한다. • void glCallLists (GLsizei n, GLenum type, const GLvoid *lists) • display list 이름을 배열로 관리할 경우 여러 개의 display list를 한 번에 실행. • n : 배열에 담긴 display list의 개수 • type : display list 이름의 타입(GL_UNSIGNED_INT, GL_UNSIGNED_BYTE) • lists : 배열의 시작 주소

  10. Vertex array • 한 버텍스 단위로 버텍스 정보를 전송하는 immediate mode와 달리 배열을 이용하여 많은 수의 버텍스 정보를 한 번에 전송한 뒤, 렌더링하는 방법. • 데이터 전송 대역폭과 그래픽 하드웨어의 병렬 처리 능력을 활용 • 정적인 모델 뿐만 아니라 동적인 모델에도 적용 가능 • vertex array 관련 함수에 대해서는 modeling hierarchy 에서 설명.

  11. OBJ 형식 모델 파일의 추출 및 OPENGL에서의 사용

  12. Obj format • Wavefront OBJ (object) files are used by Wavefront's Advanced Visualizer application to store geometric objects composed of lines, polygons, and free-form curves and surfaces. • http://www.fileformat.info/format/wavefrontobj/egff.htm • 버텍스 좌표, 법선 벡터, 텍스처 좌표, 삼각형을 구성하는 버텍스의 인덱스, 재질 속성 파일이름(.mtl) 등이 저장됨. • 3DS Max, Maya 등의 3D 모델링 툴에서 모델을 만든 후, obj 파일 형식으로 내보내어 OpenGL 어플리케이션에서 로드한다.

  13. 3ds max에서 obj 파일 추출

  14. 재질 속성

  15. 색상 변경(diffuse), material editor 상단의 변경된 색상의 원을 클릭하여 모델로 드래그하면 모델 색상이 변경된다.

  16. 색상이 변경되었다.

  17. 이미지 텍스처 매핑

  18. 마찬가지로 변경된 원을 클릭 후 모델에 드래그하면 모델의 재질속성이 변경된다.(Show Standart Map in Viewport가 활성화되어야 확인 가능)

  19. menu->file->export 혹은 export selected

  20. 경로 및 파일 형식(Wavefront Object, *.obj) 선택

  21. 재질 속성을 사용하지 않을 경우 • 재질속성을 사용할 경우(재질속성은 mtl 파일로 추출)

  22. Obj format parser • nVidia OpenGL SDK의 nvModel 라이브러리 이용 • OpenGL SDK 다운로드 • http://developer.nvidia.com/object/sdk_home.html

  23. visual studio에서 obj parser에 필요한 각 헤더 파일과 라이브러리 파일 폴더 경로를 지정 및 dll 파일 복사 • 헤더파일 경로 • C:\Program Files\NVIDIA Corporation\NVIDIA OpenGL SDK 10\common\include • C:\Program Files\NVIDIA Corporation\NVIDIA OpenGL SDK 10\common\GLEW\include • C:\Program Files\NVIDIA Corporation\NVIDIA OpenGL SDK 10\common\nvImage\include • C:\Program Files\NVIDIA Corporation\NVIDIA OpenGL SDK 10\common\nvModel\include • 라이브러리 파일 경로 • C:\Program Files\NVIDIA Corporation\NVIDIA OpenGL SDK 10\common\GLEW\lib • C:\Program Files\NVIDIA Corporation\NVIDIA OpenGL SDK 10\common\nvImage\lib • C:\Program Files\NVIDIA Corporation\NVIDIA OpenGL SDK 10\common\nvModel\lib • dll 파일 • C:\Program Files\NVIDIA Corporation\NVIDIA OpenGL SDK 10\bin • 에서 glew32.dll, nvModel.dll, nvImage.dll을 C:\Windows\system32 폴더에 복사

  24. nvModel • obj 파일에서 버텍스 좌표, 법선 벡터, 텍스처 좌표등을 로드하여 배열 형태로 메모리에 저장. • 렌더링할 때 버텍스 정보가 저장된 배열 주소를 이용하여 vertex array 방식으로 렌더링 • nvModel은 obj 파일만 읽어들일 뿐, 재질속성 파일(.mtl) 및 텍스처 이미지 파일은 읽어들이지 않음 • 조명에 대한 반사도(색상)이 필요하면 mtl 파일 parser를 따로 작성해야 함. • 혹은, mtl 파일을 생성하지 않고, 모델을 렌더링할 때 glColor*로 직접 색상 지정. • 텍스처의 경우 nvImage를 이용하여 이미지 파일을 따로 로드하여 텍스처 객체를 생성해 주어야 함.

  25. nvModel • 모델 로드 방법 nv::Model *model = new nv::Model; // 모델 로드 model->loadModelFromFile(model_filename); // 중복된 버텍스 인덱스를 제거 model->removeDegeneratePrims(); // 법선 벡터 계산 model->computeNormals(); // 삼각형 메쉬로 렌더링할 수 있도록 vertex arrays 생성 model->compileModel( nv::Model::eptAll);

  26. nvModel • 모델 렌더링 방법 glVertexPointer( model->getPositionSize(), GL_FLOAT, model->getCompiledVertexSize() * sizeof(float), model->getCompiledVertices()); glNormalPointer( GL_FLOAT, model->getCompiledVertexSize() * sizeof(float), model->getCompiledVertices() + model->getCompiledNormalOffset()); glEnableClientState( GL_VERTEX_ARRAY); glEnableClientState( GL_NORMAL_ARRAY); if ( model->hasTexCoords()) { glTexCoordPointer( model->getTexCoordSize(), GL_FLOAT, model->getCompiledVertexSize() * sizeof(float), model->getCompiledVertices() + model->getCompiledTexCoordOffset()); glEnableClientState( GL_TEXTURE_COORD_ARRAY); } glDrawElements( GL_TRIANGLES, model->getCompiledIndexCount( nv::Model::eptTriangles), GL_UNSIGNED_INT, model->getCompiledIndices( nv::Model::eptTriangles)); glDisableClientState( GL_VERTEX_ARRAY); glDisableClientState( GL_NORMAL_ARRAY); glDisableClientState( GL_TEXTURE_COORD_ARRAY);

  27. EXAMPLE – 많은 수의 큐브를 그리는 예제(IMMEDIATE MODE 및 DISPLAY LIST 이용)

  28. 기본 뼈대 작성 #include <math.h> #include <time.h> #include <stdlib.h> #include <gl/glut.h> #define PI 3.141592 typedef struct _Vector3D { float x; float y; float z; } Vector3D; static GLfloat angle, velocity = 5; static Vector3D pos = {0.0, -20.0, 0.0}; void DrawCube(CubeData *pData); void ChangeSize(GLsizei width, GLsizei height) { GLfloat fAspect = (GLfloat)width/(GLfloat)height; GLfloat nRange = height/4.0; if(height == 0) height = 1; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, fAspect, 1.0, 4000.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void SpecialKeys(int key, int x, int y) { if(key == GLUT_KEY_UP) { pos.x -= (velocity*sin(angle*PI/180.0)); pos.z += (velocity*cos(angle*PI/180.0)); } if(key == GLUT_KEY_DOWN) { pos.x += (velocity*sin(angle*PI/180.0)); pos.z -= (velocity*cos(angle*PI/180.0)); } if(key == GLUT_KEY_LEFT) angle -= 5.0f; if(key == GLUT_KEY_RIGHT) angle += 5.0f; angle = (GLfloat)((const int)angle % 360); glutPostRedisplay(); } // 모델이나상태변수등의초기화함수 void SetupRC() { glClearColor(0.0, 0.0, 0.0, 0.0); glEnable(GL_DEPTH_TEST); } void RenderScene(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glRotatef(angle, 0.0f, 1.0f, 0.0f); glTranslatef(pos.x, pos.y, pos.z); glutSwapBuffers(); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(600, 600); glutCreateWindow("Example"); glutReshapeFunc(ChangeSize); glutSpecialFunc(SpecialKeys); glutDisplayFunc(RenderScene); SetupRC(); glutMainLoop(); return 0; } 키보드 상하키로 전/후진 키보드 좌우키로 회전

  29. 큐브의 위치와 색상을 저장할 구조체 선언 및 임의의 위치에 배치 #define MAX_CUBE 10000 typedef struct _CubeData { Vector3D pos; Vector3D angle; Vector3D color; } CubeData; CubeData cData[MAX_CUBE]; • stdlib.h, time.h 포함하고,SetupRC() 에서 다음을 추가 srand((unsigned char)time(NULL)); for (int i = 0 ; i < MAX_CUBE ; i++ ) { cData[i].pos.x = rand() % 8000 - 4000; cData[i].pos.z = rand() % 8000 - 4000; cData[i].angle.x = rand() % 360; cData[i].angle.y = rand() % 360; cData[i].angle.z = rand() % 360; cData[i].color.x = (float)(rand() % 101) / 100.0; cData[i].color.y = (float)(rand() % 101) / 100.0; cData[i].color.z = (float)(rand() % 101) / 100.0; } 모델들을 월드에 배치하기 위한 modelview transformation 에서 사용할 정보 랜덤한 위치로 modelview transformation 시키기 위한 좌표 및 랜덤 색상 생성

  30. 큐브 그리는 함수 작성 및 렌더링 void DrawCube(CubeData *pData) { glMatrixMode(GL_MODELVIEW); glTranslatef(pData->pos.x, 0.0, pData->pos.z); glRotatef(pData->angle.x, 1.0, 0.0, 0.0); glRotatef(pData->angle.y, 0.0, 1.0, 0.0); glRotatef(pData->angle.z, 0.0, 0.0, 1.0); glColor3f(pData->color.x, pData->color.y, pData->color.z); glBegin(GL_QUADS); glVertex3f(10.0,10.0,10.0); glVertex3f(10.0,-10.0,10.0); glVertex3f(-10.0,-10.0,10.0); glVertex3f(-10.0,10.0,10.0); glVertex3f(10.0,10.0,-10.0); glVertex3f(10.0,-10.0,-10.0); glVertex3f(-10.0,-10.0,-10.0); glVertex3f(-10.0,10.0,-10.0); glVertex3f(10.0,10.0,-10.0); glVertex3f(10.0,10.0,10.0); glVertex3f(-10.0,10.0,10.0); glVertex3f(-10.0,10.0,-10.0); glVertex3f(10.0,-10.0,-10.0); glVertex3f(10.0,-10.0,10.0); glVertex3f(-10.0,-10.0,10.0); glVertex3f(-10.0,-10.0,-10.0); glVertex3f(10.0,10.0,10.0); glVertex3f(10.0,10.0,-10.0); glVertex3f(10.0,-10.0,-10.0); glVertex3f(10.0,-10.0,10.0); glVertex3f(-10.0,10.0,10.0); glVertex3f(-10.0,10.0,-10.0); glVertex3f(-10.0,-10.0,-10.0); glVertex3f(-10.0,-10.0,10.0); glEnd(); } • RenderScene()에서 glutSwapBuffers(); 위에 다음을 추가 for ( int i = 0 ; i < MAX_CUBE ; i++ ) { glPushMatrix(); DrawCube(cData+i); glPopMatrix(); } 오일러 각으로 모델을 3차원 회전시키고 월드 상의 [pos.x, pos.y, pos.z] 위치로 이동시킴으로서 모델의 배치 수행

  31. 실행화면 • MAX_CUBE의 값을 크게 하면 굉장히 느려진다. MAX_CUBE = 10000 32 fps MAX_CUBE = 50000 7 fps

  32. Display list의 사용 • Display list 이름으로 사용할 전역 변수 선언. • GLuint cubeDList; • SetupRC()에서 display list 이름을 예약하고 큐브를 그리는 부분을 RenderScene()으로부터 glNewList() ~ glEndList() 사이로 옮긴다. • RenderScene()에서 glCallList()로 Display list를 실행시킨다.

  33. 실행화면 • Display list를 사용할 경우 성능 향상. • 이 예제에서는 간단한 모델이 많은 scene 전체를 display list로 만들었기 때문에 성능 향상이 크지는 않다. • 복잡한 모델 단위로 display list를 만들어 사용한다면 성능 향상이 클 것이다. Display list 사용 MAX_CUBE = 50000 12 fps Immediate mode 사용 MAX_CUBE = 50000 7 fps

  34. EXAMPLE – OBJ 형식의 모델 파일 로드 및 렌더링

  35. Obj 파일을 로드하기 위한 함수 작성 nv::Model* LoadModel(const char *filename) { nv::Model *model = new nv::Model; if (model->loadModelFromFile(filename)) { // remove any primitives with duplicate indices, as they might confuse adjacency model->removeDegeneratePrims(); // compute normal model->computeNormals(); // make the model efficient for rendering with vertex arrays model->compileModel( nv::Model::eptAll); } else { fprintf(stderr, "Error loading model '%s'\n", filename); delete model; model = 0; } return model; } 모델의 로드가 성공하면 모델 정보가 저장된 nv::Model 클래스의 포인터를 리턴하고, 실패하면 NULL 포인터 리턴

  36. 텍스처 이미지를 로드하기 위한 함수 작성 GLuint LoadImage(const char *filename) { nv::Image img; GLuint tex; if(img.loadImageFromFile(texture_filename)) { // 텍스처객체를생성하고텍스처객체에이미지데이터복사 glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); glTexImage2D( GL_TEXTURE_2D, 0, img.getInternalFormat(), img.getWidth(), img.getHeight(), 0, img.getFormat(), img.getType(), img.getLevel(0)); } else { fprintf(stderr, "Error loading model '%s'\n", filename); tex = 0; } return tex; } nvImage 라이브러리는 “png”, “dds”, “hdr” 형식의 이미지만 로드할 수 있다. 이미지 파일의 로드가 성공하면 이미지 데이터를 가진 텍스처 객체의 id를 리턴하고, 실패하면 0을 리턴(id가 0이면 텍스처가 없음을 나타냄) 텍스처 관련 함수는 Discrete techs 에서 설명한다.

  37. 로드한 모델을 그리기 위한 함수 작성 void DrawModel(nv::Model *model, GLuint tex, Vector3D color) { if (model) { // 모델색상지정 glColor3f(color.x, color.y, color.z); // 텍스처사용on glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex); // vertex array로사용할배열지정 glVertexPointer( model->getPositionSize(), GL_FLOAT, model->getCompiledVertexSize() * sizeof(float), model->getCompiledVertices()); glNormalPointer( GL_FLOAT, model->getCompiledVertexSize() * sizeof(float), model->getCompiledVertices() + model->getCompiledNormalOffset()); // vertex array 사용on glEnableClientState( GL_VERTEX_ARRAY); glEnableClientState( GL_NORMAL_ARRAY); // 텍스처좌표가있을경우 if ( model->hasTexCoords()) { glTexCoordPointer( model->getTexCoordSize(), GL_FLOAT, model->getCompiledVertexSize() * sizeof(float) , model->getCompiledVertices() + model->getCompiledTexCoordOffset()); glEnableClientState( GL_TEXTURE_COORD_ARRAY); } // vertex array와vertex index를이용하여실제로그리는함수 glDrawElements( GL_TRIANGLES, model->getCompiledIndexCount( nv::Model::eptTriangles), GL_UNSIGNED_INT , model->getCompiledIndices( nv::Model::eptTriangles)); // vertex array 사용off glDisableClientState( GL_VERTEX_ARRAY); glDisableClientState( GL_NORMAL_ARRAY); glDisableClientState( GL_TEXTURE_COORD_ARRAY); // 텍스처사용off glDisable(GL_TEXTURE_2D); } } 전달받은 모델 클래스, 텍스처 객체, 모델 색상을 이용하여 모델을 그린다. vertex array 관련 함수는 modeling hierarchy 에서 설명한다.

  38. 모델 및 텍스처 로드 및 렌더링에 사용할 변수 선언 • nvModel.h, nvImage.h를 인클루드하고, 프로젝트 속성에서 nvModel.lib, nvImage.lib을 링크시키도록 설정 • 아래의 변수들을 전역 변수로 선언한다. // 모델 파일 및 이미지 파일 이름 const char *model_filename[2] = {"tree.obj", "treeBase.obj"}; const char *texture_filename = "leaf.png"; // 모델, 모델 색상, 텍스처 객체id nv::Model *treeModel[2]; Vector3D treeBaseColor = {0.4, 0.0, 0.0 }; GLuint treeTex;

  39. 나무 모델과 텍스처 로드 • SetupRC()에서 다음 코드를 추가 treeModel[0] = LoadModel(model_filename[0]); treeModel[1] = LoadModel(model_filename[1]); treeTex = LoadImage(texture_filename); 나무 모델은 나무 기둥(treebase.obj)과 나무 잎사귀부분(tree.obj, leaf.png)의 두 개의 모델로 구성된다. nvImage 라이브러리는 “png”, “dds”, “hdr” 형식의 이미지만 로드할 수 있다.

  40. 나무 모델의 렌더링 • RenderScene()에서 다음의 코드를 추가 for ( int i = 0 ; i < 8 ; i++ ) { glPushMatrix(); glRotatef(i*360.0/8.0, 0.0, 1.0, 0.0); glTranslatef(500.0, 0.0, 0.0); DrawModel(treeModel[0], treeTex, treeBaseColor); DrawModel(treeModel[1], 0, treeBaseColor); glPopMatrix(); } 월드의 중심으로부터 반경 500 거리에 8개의 나무를 그린다.

More Related