• 북마크
  • 추가메뉴
어디로 앱에서 쉽고 간편하게!
애플 중고 거래 전문 플랫폼
오늘 하루 보지 않기
KMUG 케이머그

소프트웨어

[App 개발] NeHe Lesson 6

본문

텍스쳐 매핑을 배우면 여러가지 잇점이 있습니다. 만약 화면을 가로질러 날아가는 미사일을 표현한다고 합시다. 지금까지 배운 것을 토대로 하자면 미사일 전체를 형형색색의 다각형을 모아서 만들어야만 합니다. 텍스쳐 매핑을 사용한다면 진짜 미사일 사진 한 장을 가져다가 화면에 날아가는 모습을 만들어주면 됩니다. 사진 한 장과 삼각형/사각형의 조합을 비교해 보세요. 어느쪽이 더 쉬워 보이십니까? 텍스쳐 매핑을 이용하면 보기에 더 멋있어질 뿐 아니라 프로그램 속도도 더 빨라집니다. 텍스쳐 매핑된 미사일은 사각형 하나만 화면에서 움직여주면 되기 때문입니다. 반면에 다각형으로 미사일을 표현하려면 수천 수만 개의 다각형의 조합으로 만들어야만 합니다. 텍스쳐 매핑된 사각형이 훨씬 더 계산이 적게 듭니다.

이제 제 1장에서 썼던 소스코드의 윗부분에 새 코드 다섯 줄을 더하겠습니다. #include 를 넣어서 프로그램에서 파일을 이용할 수 있도록 합니다. 이 줄을 첨가하여야 나중에 fopen() 함수를 이용할 수 있습니다. 그리고 세 개의 부동소숫점 변수 xrot, yrot, zrot를 추가합니다. 이것들은 육면체를 각각 x축, y축, z축으로 회전하는데 사용할 것입니다. 마지막으로 GLuint texture[1]은 텍스쳐를 저장하는 변수입니다. 만약에 텍스쳐가 더 필요하면 1 대신 원하는 텍스쳐의 갯수만큼 숫자를 넣어주시면 됩니다.


#include

GLfloat xrot; // X축으로 회전
GLfloat yrot; // Y축으로 회전
GLfloat zrot; // Z축으로 회전

GLuint texture[1]; // 텍스쳐 저장 변수


위의 코드와 ResizeGLScene() 함수 사이에 다음의 코드를 첨가하겠습니다. 이 코드는 비트맵 파일을 읽어들이는 일을 합니다. 만약에 파일이 존재하지 않으면 텍스쳐를 읽을 수 없다는 뜻으로 NULL값을 리턴하게 됩니다. 이 코드를 설명하기 전에 텍스쳐로 사용하고자 하는 이미지에 대해서 알아두어야 할 아주 중요한 점을 이야기하겠습니다. 이미지의 넓이와 길이는 모두 2의 급수여야 하며, 적어도 64 이상이어야 합니다. 그리고 호환성 문제를 생각해서 256 이상이 되지 않도록 합니다. 만약에 사용하고자 하는 이미지의 넓이와 길이가 64, 128, 256픽셀이 아니라면 페인팅 프로그램에서 크기를 조절하세요. 기타 등등의 조건들이 있지만, 우리는 일단 기본 텍스쳐 크기만을 이용하도록 하겠습니다.

먼저 파일 핸들을 만듭니다. 핸들은 프로그램이 사용하는 리소스를 구분하는 값입니다. 일단 처음에는 핸들값을 NULL로 놓습니다.


AUX_RGBImageRec *LoadBMP(char *Filename)
{
FILE *File=NULL; // 파일 핸들


그 다음 파일 이름이 확실히 전달되었는지를 확인합니다. LoadBMP()함수에 읽어들일 파일 이름을 빼먹고 사용할 수 있기 때문에, 먼저 이것을 확인하는 것입니다. 설마 아무것도 아닌 것을 읽어들일 생각은 아니겠죠? :)



