[App 개발] NeHe Lesson 18
본문
Quadrics는 for 루프와 삼각함수를 이용하여 복잡한 물체를 그리는 방법을 뜻합니다.
강의 7 에서 사용한 코드를 이용할 것입니다. 일곱 개의 변수를 추가하고 텍스쳐를 바꾸어서 변화를 주었습니다.
bool sp; // 스페이스바가 눌렸는가
int part1; // 디스크의 시작
int part2; // 디스크의 끝
int p1=0; // 증가 1
int p2=1; // 증가 2
GLUquadricObj *quadratic; // 2차곡면 저장
GLuint object=0; // 어떤 물체를 그리는가
이제 InitGL()함수로 이동해서 2차곡면을 초기화하기 위한 코드 세 줄을 추가하겠습니다. light1을 활성화한 코드 다음부분과 리턴하기 전 부분에 코드를 삽입합니다. 첫 번째 줄은 2차곡면을 초기화하고 메모리 어디에 저장될지를 가리키는 포인터를 만듭니다. 만약 만들어지지 않았으면 0을 리턴합니다. 두 번째 줄은 2차함수의 법선을 smooth로 만들어서 보기 좋게 빛이 반사되도록 합니다. 그 외에도 GLU_NONE 나 GLU_FLAT 등을 선택할 수 있습니다. 마지막은 2차곡면에 텍스쳐 매핑을 활성화합니다. 텍스쳐 매핑은 주의를 요하는 일이라서 상자 텍스쳐 만드는 것에서 보신 것처럼 항상 계획했던 대로 잘 되지 않곤 합니다.
quadratic=gluNewQuadric(); // 2차곡면 물체의 포인터를 만든다
gluQuadricNormals(quadratic, GLU_SMOOTH); // Smooth한 법선을 만든다
gluQuadricTexture(quadratic, GL_TRUE); // 텍스쳐 좌표를 만든다
지난 강의에서 썼던 육면체를 그대로 사용하기 때문에 여러분은 어떻게 텍스쳐가 2차곡면 물체에 매핑되는지 보실 수 있습니다. 육면체 만드는 코드를 함수로 만들어서 그리기 함수를 좀 더 깔끔하게 만들었습니다. 이 코드는 다 이해하실 것입니다.
GLvoid glDrawCube()
{
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glNormal3f( 0.0f, 0.0f,-1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glNormal3f( 0.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glNormal3f( 0.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glNormal3f( 1.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glNormal3f(-1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
}
다음은 DrawGLScene()함수입니다. 간단한 if 구문을 사용하여 다른 물체를 그리도록 했습니다. 그리고 정적 변수(함수를 호출할 때마다 값을 간직하고 있는 지역변수)를 사용하여 멋있는 효과로 디스크 조각을 그리도록 만들었습니다. DrawGLScene()함수 전체를 다시 보여드리겠습니다.
사용되는 인수들을 설명할 때 실제 첫 번째 인수 quadratic을 언급하지 않을 것입니다. 이 인수는 육면체 주변에 물체를 그릴 때 항상 사용되는 것이기 때문에 인수 설명할 때 건너뛰겠습니다.
int DrawGLScene(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,z);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
glBindTexture(GL_TEXTURE_2D, texture[filter]);
// 이제부터 새로 추가된 코드
switch(object) // 어떤 물체를 그릴 것인지를 선택
{
case 0: // 첫 번째 물체를 그린다
glDrawCube(); // 육면체를 그린다
break;
우리가 만들 두 번째 물체는 실린더입니다. 첫 번째 인수 1.0f 는 실린더 바닥의 반지름입니다. 두 번째 인수 1.0f 는 실린더 위의 반지름입니다. 세 번째 인수 3.0f 는 실린더의 높이 (실린더의 길이) 입니다. 네 번째 인수 32 는 z 축을 둘레로 몇 개의 구획을 만들 것인지를 표시합니다. 마지막으로 다섯 번째 인수 32는 z축을 따라서 몇 개의 구획을 만들 것인지를 표시합니다. 더 많은 구획을 사용할 수록 더 자세한 물체가 만들어집니다. 구획의 갯수를 증가시킬 수록 물체에 더 많은 다각형이 이용됩니다. 결국 품질을 위해 속도를 희생해야 합니다. 대부분 최적의 값을 찾는 것이 쉽지 않습니다.
case 1: // 두 번째 물체
glTranslatef(0.0f,0.0f,-1.5f); // 실린더의 가운데
gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32); // 실린더 그린다
break;
우리가 만들 세 번째 물체는 CD 모양의 디스크입니다. 첫 번째 인수 0.5f 는 디스크의 안쪽 지름입니다. 이 값을 0을로 하면 가운데 구멍이 없게 됩니다. 안쪽 지름이 크면 클수록 가운데 구멍이 큰 디스크가 됩니다. 두 번째 인수 1.5f 는 바깥 지름입니다. 이 값은 안쪽 지름 크기보다 커야 합니다. 만약 이 값을 안쪽 지름보다 약간 크게 만들면 얇은 링을 만들게 됩니다. 반대로 안쪽 지름보다 엄청나게 크게 만들면 아주 두꺼운 링이 만들어집니다. 세 번째 인수 32는 디스크를 몇 조각으로 만들 것인지를 결정하는 수입니다. 이 조각은 마치 핏자 조각 모양을 생각하시면 됩니다. 더 많은 조각을 낼 수록 디스크의 바깥 둘레가 부드럽게 만들어질 것입니다. 마지막으로 네 번째 인수 32는 디스크를 만드는 링의 갯수입니다. 링은 레코드 판의 트랙과 비슷한, 원 안의 원입니다. 이 링은 안쪽 지름과 바깥 지름의 구획을 나누어서 좀 더 세밀하게 만들어줍니다. 역시 더 많은 구획을 이용할 수록 속도는 느려집니다.
case 2: // 세 번째 물체
gluDisk(quadratic,0.5f,1.5f,32,32); // CD 모양의 디스크
break;
네 번째 물체는 여러분들이 만들고 싶어하는 물체, 바로 공입니다. 이것은 꽤 쉽습니다. 첫 번째 인수는 공의 반지름입니다. 반지름/지름 등에 대해서 익숙하지 않으신 분을 위해서, 반지름이란 물체의 한 가운데에서부터 물체의 바깥쪽까지의 길이를 뜻합니다. 여기서 반지름은 1.3f 입니다. 그 다음은 z 축 둘레로 만들어지는 구획의 갯수 (32) 입니다. 그리고 z축을 따라서 만들어지는 구획 (32) 의 갯수입니다. 구획을 많이 만들수록 부드러운 물체를 만들 수 있습니다. 공을 부드럽게 만들기 위해서 필요한 구획은 그리 많이 필요하지 않습니다.
case 3: // 네 번째 물체
gluSphere(quadratic,1.3f,32,32); // 공을 만든다
break;
다섯 번째 물체는 실린더를 만들 때 사용했던 명령과 동일한 것을 사용합니다. 기억하시겠지만, 실린더를 만들 때 처음 두 인수가 실린더의 밑과 위의 반지름을 결정했습니다. 고깔 모양을 만든다면 한쪽 끝의 반지름을 0으로 하면 됩니다. 이렇게 하면 한쪽 끝이 점으로 만들어집니다. 다음의 코드에서는 실린더의 위쪽 반지름을 0으로 해서, 한쪽 끝이 점으로 만들어지고, 물체는 고깔 모양으로 만들어집니다.
case 4: // 다섯 번째 물체
glTranslatef(0.0f,0.0f,-1.5f); // 고깔의 중심
gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32); // 바닥의 지름이 .5 이고 높이가 2인 고깔
break;
여섯 번째 물체는 gluPartialDisc함수로 만들어집니다. 이 명령으로 만들어지는 물체는 위에서 만든 디스크와 동일한 모양입니다만 gluPartialDisk 명령에는 두 개의 새로운 인수가 있습니다. 다섯 번째 인수 part1 은 디스크를 그리기 시작하는 각도입니다. 여섯 번째 인수는 디스크가 sweep 각도입니다. sweep각도는 혀재 각도로부터 디스크를 그리는 거리입니다. 우리는 sweep 각도를 증가시켜서 디스크가 화면에서 시계 방향으로 천천히 그려져 나가도록 만들 것입니다. sweep 각도가 360도에 이르게 되면 이것을 다시 시작 각도에서 다시 증가시킵니다. 이렇게 하면 디스크가 지워지는 것처럼 보이게 됩니다. 그 다음 처음부터 다시 시작하게 됩니다.
case 5: // 여섯 번째 물체
part1+=p1; // 시작 각도
part2+=p2; // sweep 각도
if(part1>359)
{
p1=0; // 시작 각도 증가를 멈춤
part1=0; // 시작 각도를 0으로
p2=1; // sweep 각도를 증가
part2=0; // sweep 각ㄷ를 0으로
}
if(part2>359)
{
p1=1; // 시작 각도 증가
p2=0; // sweep 각도 증가 멈춤
}
gluPartialDisk(quadratic,0.5f,1.5f,32,32,part1,part2-part1);
break;
};
xrot+=xspeed;
yrot+=yspeed;
return TRUE;
}
KillGLWindow()함수의 코드에 2차곡면을 지워서 시스템 리소스를 풀어주는 부분을 넣습니다. gluDeleteQuadratic함수가 그 일을 하는 것입니다.
GLvoid KillGLWindow(GLvoid)
{
gluDeleteQuadric(quadratic);
이제 마지막으로 키 입력입니다. 키보드 입력하는 코드에 다음의 코드를 첨가합니다.
if (keys[] && !sp)
{
sp=TRUE;
object++;
if(object>5)
object=0;
}
if (!keys[])
{
sp=FALSE;
}
최신글이 없습니다.
최신글이 없습니다.
댓글목록 0