[App 개발] NeHe Lesson 23
본문
일단 샘플 코드의 구현은 흥미로운 것 위주로 하도록 하고, 나머지는 텍스트를 익히는 것에 중점을 두려고 합니다. (제가 게을러졌다는 것을 우회적으로 표현하는 것입니다. ㅡㅡ;;;)
-------------------------
구면 환경 매핑은 씬에 있는 금속성이나 반사물체에 반사영상을 만드는 손쉬운 방법입니다. 비록 실제 상황이나 육면체 환경 매핑에 비해 정확성은 떨어지더라도, 이 방법이 훨씬 속도가 빠릅니다. 우리는 18과 (2차평면) 소스를 이번 강의 기본코드로 사용하겠습니다. 그리고 기존의 텍스쳐 맵을 사용하지 않고 새로운 구면 맵과 배경 그림을 사용할 것입니다.
시작하기 전에… “빨간책” 에서는 구면 맵을 무한 초점 거리에서 무한대의 거리에 있는 금속 공의 영상이라고 정의하고 있습니다. 실제 상황에서는 불가능하죠. 어안렌즈를 사용하지 않고 구면 맵을 만들 수 있는 가장 좋은 방법은 아도베 포토샵을 사용하는 방법입니다.
포토샵에서 구면 맵을 만들기
먼저 구면에 매핑할 환경 그림이 먼저 필요할 ㅓㅅ입니다. 아도베 포토샵에서 그림을 열어서 전체 그림을 선택합니다. 그림을 복사한 다음 새 PSD 파일을 만듭니다. 새 그림 크기는 방금 복사한 그림 크기와 동일할 것입니다. 만들어진 파일에 그림을 붙힙니다. 그림을 복사하는 이유는 그렇게 해야 포토샵의 필터를 사용할 수 있기 때문입니다. 그림을 복사하지 않으려면 대신에 메뉴에서 Mode 를 선택한 다음 RGB mode 를 선택합니다. 이제 모든 필터가 사용 가능하게 됩니다.
그 다음은 그림 크기를 2의 급수가 되도록 조절합니다. 그림을 텍스쳐로 사용하려면 그림은 128x128, 256x256 등의 크기가 되어야 합니다. Image 메뉴에서 Image Size 를 선택하시고 constraint proportions 체크 박스를 해제한 다음 그림을 텍스쳐 사용 가능하도록 크기를 조절합니다. 만약 그림이 100x90 이라면 64x64 대신 128x128 로 만드는 것이 좋습니다. 그림을 작게 만들면 그림의 세밀한 부분이 망가지기 때문입니다.
마지막으로 Filter 메뉴를 선택하고 Distort 를 선택한 다음 Spherize Modifier 를 적용합니다. 그림의 가운데가 마치 풍선처럼 불어오른 것을 볼 것입니다. 일반적인 구면 맵은 바깥쪽이 모두 검게 없어져 있습니다만 크게 상관 없습니다. 지금 그림을 파일에 저장하면 코드를 작성할 준비가 끝입니다.
이번에는 광역변수를 새로 정의하는 것은 없습니다만 그 대신 텍스쳐르 여섯 개 사용할 수 있도록 텍스쳐 배열을 조정합니다.
GLuint texture[6];
다음은 LoadGLTextures() 함수를 변경하여 비트맵 두 개를 읽어서 필터 세 개를 만들도록 하였습니다. (원래 텍스쳐 예제에서 했던 것처럼). 기본적으로 루프를 두 번 돌리고 각각 다른 필터링 모드를 사용하여 세 개의 텍스쳐를 만드는 과정입니다. 거의 대부분의 코드가 새롭게 추가되거나 변경된 것들입니다.
int LoadGLTextures()
{
int Status=FALSE;
AUX_RGBImageRec *TextureImage[2];
memset(TextureImage,0,sizeof(void *)*2);
if ((TextureImage[0]=LoadBMP("Data/BG.bmp")) && (TextureImage[1]=LoadBMP("Data/Reflect.bmp")))
{
Status=TRUE;
glGenTextures(6, &texture[0]);
for (int loop=0; loop<=1; loop++)
{
glBindTexture(GL_TEXTURE_2D, texture[loop]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
glBindTexture(GL_TEXTURE_2D, texture[loop+2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
glBindTexture(GL_TEXTURE_2D, texture[loop+4]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
}
for (loop=0; loop<=1; loop++)
{
if (TextureImage[loop])
{
if (TextureImage[loop]->data)
{
free(TextureImage[loop]->data);
}
free(TextureImage[loop]);
}
}
}
return Status;
}
이제 육면체를 그리는 코드를 약간 변경합니다. 노멀값으로 1.0과 -1.0을 사용하는 대신 0.5와 -0.5를 사용합니다. 노멀값을 이렇게 바꾸게 되면 이제 반사 맵을 크게 작게 줌 할 수 있게 됩니다. 만약 노멀값이 커지면 반사되는 그림은 커지고 울퉁불퉁하게 됩니다. 노멀값을 0.5 와 -0.5 로 줄이게 되면 반사 그림이 약간 작아지게 되어 반사된 그림은 울퉁불퉁하지 않게 됩니다. 노멀값을 너무 작게 만들면 원하지 않는 결과를 만들게 됩니다.
GLvoid glDrawCube()
{
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f, 0.5f);
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,-0.5f);
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, 0.5f, 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,-0.5f, 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( 0.5f, 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(-0.5f, 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();
}
InitGL() 함수에 두 개의 함수 호출을 추가했습니다. 구면 매핑을 위한 텍스쳐 생성 모드 S 와 T 를 설정하는 것입니다. 텍스쳐 좌표 S, T, R, Q 는 물체 좌표 x, y, z, w 와 관련이 있습니다. 만약 1차원 텍스쳐일 때는 S 좌표를 사용하게 됩니다. 2차원 텍스쳐는 S 와 T 좌표를 사용합니다.
다음은 OpenGL에게 구면 매핑 공식에 의하여 자동적으로 S 와 T 좌표를 설정하는 코드입니다. Q 좌표는 복잡한 텍스쳐 매핑 확장 기능에서 활용되고, R 좌표는 만약 OpenGL 에 3차원 텍스쳐가 구현된다면 활용될 것입니다. 그러나 여기서는 R 과 Q 좌표는 무시됩니다. S 좌표는 다각형 면의 수평 선분으로 움직이고, T 좌표는 다각형 면의 수직 선분으로 움직입니다.
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
거의 다 되었습니다. 이제 랜더링 을 하면 됩니다. 저는 여기서 몇 개의 2차함수 물체들을 제거했는데 왜냐하면 환경 매핑이 잘 동작하지 않았기 때문입니다. 먼저 할 일은 텍스쳐를 만드는 일입니다. 그 다음 반사 텍스쳐 (구면 맵) 를 선택하여 물체를 그립니다. 구면 매핑된 물체들이 그려지고 난 다음 텍스쳐 생성을 제거합니다. 그렇지 않으면 모든 물체들이 구면 매핑이 될 것입니다. 그 다음 배경 씬을 그리기 전에 구면 매핑을 제거합니다. (배경 그림이 구면 매핑이 되면 안되니까) 텍스쳐 바인딩 명령이 약간 복잡해 보일 것입니다. 여기서 하는 일은 구면 맵을 그리거나 배경 이미지를 그릴 때 사용될 필터를 선택하는 것입니다.
int DrawGLScene(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();
glTranslatef(0.0f,0.0f,z);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glBindTexture(GL_TEXTURE_2D, texture[filter+(filter+1)]);
glPushMatrix();
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
switch(object)
{
case 0:
glDrawCube();
break;
case 1:
glTranslatef(0.0f,0.0f,-1.5f);
gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);
break;
case 2:
gluSphere(quadratic,1.3f,32,32);
break;
case 3:
glTranslatef(0.0f,0.0f,-1.5f);
gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32);
break;
};
glPopMatrix();
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glBindTexture(GL_TEXTURE_2D, texture[filter*2]);
glPushMatrix();
glTranslatef(0.0f, 0.0f, -24.0f);
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-13.3f, -10.0f, 10.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 13.3f, -10.0f, 10.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 13.3f, 10.0f, 10.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-13.3f, 10.0f, 10.0f);
glEnd();
glPopMatrix();
xrot+=xspeed;
yrot+=yspeed;
return TRUE;
}
마지막으로 스페이스키가 눌리면 구현되는 2차함수의 방식을 변경하도록 만들어주는 코드입니다.
if (keys[] && !sp)
{
sp=TRUE;
object++;
if(object>3)
object=0;
}
최신글이 없습니다.
최신글이 없습니다.
댓글목록 0