if (!Filename) // 파일명이 없는가
{
return NULL; // 없으면 NULL을 리턴하고 끝
}


파일 이름이 있다면 그러한 이름의 파일이 실제로 있는지 확인해야 합니다. 다음 코드에서 파일을 엽니다.



File=fopen(Filename,"r"); // 정말로 파일이 존재하는지 확인한다


만약 파일이 열린다면 파일은 존재하는 것입니다. 열린 파일을 fclose(File)함수로 닫고 이미지 데이터를 리턴합니다. auxDIBImageLoad(Filename)가 데이터를 읽는 함수입니다.



if (File) // 파일이 있습니까?
{
fclose(File); // 열린 파일을 닫고
return auxDIBImageLoad(Filename); // 비트맵을 읽어 데이터를 리턴
}


만약 파일을 열 수 없었다면 파일을 읽을 수 없었다는 뜻으로 NULL을 리턴합니다. 이후의 프로그램에서 파일이 제대로 읽혀지는지를 확인해서 만일 잘못되어 있다면 오류 메세지와 함께 프로그램을 종료할 것입니다.


return NULL; // 파일을 열 수 없었다면 NULL을 리턴
}


이제부터는 위의 함수를 이용해서 비트맵을 읽은 다음 텍스쳐로 변환하는 과정입니다.



