정점배열
육면체 그리기
GLfloat MyVertices[8][3] = {{-0.25, -0.25, 0.25}, {-0.25, 0.25, 0.25}, {0.25, 0.25, 0.25},{0.25, -0.25, 0.25},
{-0.25, -0.25, -0.25}, {-0.25, 0.25, -0.25}, {0.25, 0.25, -0.25}, {0.25, -0.25, -0.25}};
GLfloat MyColors[8][3]={{0.2, 0.2, 0.2}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0},
{1.0, 0.0, 1.0}, {1.0, 1.0, 1.0}, {0.0, 1.0, 1.0}};
정점 0, 3, 2, 1으로 구성된 면 (반시계 방향으로 명시)
glBegin(GL_POLYGON);
glColor3fv(MyColors[0]); glVertex3fv(MyVertices[0]);
glColor3fv(MyColors[3]); glVertex3fv(MyVertices[3]);
glColor3fv(MyColors[2]); glVertex3fv(MyVertices[2]);
glColor3fv(MyColors[1]); glVertex3fv(MyVertices[1]); //fv 접미사는 배열 형태로 값을 전달할 때 사용되는 함수
glEnd();
밖에서 바라보는 면 (Front face), 안에서 바라볼 때 보이는 면은 이면 (Rear Face)
정점을 명시하는 순서에 따라서 표면과 이면이 구분됨.
더보기
- 맨 위 코드는 3차원 공간에 육면체를 그리기 위한 정점 좌표와 색상 정보를 저장하는 배열을 초기화한 것임.
- MyVertices는 육면체를 구성하는 8개의 정점 좌표를 3차원 벡터 형태로 저장하고 있음. 각 벡터는 8개의 좌표로 이루어져 있음
- MyColors는 육면체를 구성하는 8개의 정점에 대한 색상 정보를 저장하고 있음. 각 색상은 8개의 RGB 색상 값으로 이루어져 있음.
- 오른손 법칙으로 그림
- x, y, z 좌표 값. 정점을 가리키는 인덱스의 순서대로.
- 색상을 R, G, B로 표현하므로 세 개의 값이 필요함. 정점은 오른손 좌표계와 왼손 좌표계를 이용하여 명시함.
- 오른손 좌표계란? x, y, z축이 각각 90도. x축에서 y축을 손으로 감았을 때, 엄지 손가락의 방향이 z축의 양의 방향.
계층구조적 표현
더보기
계층구조적 표현 : 애니메이션에 유리
큐브는 육면체이므로 6개의 면으로 이루어져 있음. 하나의 면은 4개의 정점으로 이루어져 있음. 따라서 정점리스트가 4개. 정점에 정점을 표현하는 인덱스 값을 넣음. 정점의 실제 좌표들을 넣을 경우, 정점의 개수가 많으면 메모리를 많이 차지하게 됨. 이렇게 표현하면 정점 리스트로 정점을 연결하고 이를 반복. 이렇게 해서 훨씬 효율적으로 만들 수 있음. 자료 구조에 따라서 더 편리하게 만들 수 있음.
정점 배열
#include <GL/freeglut.h>
GLfloat MyVertices[8][3] = {//육면체의 8개의 꼭짓점 좌표를 저장. 각 꼭짓점은 x, y, z 좌표값을 가짐.
//배열의 각 행에 대해 첫 번째 열은 x좌표, 두 번째 열은 y좌표, 세 번째 열은 z좌표를 나타냄.
{ -0.25, -0.25, 0.25 },
{ -0.25, 0.25, 0.25 },
{ 0.25, 0.25, 0.25 },
{ 0.25, -0.25, 0.25 },
{ -0.25, -0.25, -0.25 },
{ -0.25, 0.25, -0.25 },
{ 0.25, 0.25, -0.25 },
{ 0.25, -0.25, -0.25 }
};
GLfloat MyColors[8][3] = { //각 꼭짓점에 대한 색상값을 저장함. 각 꼭짓점에 대한 색상값은 RGB값으로 표시됨
{ 0.2, 0.2, 0.2 },
{ 1.0, 0.0, 0.0 },
{ 1.0, 1.0, 0.0 },
{ 0.0, 1.0, 0.0 },
{ 0.0, 0.0, 1.0 },
{ 1.0, 0.0, 1.0 },
{ 1.0, 1.0, 1.0 },
{ 0.0, 1.0, 1.0 }
};
GLubyte MyVertexList[24] = {//육면체의 12개의 면을 구성하는 정점의 인덱스 저장.
0, 3, 2, 1,
2, 3, 7, 6,
0, 4, 7, 3,
1, 2, 6, 5,
4, 5, 6, 7,
0, 1, 5, 4 //여기 사용된 숫자는 해당 정점이 들어가 있는 곳의 인덱스
};
void MyDisplay() {
glClear(GL_COLOR_BUFFER_BIT); //화면 초기화
glFrontFace(GL_CCW); //CCW(Counter-Clockwise) 반시계 방향으로 그려질 표면을 의미
glEnable(GL_CULL_FACE); //보이지 않는 면을 제거하도록 설정
glEnableClientState(GL_COLOR_ARRAY); //정점 배열 기능은 정점좌표, 컬러, 컬러 인덱스,
glEnableClientState(GL_VERTEX_ARRAY); //법선 벡터, 텍스쳐 좌표등에 적용
glColorPointer(3, GL_FLOAT, 0, MyColors); //첫 번째 인자 : 배열의 크기 (차원), 두 번째 인자 : 배열의 데이터 형식
glVertexPointer(3, GL_FLOAT, 0, MyVertices);//세 번째 인자 : 각 정점 데이터의 바이트 단위 크기, 네 번째 인자 : 배열의 시작 주소
glMatrixMode(GL_MODELVIEW); //모델뷰 행렬을 사용하도록 설정
glLoadIdentity(); //모델뷰 행렬을 단위 행렬로 초기화함.
glRotatef(30.0, 1.0, 1.0, 1.0); //30도 각도만큼 x, y, z 축을 기준으로 회전시킴.
for(GLint i = 0; i < 6; i++) //육면체 그리기
glDrawElements(GL_POLYGON, 4, GL_UNSIGNED_BYTE, &MyVertexList[4*i]);
//glDrawElements 함수는 정점 인덱스를 사용하여 도형을 그림.
//GL_POLYGON은 도형의 형태 지정하고, 4는 인덱스의 수를 지정
//GL_UNSIGNED_BYTE 인덱스의 데이터 형식 지정, 마지막 인자는 인덱스 배열의 시작 위치 지정
glFlush(); //그리기 명령 실행
}
int main(int argc, char** argv) {
glutInit(&argc, argv); //GLUT 라이브러리를 초기화함
glutInitDisplayMode(GLUT_RGB); //디스플레이 모드를 RGB 컬러 모드로 설정함
glutInitWindowSize(300, 300); //윈도우 크기 설정
glutInitWindowPosition(0, 0); //윈도우 위치 설정
glutCreateWindow("OpenGL Drawing Example"); //윈도우 생성
glClearColor(1.0, 1.0, 1.0, 1.0); //초기화 색은 백색
glMatrixMode(GL_PROJECTION); //행렬 모드를 GL_PROJECTION으로 설정
glLoadIdentity(); //현재의 행렬 상태 초기화함.
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); //뷰포트의 좌표계 설정
glutDisplayFunc(MyDisplay); //디스플레이 콜백 함수 등록
glutMainLoop(); //이벤트 루프 실행
return 0;
}
더보기
- glEnableClientState(GL_COLOR_ARRAY)와 glEnableClientState(GL_VERTEX_ARRAY)는 모두 정점 배열을 사용할 때 활성화해주는 함수.
- GL_COLOR_ARRAY & GL_VERTEX_ARRAY가 정점배열.
- GL_COLOR_ARRAY는 각 정점의 색상 정보를 가진 배열을 사용하겠다는 것을 의미. 이 함수를 호출하면 glColorPointer()를 사용하여 정점의 색상 정보를 저장한 배열을 OpenGL 컨텍스트에 등록해야 함.
- GL_VERTEX_ARRAY는 각 정점의 위치 정보를 가진 배열을 사용하겠다는 것을 의미. 이 함수를 호출하면 glVertexPointer()를 사용하여 정점의 위치 정보를 저장한 배열을 OpenGL 컨텍스트에 등록해야 함.
디스플레이 리스트
-
직접 모드(immediate mode)
-
물체를 화면에 그림과 동시에 물체 생성과 관련된 모든 정보를 파기
-
다시 그리려면 모든 코드를 처음 부터 다시 실행
-
-
보류 모드(retained mode)
-
정의된 물체 정보를 그대로 유지하고 재사용
-
물체를 다시 그려낼 때 코드를 실행하지 않고 이미 정의된 물체를 컴파일 된 형태로 재사용함으로써 빠른 속도를 보장함
-
지엘의 보류 모드는 디스플레이 리스트에 의해 이루어짐
-
더보기
- 지엘 함수의 실행 모드는 두 가지로 분류됨. 바로 직접 모드와 보류 모드.
- 디스플레이 리스트는 그래픽 처리 속도와 직결됨. 디스플레이 리스트 내부에는 기본 요소, 상태 변수, 영상은 물론 이동, 회전, 조명 작업과 관련된 모든 명령을 집어 넣을 수 있음. 다시 말해 반복적으로 실행되어야 할 일련의 지엘 명령어를 디스플레이 리스트 내부에 포함시킴으로써 실행 시간은 빨라짐.
#include <GL/freeglut.h>
int MyListID;
void MyCreateList() { //glNewList() 함수를 사용하여 새로운 그리기 목록 생성. 해당 목록에 그리기 명령어 추가
MyListID = glGenLists(1); //디스플레이 리스트 생성
glNewList(MyListID, GL_COMPILE); //실행하지 않고 컴파일 완료된 버전을 만듦 (새로운 디스플레이 리스트 만듦)
glBegin(GL_POLYGON); //사각형 그리기
glColor3f(0.5, 0.5, 0.5); //그리는 도형의 색상 설정
glVertex3f(-0.5, -0.5, 0.0);
glVertex3f(0.5, -0.5, 0.0);
glVertex3f(0.5, 0.5, 0.0);
glVertex3f(-0.5, 0.5, 0.0); //glNewList(), glEndList() 내부에 정의
glEnd( ); //도형 그리기 종료
glEndList(); //디스플레이 리스트를 끝내고, 저장된 명령들을 컴파일하여 리스트에 저장
}
void MyDisplay() { //이전에 생성된 그리기 목록을 호출하여 단일 다각형을 그림
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, 300, 300); //출력 창의 크기와 위치 설정
glCallList(MyListID); //컴파일 완료된 리스트가 실제로 실행됨. 저장된 디스플레이 리스트를 실행하여 그림 출력
glFlush();
}
int main(int argc, char** argv) {
glutInit(&argc, argv); //GLUT 라이브러리를 초기화함
glutInitDisplayMode(GLUT_RGB); //디스플레이 모드를 RGB 컬러 모드로 설정함
glutInitWindowSize(300, 300); //윈도우 크기 설정
glutInitWindowPosition(0, 0); //윈도우 위치 설정
glutCreateWindow("OpenGL Example Drawing"); //윈도우 생성
glClearColor(1.0, 1.0, 1.0, 1.0); //초기화 색은 백색
glMatrixMode(GL_PROJECTION); //행렬 모드를 GL_PROJECTION으로 설정
glLoadIdentity(); //현재의 행렬 상태 초기화함.
glOrtho(-1.0, 1.0, -1.0, 1.0, 1.0, -1.0); //뷰포트의 좌표계 설정
glutDisplayFunc(MyDisplay); //디스플레이 콜백 함수 등록
MyCreateList(); //그리기 목록 생성
glutMainLoop(); //이벤트 루프 실행
return 0;
}
GLuint glGenLists(GLsizei range);
//사용 안 된 일련의 아이디 중 첫번째 아이디를 되돌려 줌
//여러개의 디스플레이 리스트 아이디를 할당하기
GLunit ListOne, listTwo, listThree;
listOne = glGenLists(3);
listTwo = listOne + 1;
listThree = listTwo + 1;
Void glNewList(GLunit list, GLenum mode);
//mode 변수 값이 GL_COMPILE_AND_EXECUTE 라면 직접모드처럼 명령어가 즉시 실행됨과 동시에 디스플레이 리스트에도 저장
//GL_COMPILE 이면 실행되지 않고 디스플레이 리스트에만 저장됨
//복잡한 물체를 빠른 속도로 처리하려면 디스플레이 리스트 사용은 필수적임
//디스플레이 리스트 내부에는 기본요소, 상태변수, 영상은 물론 이동, 회전, 조명 작업과 관련된 모든 명령을 집어 넣을 수 있음
//네트워크 환경에서 디스플레이 리스트를 적용하면 기본 요소를 조합하여 계산된 최종 모습을 전송함으로써 전송속도를 높일 수 있음. 디스플레이 리스트는 서버 쪽에 존재
더보기
- glGenLists()는 새로운 디스플레이 리스트를 생성하고 그 리스트의 이름(정수)를 반환하는 OpenGL 함수.인자로는 생성하려는 리스트의 개수를 나타내는 GLsizei형 변수 range를 받음. 반환값으로는 생성된 리스트의 이름(정수)을 반환. 이 이름은 생성된 리스트를 식별하는 데 사용됨.
- 리스트는 glNewList()를 호출하여 시작하고, glEndList()를 호출하여 끝냄. 리스트가 완성되면, 이 이름을 호출하여 리스트를 다시 실행할 수 있음. 리스트는 고유의 이름 공간을 가짐. 리스트 이름이 중복되면 안됨.
- 두 번째 코드는 3개의 리스트 ID를 생성하고, listOne, listTwo, listThree 변수에 각각 할당하는 코드. glGenLists() 함수는 매개변수로 전달된 숫자만큼의 연속적인 유일한 리스트 ID를 생성. 따라서 glGenLists(3) 호출 결과로 listOne, listTwo, listThree 변수에는 3개의 연속된 리스트 ID가 차례로 할당됨.
- glNewList 함수는 새로운 디스플레이 리스트를 생성하고, 그 리스트를 작성할 때 사용할 모드를 설정함.
- 함수의 첫 번째 매개변수 list는 새로운 디스플레이 리스트의 고유한 ID를 나타내며, 두 번째 매개변수 mode는 디스플레이 리스트에 추가될 명령어들을 어떤 방식으로 처리할지 지정.
- GL_COMPILE : 지정한 리스트에 명령어를 컴파일하여 저장.
- GL_COMPILE_AND_EXECUTE : 지정한 리스트에 명령어를 컴파일하고 실행.
- glNewList 함수를 호출한 후에는, 이어지는 명령어들이 새로운 리스트에 저장되며, glEndList 함수를 호출하여 리스트 작성을 종료함.
'전공 > 컴퓨터 그래픽스' 카테고리의 다른 글
모델변환과 시점변환 (2)기하변환 (1) | 2023.04.13 |
---|---|
모델변환과 시점변환 (1)좌표계 (0) | 2023.04.11 |
OpenGL 기본틀 : Callback 프로그래밍 (2)Menu Callback, Idle Callback, Timer Callback (0) | 2023.04.11 |
OpenGL 기본틀 : Callback 프로그래밍 (1)Reshape Callback, Keyboard Callback, Mouse Callback (0) | 2023.04.10 |
OpenGL 기본 틀 (5)_더블 버퍼링 (0) | 2023.04.09 |
댓글