말머리
안녕하세요~ 샤케 입니다.^^.
슬슬 마지막 강좌 입니다.
맥스에서 애니 정보도 뽑아 올 수 있지만
제 실력이 안되는지라 이녀석을 마지막으로 할까 합니다.
이번 강좌는 소스에 대한 언급을 일체 안하겠습니다.
그 이유는 제 생각에 이번 강좌는
소스보다는 구현 방법(이론)을 살피는 것이
더 도움이 될거라 생각해서 입니다.
소스는 소스 자료실에 올려 놨으니 강좌를 보시면서
소스를 같이 보시면 많은 도움이 될거라 생각합니다.
뽑아내는 방법을 바꾸자
"헉...이녀석 이게 무슨 말이냐!!"
윗 글 그대로 입니다.
사실 저번 강좌까지는 텍스쳐 없이 맥스에서 익스포팅 하기 때문에
텍스쳐에 대해 걱정할 필요 없이 정말 단순하게 했으면 됐습니다.
하지만 이번에는 텍스쳐도 같이 익스포팅 해야 합니다.
"그게 무슨 큰 차이라고 방법을 바꾸는겨~~"
음..저도 처음엔 그리 생각했으나 실제로 구현을 해보면 크게 다릅니다.
우선 D3D 에서 텍스쳐 입히고 랜더링 하는 방법을 보죠.
보통 Render() 함수 안에서 구현을 합니다.
그리고 SetTexture() 라는 녀석을 사용해서 텍스쳐를 스테이지에 올립니다.
즉, 스테이지에 올린 텍스쳐를 기준으로 면과 점을 읽어와 그리게 됩니다.
그렇다면 익스포팅 할 때도 텍스쳐를 기준으로 면과 점을 뽑아내야 합니다.
그렇기 때문에 방법을 바꿔야 하는 것입니다.
어떻게 바꿀꼬...
일단 생각을 해 봅시다.
텍스쳐 기준으로 뽑는다는게 딱 생각을 하면 앞이 막힙니다.
그래서 주먹 구구식으로 일단은 모든 정점 정보를 얻어 옵니다.
문제는 전 시간처럼 점의 개수를 구하고 인덱스를 구하는 것이 아닙니다.
먼저 면의 개수를 구하고 점의 정보를 구해야 한다는 것입니다.
이유는??
우선 간단한 육면체를 생각해 봅시다.
그 육면체에 텍스쳐를 입힙니다.
그럼 점 한개에 겹치는 텍스쳐가 발생합니다.
아마 점 한개에 세개의 텍스쳐가 겹치겠죠.
즉, 8*3 = 24 개의 정점 정보가 필요합니다.
하지만 정점 개수는 8개 이니 16개의 정점 정보를 흘리게 되는 거죠.
그러므로 면의 개수 * 3 을 해주어서 꼭 필요한 정점 정보보다 많이 뽑아냅니다.
정육면체로 하면 12 * 3 = 36 개의 정점을 뽑아 내겠죠.
이것이 첫번째 과정입니다.
그럼 정점 정보만 뽑아 내면 되냐??
아닙니다. 텍스쳐를 입히기 때문에 텍스쳐에 대한 아이디를 얻어와야 합니다.
아이디라 하면 어려우니 인덱스라고 하죠.
만약 육면체를 그리는데 텍스쳐 6개를 사용했다고 하면 0부터 5까지의 인덱스를 부여합니다.
그리고 텍스쳐 인덱스를 이용해서 각 면을 나누어야 합니다.
즉, 각각의 텍스쳐가 몇개의 면에 걸치게 되냐 하는 겁니다.
육면체에서 여섯개의 텍스쳐를 사용하면 하나의 텍스쳐는 2개의 면을 걸치고
2개의 면에는 6개의 정점이 있습니다.
즉, 텍스쳐(이하 맵 또는 텍스쳐맵 또는 텍스쳐)에 걸치는 면의 개수를 세는 것이
두번째 과정이 되는 것입니다.
이제 이렇게 얻어 왔으니 불필요한 정점을 제외해야 합니다.
육면에체서 2개의 면(육면체와 구분짓기 위해 이하 페이스)을 그리는데
필요한 점(이하 버텍스)은 4개면 됩니다.
(단순하게 육면체에서의 한면을 생각합니다)
즉, 분류한 것들을 다시 저장을 합니다.
즉, 버텍스를 추가할 때 이미 들어와 있으면 버텍스 인덱스를 넘기고
새로운 것이면 버텍스를 추가한 후 인덱스를 넘겨줍니다.
이렇게 넘겨 받은 인덱스가 우리가 사용할 인덱스 버퍼가 됩니다.
이것이 세번째 과정이 됩니다.
"그럼 텍스쳐를 6개 사용했는지는 어떻게 아나?"
여기서 주의할 점이 있습니다.
단순하게 맥스에 있는 맵 개수를 얻어오는 함수를 사용하면 안된다는 것입니다.
맥스에 있는 함수를 사용하게 되면 그 수는 실제보다 더 크게 나옵니다.
정확하게 알아보지 않아서 모르겠습니다만...
아마도 각 페이스에 씌어져 있는 것들을 일일이 또다른 하나로 생각하고
페이스 개수 정도로 나와 버립니다.
그러니 여기에서도 중복된 텍스쳐는 추가 시키면 안되겠지요.
이 작업을 위의 세가지 보다 제일 먼저 해줘야 합니다.
그래야 텍스쳐에 따라 분류를 하고 저장을 하고 하겠죠.
첫번째, 텍스쳐 매니저를 만들자
익스포팅에서의 텍스쳐 매니저는 간단합니다.
텍스쳐 이름과 개수를 저장하면 됩니다.
그리고 저장을 시킬 때 이미 있는 텍스쳐인지 아닌지를 검사합니다.
이미 있는 것이면 추가를 안 시켜 주고, 없으면 추가를 시켜 줍니다.
소스를 보시면 아시겠지만 일단은 간단하다는 것을 알 수 있습니다.
두번째, 모든 정점 정보를 얻자
여기서 어떻게 얻어 온다고 했는지 다시 한번 알려드리겠습니다.
우선 면 개수를 얻어 옵니다.
그리고 면 개수 * 3 개의 버텍스 정보를 얻어 옵니다.
말은 쉽습니다...;;
과정은 여지껏 해온 방식하고 다릅니다.
소스를 보시면 일단 면의 개수를 구하고 루프를 돕니다.
그 안에 3번의 루프를 돕니다(x,y,z).
여기서 정점을 얻어 오는 방식이 틀리다는 것을 아실 수 있습니다.
즉, 면에 포함된 x,y,z를 이용해서 얻어오는 것이죠.
말로 하니 계속 그게 그것처럼 보이네요. 소스를 보세요.
그리고 텍셀 좌표를 정할 때 tv 의 좌표는 1.0f- 얼마 입니다.
이유는 텍스쳐가 거꾸로 보이기 때문에 돌려 놓는 것입니다.
직접 실험해 보시는 것도 재밌겠네요.^^.
그리고, 이젠 맵 아이디를 얻어옵니다.
처음 과정에서 했던 것 기억나시나요?
첫번째 과정에서 저장해 놓은 텍스쳐 정보를 가지고 아이디를 얻습니다.
즉, 지금 얻어오려는 페이스(혹은 버텍스)에서 사용하고 있는 맵을 얻어옵니다.
그리고 우리가 저장한 텍스쳐 정보를 기준으로 인덱스 번호를 매깁니다.
세번째, 분류하자
여기가 사실 제일 골치아프다면 골치 아픈 부분입니다.
각 텍스쳐가 어떤 페이스에서 몇번 사용되는지 숫자를 카운트 합니다.
카운트 된 숫자로 페이스 구조체의 크기와 버텍스 구조체의 크기를 정합니다.
그 후 두번째 과정에서 모아놓은 버텍스 정점에서 같은 맵 아이디인 버텍스만 얻어옵니다.
간단히 보자면 텍스쳐 개수 만큼 for 문을 사용하여 루핑(ㅋㅋ영어아~) 합니다.
0 부터 5 까지 루핑하겠죠.
그러면 0번 아이디를 두번째 과정에서 했던 종합 버텍스 구조체에서 얻어 옵니다.
즉, 맵 아이디와 현재 루핑되는 번호를 비교 후 같으면 가지고 옵니다.
이렇게 가지고 오면 위에서 설명 했다시피 두개의 페이스에 여섯개의 버텍스가 포함됩니다.
그러면 다음 네번째에서 걸러내는 것이죠.
네번째, 걸러내자
이건 간단합니다.
세번째 과정에서 분류한 구조체를 가지고 루핑합니다.
세번째 과정에서 얻어온 정점의 개수를 카운트 한 후에
카운트 만큼 for 를 사용하여 루핑합니다.
그리고 루핑하면서 버텍스에 대한 정보를 검색합니다.
여기서 중요한 점은 인덱스 정보도 여기서 얻는 다는 것입니다.
육면체에서 0번째 면에 해당하는 것을 예로 들어봅시다.
사각형 면에서 왼쪽위 0, 오른족 위 1, 왼쪽 아래 2, 오른쪽 아래 3 로 번호를 매겨봅시다.
우선 위에서 분류한 버텍스의 개수는 6개니 for 로 6번 루핑합니다.
0번째 버텍스는 0에
1 " " 1에
2 " " 3에
3 " " 3에
4 " " 2에
5 " " 0에 각각 번호가 매겨지겠쬬.
즉, 0번째 부터 2번째 버텍스는 저장을 하면서 각각 0,1,2 로 번호가 매겨집니다.
그리고 3번째 버텍스는 이미 저장을 했으니 이미 매겨져 있는 2를 저장합니다.
다음 4번째 버텍스는 새로운 것이므로 버텍스 정보를 저장하고 3번 이라는 번호를 매깁니다.
다음 5번째는 이미 있는 정점이므로 번호만 저장합니다.
이렇게 저장을 하면 버텍스 개수 4개 페이스 개수 2개로 각각 저장이 됩니다.
여기서 텍스쳐는 신경 안써도 될까??
안써도 됩니다.
위에서 최초의 루핑이 각 면의 개수입니다.
즉, 텍스쳐의 개수 만큼 루핑이 됩니다.
이때 0번째 루핑은 0번 텍스쳐를 이용하고
1번째 루핑은 1번 텍스쳐를 이용하게 됩니다.
그러므로 자연스레 텍스쳐에 대한 번호 매깁도 되는 것입니다.
(즉, 읽어올 때 순서대로 읽으므로 순서대로 텍스쳐를 사용합니다)
마무리 익스포팅
일단 TXT 파일로 저장하는 것은 개인 취향에 맞게 저장을 하면 되므로 걱정 없습니다.
문제는 DAT 파일입니다.
당연히 DAT 파일도 개인 취향에 맞게 저장을 하면 됩니다.
문제는 제 개인의 입장에서 보자는 것이죠(세상은 나를 중심으로 돌아~~)
저는 다음과 같이 DAT 파일을 작성 했습니다.
노드 개수
텍스쳐 개수
텍스쳐 이름
(텍스쳐 개수 만큼 반복)
{
오브젝트 이름
면 개수
면 정보
정점 개수
정점 정보
...
...
}
이렇게 출력하면 좋은 점??
없을지도 모릅니다. 단지 전 이게 편해서 이렇게 하는 것 뿐입니다.
만약 여러분이 더 편하게 할 수 있다면 더 편하게 하셔도 됩니다.
문제는 위의 과정들이 이렇게 뽑기 위해서 한 과정이니 이렇게 뽑아야 겠죠.
(역시 나를 중심으로 도는 구나~~)
그럼 이제 문제는 D3D 에서 읽어 오는 것이겠죠??
D3D 에서 읽어 보자
이게 정말 난감합니다.
누가 오브젝트 하나에 텍스쳐 하나로만 모델링 하는 것도 하니고
여러개의 오브젝트에 여러개의 텍스쳐를 사용하니 말입니다.
그렇다면 이것들은 어떻게 읽어 와야 할까요?
일단 위에서 출력한 것으로 읽어 보도록 하죠.
노드 개수 읽어 옵니다(사실 쓸 곳은 없습니다...)
텍스쳐 개수 읽어 옵니다.
이 개수를 가지고 여러 가지 메모리를 할당합니다.
정점 개수나 인덱스 개수를 저장할 배열의 크기를 정하고
텍스쳐를 저장할 구조체의 크기도 정하고
렌더링 할 때도 이 개수 만큼 루핑해서 렌더링 합니다.
그리고 텍스쳐 이름을 얻어 올 때도 이 개수만큼 루핑햇 얻어오죠.
다음으로 텍스쳐 개수 만큼 반복하면서 모델에 대한 정보를 얻어옵니다.
사실 텍스쳐 개수 만큼 이라고 했지만 파일이 끝날때까지 주구장창 루핑해도 됩니다.
이렇게 읽어 오고 사용은 하려면, 즉 렌더링을 하려면 어찌 해야 할까요?
렌더링 함수 부분을 봅니다.
텍스쳐 개수만큼 루핑을 해서 사용하려는 텍스쳐를 스테이지(SetTexture)에 올립니다.
그리고 스테이지 올린 텍스쳐에 해당하는 정점 정보와 인덱스 정보를 가지고 그립니다.
읔..여기서 막힙니다.
사실 하자면 합니다. 주먹 구구식으로 엄청난 길이의 소스를 자랑하면서 하면 말이죠;;
그럼 이렇게 설명한 것을 간단하게 소스로 보겠습니다.
(자세한 제가 올린 소스하고는 관련 없습니다)
일단 텍스쳐 개수를 구합니다( TextureCount )
텍스쳐 이름을 얻어옵니다( TextureName[TextureCount][256] )
얻어온 이름으로 텍스쳐를 생성합니다( LPDIRECT3DTEXTURE9 [TExtureCount] )
텍스쳐 개수 혹은 파일의 끝이 보일 때까지 루핑을 하면서 정보를 가져옵니다.
오브젝트 이름( ObjectName[64] )
면 개수 ( IndexNum )
면 정보 ( IndexNum * CUSTOMFACE )
정점 개수 ( VertexNum )
정점 정보 ( VertexNum * CUSTOMVERTEX )
여기서 CUSTOMFACE 과 CUSTOMVERTEX 은 구조체 입니다.
즉, 구조체를 개수 만큼 얻어온다는 거죠.
제 소스처럼 안하고 위에처럼 한번에, 즉 InitGeometry() 함수 안에
한꺼번에 쫘~악 읽어오고 저장하게 해도 됩니다.
다음으로 렌더링 할 때
텍스쳐 개수만큼 루핑하면서
저장한 텍스쳐를 스테이지에 올리고
저장한 면정보와 정점정보를 불러와서 그려줍니다.
정말 간단해 보이죠??
자...이렇게 하면 모델 하나가 끝납니다.
그럼 이제 두번째 모델도 그려야 하는데....
하긴 텍스쳐로 분리해서 저장했으니 그리 크게 신경쓸 부분은 아닙니다.
애초에 모델별로 저장이 아니라 텍스쳐 별로 저장이었으므로
모델이 두개가 되든 세개가 되든 텍스쳐 개수만큼 루핑하면 다 그릴 수 있습니다.
자 이렇게 그렸습니다.
문제는 다른 익스포팅된 파일로 이번엔 배경을 그리고 싶어졌습니다.
...헉!!
다시 위에것을 반복해야 한단 말인가....!!
아냐 배경 빼자...
그랬떠니 캐릭터를 두개 그려야 하는 상황이 왔습니다.
운좋게 똑같은 캐릭터가 아니고 하나는 여자, 하나는 남자 캐릭터 인것이었습니다!!
...헉!!
별 수 없이 위에 것을 한번 더 해야 합니다...
말도 안되죠??
이렇게 노가다를 줄여 주고자 제 소스에 있는 것처럼
텍스쳐 매니저, 오브젝트 메니저, 지오메트릭스 메니저가 필요합니다.
텍스쳐 매니저는 이름에서 처럼 텍스쳐 관리 매니저 입니다.
모든 텍스쳐에 대한 것은 이 매니저 클래스에서 조작합니다.
텍스쳐 저장과 얻어오기 역시 이곳에서 다합니다.
다음으로 오브젝트 매니저는 모델에 대한 정보를 얻어오는 부분입니다.
계란 노른자 같은 매니저죠.
그리고 지오메트릭스 매니저는 텍스쳐 매니저와 오브젝트 매니저를 연결시켜줍니다.
즉, 지오메트릭스가 대장으로 통솔하게 되는 거죠.
이렇게 하면 뭐가 좋아지냐?
위에 ...헉!! 하는 상황처럼 남자 캐릭터와 여자 캐릭터를 그려야 합니다.
그때 우리는 지오메트릭스 매니저를 배열로 두개 잡아주면 됩니다.
첫번째는 남자, 두번째는 여자.
렌더링 할 때도 캐릭터 개수 만큼 루핑하면서 지오매트릭스 매니저를 호출합니다.
제 생각이지만 이것들을 이용해서 지오매트릭스를 관리한 황제 매니저를 만듭니다.
이 황제 매니저로 지오매트릭스에 대한 연결 리스트를 구현하면
몇개의 캐릭터나 몇개의 아이템을 그려도 편하게 그릴 수 있습니다.
당연히 황제 매니저 클래스는 여러분의 몫입니다.
(사실...귀찮고 힘들고 소스도 난해하고 해서 떠넙깁니다...)
마무리
이제 대충 어떻게 하면 되겠다라는 생각이 넘치지요?
정말 오호..하고 막 코딩하면 되겠다 싶으시면 전 성공한 겁니다.^^.
제가 설명을 못드려서 제대로 이해 못하시는 분이 많으실 겁니다.
그땐 언제나 질문란에 글 올려주세요.
제 소스에 주석도 있으니 정말 모르겠다 하는 분은 안계실 거라 믿습니다.
현재의 소스는 단순히 모델을 익스포팅하고 D3D로 단순히 불러오는 것인데
시간이 지나 어느 정도의 때가 되면(...)
여러개의 캐릭터를 올릴 수 있는 프로그램을 보물 자료실에 올리겠습니다.
그때쯤 가면 황제 매니저 클래스를 완성 했을 수도 있고....
정말 단순하게 배열로 여러개의 캐릭터를 띄울 수도 있고...;;
어렵진 않지만 제 개인적으로 굉장히 힘들었던 강좌가 끝났습니다.
강좌를 봐주신 모든 분들께 "수고하셨습니다" 꾸벅...
그리고 앞으로도 제 실력이 쌓이는 대로 꾸준히 강좌를 올리겠습니다.
개인적인 사정(귀찮아즘과 의욕상실 등등)으로 언제가 될지는 모르겠지만
지금보다는 제대로 된 강좌를 꼭 올려보겠습니다.^^.
그럼 질문은 질문란에 제 소스는 소스 자료실에 아시죠?
첫댓글 강좌 감사합니다~