int LoadGLTextures()
{


먼저 Status라는 변수를 선언합니다. 이것은 비트맵을 읽어서 텍스쳐를 만들 수 있었는지를 기록하는 변수입니다. 이것을 일단 초기값으로 FALSE로 선언하여 아직 아무것도 읽거나 만들어지지 않았음을 표시하겠습니다.


int Status=FALSE; // 상태 기록 변수


이제 이미지 레코드를 만들어서 비트맵을 저장하도록 하겠습니다. 레코드에는 비트맵의 넓이 길이, 그리고 실제 데이터가 기록됩니다.


AUX_RGBImageRec *TextureImage[1];


레코드의 값을 초기화하여 확실히 비어 있도록 합니다.


memset(TextureImage,0,sizeof(void *)*1);


이제 비트맵을 읽어서 텍스쳐로 변환하겠습니다. TextureImage[0]=LoadBMP("Data/NeHe.bmp") 를 호출하면 코드는 LoadBMP()함수로 이동하여, Data 디렉토리 안에 있는 NeHe.bmp라는 이름의 파일을 읽게 되고, 다른 문제가 없다면 이미지 데이터가 TextureImage[0]변수에 저장될 것입니다. 이제 Status변수를 TRUE로 세팅하고 텍스쳐를 만들기 시작합니다.


if (TextureImage[0]=LoadBMP("Data/NeHe.bmp"))
{
Status=TRUE;


TextureImage[0]에 저장되어 있는 이미지 데이터를 가지고 텍스쳐를 만들 것입니다. 첫 번째 줄에 있는 glGenTextures(1,&texture[0])은 OpenGL에게 우리가 만들 텍스쳐의 이름을 알려줍니다. (만약 여러 개의 텍스쳐를 만들 때에는 숫자가 증가되어야 합니다.) 강의 처음에 우리는 GLuint texture[1] 에서 텍스쳐를 저장할 변수를 선언했습니다. 여러분 생각에는 &texture[0]이 아니라 &texture[1]이 아닌가 하고 생각하실지 모르지만 그렇지 않습니다. 첫 번째 기억장소는 0입니다. 만약에 GLuint texture[2]를 선언했다면 두 번째 기억장소는 texture[1]이 됩니다.

두 번째 줄, glBindTexture(GL_TEXTURE_2D, texture[0])은 OpenGL에게 texture[0] 이름과 텍스쳐를 연결하게 합니다. 2D 텍스쳐는 높이(y축으로)와 길이(x축으로)를 갖고 있습니다. glBindTexture()함수는 텍스쳐 데이터에 이름을 부여합니다. 지금 프로그램에서는 OpenGL에게 &texture[0] 메모리가 비어 있음을 열려줘서 만들어진 텍스쳐가 &texture[0]이 가리키는 메모리 영역에 저장되도록 합니다.


glGenTextures(1, &texture[0]); // 텍스쳐를 만든다

// 비트맵 데이터를 이용한 일반적인 텍스쳐 만들기
glBindTexture(GL_TEXTURE_2D, texture[0]);


이제 실제 텍스쳐를 만듭니다. 다음 코드는 OpenGL에게 2D텍스쳐를 쓸 것임을 알립니다. (GL_TEXTURE_2D) 두 번째 인수는 이미지의 디테일 레벨을 가리키는 값으로 일반적으로 0입니다. 세 번째 인수는 데이터 컴포넌트의 갯수입니다. 이미지는 붉은 색, 녹색, 푸른 색의 3가지 컴포넌트로 구성되어 있습니다. TextureImage[0]->sizeX는 텍스쳐의 넓이입니다. 만약 넓이를 이미 알고 있다면 그대로 숫자를 넣어도 되지만 이렇게 하면 컴퓨터가 알아서 값을 넣게 됩니다. TextureImage[0]->sizeY는 텍스쳐의 높이입니다. 그 다음 값 0은 둘레입니다. 일반적으로 0을 넣습니다. GL_RGB는 이미지 데이터가 붉은색, 녹색, 파란색의 순서로 기록되어 있다는 것을 OpenGL에게 알려줍니다. GL_UNSIGNED_BYTE는 이미지 데이터의 값이 부호 없는 바이트 값으로 구성되어 있다는 뜻입니다. 마지막으로 TextureImage[0]->data는 실제 텍스쳐 데이터가 있는 곳을 가리킵니다. 여기서는 TextureImage[0]레코드에 기록되어 있는 데이터를 가리킵니다.


// 텍스쳐를 만든다
glTexImage2D(
GL_TEXTURE_2D,
0,
3,
TextureImage[0]->sizeX,
TextureImage[0]->sizeY,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
TextureImage[0]->data);


다음의 두 줄은 원래 텍스쳐보다 이미지가 크거나 화면에 늘여질 때 혹은 실제 텍스쳐보다 화면 크기가 작을 경우 어떤 필터링 방식을 사용할 것인가를 결정합니다. 나는 보통 두 가지 경우 모두 GL_LINEAR를 사용합니다. 이것은 물체가 멀리 있을 때에나 화면 가까이 있을 때에도 텍스쳐를 부드럽게 표시합니다. GL_LINEAR는 프로세서/비디오 카드에 많은 계산을 요구하기 때문에 여러분 컴퓨터가 느린 경우에는 대신에 GL_NEAREST를 사용하셔도 됩니다. GL_NEAREST로 필터링된 텍스쳐는 늘여졌을 때 약간 블럭이 져 보입니다. 이 두 가지를 섞어서 가까이 있을 때에는 필터링을 하고 멀리 있을 때에는 하지 않도록 만들 수도 있습니다.


glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}


이제 비트맵 데이터를 저장하는 데 사용했던 메모리를 풀어줍니다. 먼저 비트맵 데이터가 TextureImage[0]에 저장되어 있는지를 확인하여 데이터가 저장되어 있다면 삭제합니다. 그 다음 사용되었던 모든 메모리를 풀어주기 위하여 이미지 스트럭쳐를 풀어줍니다.




if (TextureImage[0]) // 만약 텍스쳐가 있다면
{
if (TextureImage[0]->data) // 텍스쳐 이미지가 있다면
{
free(TextureImage[0]->data); // 텍스쳐 이미지 메모리를 푼다
}

free(TextureImage[0]); // 이미지 스트럭쳐를 푼다
}


마지막으로 상태값을 리턴합니다. 모든것이 양호하면 Status변수의 값은 TRUE이고, 무엇인가 잘못되었다면 State는 FALSE가 됩니다.


return Status; // 상태 변수 리턴
}


InitGL()함수에도 몇 가지를 변경하였습니다. 함수 내용을 모두 표시하였으므로 어떤 코드가 첨가되었는지 쉽게 아실 수 있을 것입니다. 첫 번째 줄에 있는 if(!LoadGLTextures())는 비트맵을 읽어서 텍스쳐를 만드는 루틴을 실행하게 됩니다. 만약에 어떤 이유에서든 LoadGLTextures()함수 실행이 실패하면 다음 줄에서 FALSE를 리턴하게 됩니다. 모든 것이 양호할 때에는 텍스쳐가 만들어지고 우리는 2D텍스쳐 매핑을 할 준비가 됩니다. 만약 텍스쳐 매핑 세팅을 잊어버리고 안 하게 되면 만들어지는 모든 물체들은 흰 색으로 보이게 될 것입니다.



int InitGL(GLvoid)
{
if (!LoadGLTextures()) // 텍스쳐 만드는 루틴으로 간다
{
return FALSE; // 텍스쳐가 만들어지지 않았으면 FALSE를 리턴
}

glEnable(GL_TEXTURE_2D); // 텍스쳐 매핑을 활성화
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

return TRUE;
}


이제 텍스쳐 매핑된 육면체를 만듭니다. DrawGLScene()함수를 다음의 코드로 바꾸시거나, 제 1 장 코드에서 새로 추가된 부분만 바꾸셔도 됩니다. 주석을 잔뜩 달았으니 이해하시기 쉬울 것입니다. 처음 두 줄의 glClear()와 glLoadIdentity()는 첫 번째 시간에 설명드린 코드입니다. glClear()는 화면을 InitGL()에서 선택한 색깔로 화면을 지우는 함수입니다. 여기서는 화면을 검은 색으로 초기화합니다. depth buffer역시 초기화될 것입니다. 뷰도 glLoadIdentity()를 호출하면서 초기화됩니다.



int DrawGLScene(GLvoid) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-5.0f); // 화면 깊숙히 5유닛 이동


다음은 육면체를 먼저 x축으로, 그리고 y축으로, 마지막으로 z축으로 회전시킵니다. 얼마나 회전시키는가는 xrot, yrot, zrot에 저장된 값에 따라 결정됩니다.



glRotatef(xrot,1.0f,0.0f,0.0f); // x축으로 회전
glRotatef(yrot,0.0f,1.0f,0.0f); // y축으로 회전
glRotatef(zrot,0.0f,0.0f,1.0f); // z축으로 회전


다음에는 사용할 텍스쳐를 선택합니다. 만약에 여러 개의 텍스쳐를 화면에 사용하려면 glBindTexture(GL_TEXTURE_2D,texture[사용할 텍스쳐의 번호]) 를 이용해서 선택합니다. 새 텍스쳐를 연결하면 텍스쳐가 변경됩니다. 그러나 텍스쳐는 glBegin()과 glEnd() 사이에서는 연결할 수 없고, glBegin() 전이나 glEnd() 이후에 해야 합니다. 어떻게 glBindTextures()함수를 이용해서 어떤 텍스쳐를 만들고 그것을 선택하는지 보십시오.



glBindTexture(GL_TEXTURE_2D, texture[0]); // 텍스쳐를 선택한다


사각형에 텍스쳐를 정확히 매핑하기 위해서는 텍스쳐의 오른쪽 위와 사각형의 오른쪽 위를 맞추고, 텍스쳐의 왼쪽 위와 사각형의 왼쪽 위, 텍스쳐의 오른쪽 아래와 사각형의 오른쪽 아래, 텍스쳐의 왼쪽 아래를 사각형의 왼쪽 아래와 맞추십시오. 만일 텍스쳐의 끝과 사각형의 끝이 제 짝을 찾지 못하면 이미지가 뒤집혀지거나 한쪽으로 치우치거나, 아무것도 출력되지 않습니다.

glTexCoord2f()함수의 첫 번째 인수는 x 축입니다. 텍스쳐의 왼쪽이 0.0f입니다. 0.5f는 텍스쳐의 중간, 1.0f는 텍스쳐의 오른쪽 끝입니다. 두 번째 인수는 y 축입니다. 텍스쳐의 밑바닥이 0.0f, 중간이 0.5f, 텍스쳐의 꼭데기는 1.0f입니다.

따라서 텍스쳐의 왼쪽 끝은 x가 0.0f, y가 1.0f이고 사각형의 왼쪽 끝은 x가 -1.0f, y가 1.0f입니다. 이렇게 텍스쳐와 사각형의 나머지 세 꼭지점을 맞추어 줍니다.

한 번 glTexCoord2f의 x, y값을 변경시켜 보십시오. 1.0f를 0.5f로 바꾸면 텍스쳐를 0.0f(왼쪽)부터 0.5f(텍스쳐 가운데)까지만 그리게 될 것입니다. 0.0f를 0.5f로 바꾸면 텍스쳐를 0.5f(가운데)부터 1.0f(오른쪽)까지만 그리게 됩니다.



glBegin(GL_QUADS);

// 육면체의 정면
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); // 텍스쳐와 육면체의 왼쪽 위

// 육면체의 뒷면
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); // 왼쪽 밑

// 육면체의 윗면
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); // 오른쪽 위

// 육면체의 밑면
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); // 오른쪽 밑

// 육면체의 오른쪽 면
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); // 왼쪽 밑

// 육면체의 왼쪽 면
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();


이제 xrot, yrot, zrot의 값을 증가시킵니다. 한 번 각 변수의 증가값을 바꾸어서 육면체의 회전을 빠르게 혹은 느리게 해 보세요. 혹은 +와 -를 바꾸어 육면체가 다른 방향으로 회전하도록 해 보십시오.



xrot+=0.3f; // X 축으로 회전
yrot+=0.2f; // Y 축으로 회전
zrot+=0.4f; // Z 축으로 회전

return true;

}


******************

위의 번역은 Win32를 기준으로 만들어진 것이라서 그대로 맥의 카본 환경에서는 작동하지 않을 것입니다. 저는 몇 가지를 변경해서 동작하도록 했는데, 일단 BMP파일을 쓰지 않고 RAW파일을 써서 프로그램에서 그대로 파일을 읽어들이도록 했습니다. 실제 구현에 문제가 있으신 분들은 첨부한 소스를 참조하시면 되겠습니다.
0 0
로그인 후 추천 또는 비추천하실 수 있습니다.
포인트 228,692
가입일 :
2003-02-18 14:12:30
서명 :
미입력
자기소개 :
미입력

최신글이 없습니다.

최신글이 없습니다.

댓글목록 0

등록된 댓글이 없습니다.
전체 121 건 - 3 페이지
2004.01
25

[App 개발] CoreGraphics의 풀스크린 화면 만들기

박진철님께서 올리셨던 질문 중에 코코아에서 퀵드로우의 CopyBits대신 사용할 수 있는 방법으로서 아시는 분들은 다 아실만한 CGDirectDisplay 를 이용한 방법을 한 번 시도해 보았습니다. 프로그램은 심히 완성도가 떨어지는 관계로 감히…

2004.01
23

[App 개발] Cocoa Design Patterns (5)

Commands GOF의 패턴에 익숙하신 분들은 아마 타겟/액션이 마치 커맨드 패턴의 구현이라고 생각될 것입니다. 그러나 커맨드 패턴같은 것이 타겟/액션과 같은 구현이 이용된다 하더라도 Objective-C에서는 그것이 필요가 없습니다. 커맨드 패턴…

2004.01
22

[App 개발] Cocoa Design Patterns (4)

Enumeration 코코아의 모든 콜랙션 클래스는 계수기를 제공합니다. 이 패턴은 GOF의 반복기 패턴과 비슷합니다. 계수기는 객체의 집합을 훑어내고 각 객체에 어떤 일을 수행하는 방법을 제공합니다. 특정한 집합에 대하여 특수한 루프를 짜 주는 대…

2004.01
22

[App 개발] NeHe Lesson 16

이번 강의는 Chris Aliotta가 제작하였습니다. 당신의 OpenGL 프로그램에 안개를 넣고 싶으십니까 이번 강의에서 바로 그 방법을 보여드리려고 합니다. 저는 강의를 쓰는 것은 처음이고, OpenGL/C++ 프로그래밍은 근래에 시작한 것이…

2004.01
18

[App 개발] Cocoa Design Patterns (3)

평일은 바쁘니까 아무래도 주말에 열심히 진도를 나가는 것이 좋겠지요 번역이 많이 서툴러서 읽으시기에 불편하실지 모르겠습니다. 죄송합니다. ***** Class Clusters 클래스 클러스터는 복잡한 상속 구조를 숨기는 방법입니다. 기본적…

2004.01
18

[App 개발] NeHe Lesson 13

바로 뒤에 이어지는 두 개의 폰트 강의는 그냥 건너뛰려고 합니다. 윈도우 전용 코드 설명에 많은 부분이 할애되는 것도 그렇고, agl 함수 래퍼런스도 저에게 부족해서 (그리고 제 실력도 부족해서... 하하...) 일단은 이정도 선에서 폰트는 접도록 하…

2004.01
17

[App 개발] Cocoa Design Patterns (2)

Model-View-Controller 모델-뷰-컨트롤러, 줄여서 MVC 패턴은 패턴 이상의 구조물이라고 간주됩니다. 왜냐하면 이것은 응용 프로그램을 정리하는 기본적인 방법이며 모든 패턴들을 아우르는 상위의 구조적인 요소이기 때문입니다. 왜냐하면…

2004.01
17

[App 개발] Cocoa Design Patterns (1)

코코아를 배울 때, 코코아가 사용하는 용어 때문에 어려움을 겪으시는 분이 많으실 것입니다. 그 중에서도 코코아 설계에 응용된 디자인 패턴의 개념이 익숙하지 않아서 더 힘들게 느껴지시는 분들이 계실 줄 압니다. 제가 갖고 있는 책 Cocoa Progra…

2004.01
15

[App 개발] Nehe Lesson 12

이번 강의에서는 출력 리스트를 이용하는 법을 배우겠습니다. 단순히 리스트를 만들어 빠르게 하는 것 뿐만 아니라 간단한 GL 씬을 만들어야 할 때 몇 줄로 나누어 따로 사용할 수 있습니다. 예를 들어서 각 판을 두 개의 운석으로부터 시작하는 ast…

2004.01
13

[App 개발] NeHe Lesson 11

대충 소스를 돌아가게끔만 만들어서 캡춰해서 게재를 하다보니 혹시라도 소스코드상에 오류나 옛날 루틴의 찌꺼기등이 많이 끼어있을지도 모릅니다. ^^; 너그럽게 봐 주시고, 어쨌든 빨랑빨랑 진도를 나가는 방향으로 해 보겠습니다. 목표는 3D 게임 엔진 …

2004.01
10

[App 개발] NeHe Lesson 10

이 예제는 Lionel Brits가 만들었습니다. 여기서는 코드의 어떤 부분이 추가되었는지만 설명하고 있기 때문에 이 글에서 소개하는 코드만 가지고는 프로그램이 동작하지 않을 것입니다. 만약에 어떤 부분에 어떻게 코드가 첨가되었는지 알고 싶으시면 소스…

2004.01
09

[App 개발] NeHe Lesson 9

9번 강좌까지 오신 여러분 수고가 많습니다. 본 코스는… 쿨럭~ ㅡㅡ; 지금까지의 공부를 통해서 OpenGL윈도우를 여는 것부터 시작해서 광원과 투명처리를 한 텍스쳐 물체를 회전시키는 것까지, OpenGL에 대하여 많은 이해가 있으셨을 것입니다. 이번…

2004.01
08

[App 개발] NeHe Lesson 8

투명 OpenGL의 많은 특수 효과들은 블렌딩 기능을 이용합니다. 블렌딩이란 기존에 그려져 있는 픽셀과 새로 그리는 픽셀의 색상을 섞는 일입니다. 어떻게 색상을 섞는가는 색상의 alpha값과 블렌딩 함수에 따라 달라집니다. alpha값이란 색상을…

2004.01
07

[App 개발] NeHe Lesson 7

원문이 윈도우 소스를 기준으로 서술되어 있어서 많은 부분이 바뀌어 있습니다. 특히 키보드 입력 부분은 제가 따로 첨부하는 소스를 참조하시는 것이 더 나을 것입니다. (사실 소스를 잘 만들진 못했습니다. 대충 돌아가게만... ^^;;;) 그래도 없는 것…

2004.01
06

[App 개발] Carbon과 Cocoa중에서 어떤 것을 선택할까?

저는 C/C++ 프로그래머입니다. 옛날 터보씨 시절부터 C를 썼기 때문에 사실 이것을 고치기가 쉽지 않습니다. 자바 프로그래밍은 밥먹고 사는 문제 때문에 프로젝트를 하면서 배우게 되었습니다. 처음에는 C++의 개념을 갖고 접근하는 바람에 많이 헤매었는…

2004.01
05

열람중 [App 개발] NeHe Lesson 6

텍스쳐 매핑을 배우면 여러가지 잇점이 있습니다. 만약 화면을 가로질러 날아가는 미사일을 표현한다고 합시다. 지금까지 배운 것을 토대로 하자면 미사일 전체를 형형색색의 다각형을 모아서 만들어야만 합니다. 텍스쳐 매핑을 사용한다면 진짜 미사일 사진 한 장…

2004.01
04

[App 개발] NeHe Lesson 5

오늘은 지난 시간의 프로그램을 확장하여 3차원 공간에 2차원 물체 대신 3차원 물체를 만들어 보도록 하겠습니다. 삼각형 의 왼쪽, 오른쪽, 뒤쪽 면을 덧붙이고, 사각형에는 왼쪽, 오른쪽, 뒷면, 밑면을 덧붙일 것입니다. 그리고 나면 삼각형은 피라밋 모…

2003.12
30

[App 개발] NeHe Lesson 4

지난시간에는 삼각형과 사각형에 색상을 입히는 것을 배웠습니다. 오늘은 이 도형들을 축을 기준으로 회전하도록 만들겠습니다. 지난 시간에 썼던 코드에 몇 가지만 추가하면 됩니다. 밑에는 전체 코드를 기록할 것이기 때문에 어떤 부분이 추가되었고 어떤 부분…

2003.12
28

[App 개발] NeHe Lesson 3

지난 시간에는 삼각형과 사각형을 화면에 출력하는 것을 배웠습니다. 오늘은 도형에 색상을 입하는 두 가지 방법에 대해서 배울 것입니다. Flat Coloring으로 사각형을 단색으로 칠할 것이고, Smooth Coloring으로 삼각형의 꼭지점에 각각 …

2003.12
27

[App 개발] NeHe Lesson 2

원래는 Lesson 1부터 해야 하는데, 이미 살펴보신 분은 아시겠습니다만, 윈도우 여는 방법 설명이 반 이상입니다. MUG 게시판에 디바이스 컨텍스트가 어쩌고 저쩌고 설명하고 있으면 짜증나시겠죠 ^^; 빠진 부분은 나중에 다루어질 것으로 믿고, Le…

2003.12
26

[App 개발] NeHe Tutorial 따라가기 (0)

OpenGL 사이트 중에서 꽤 명성이 있는 NeHe 프로젝트의 튜토리얼을 따라가 보려고 합니다. 저는 지금까지 Win32와 DirectX 프로그래밍을 주로 해 왔고, 따라서 매킨토시의 Xcode도 처음이고, OpenGL도 처음입니다. 저 혼자 공부하는…