수안이의 컴퓨터 연구실

  • Mainpage
  • About Me
  • Tags
  • Metapage
  • Notice
  • Location
  • Keywords
  • Guestbook
  • Admin
  • Write an Article
  • Total | 1693892
  • Today | 243
  • Yesterday | 588

21 Articles, Search for 'Programming/Game Programming'

  1. 2007/01/03 [Source] 너구리 게임 소스
  2. 2005/09/12 3D로 이뤄진 게임 세계-4
  3. 2005/09/12 3D로 이뤄진 게임 세계-3
  4. 2005/09/12 3D로 이뤄진 게임 세계-2
  5. 2005/09/12 3D로 이뤄진 게임 세계-1
  6. 2005/09/12 다이렉트3D 프레임워크를 이용하자-4
  7. 2005/09/12 다이렉트3D 프레임워크를 이용하자-3
  8. 2005/09/11 다이렉트3D 프레임워크를 이용하자-2
  9. 2005/09/11 다이렉트3D 프레임워크를 이용하자-1
  10. 2005/09/11 3D 엔진 제작의 실제-1
«Prev  1 2 3  Next»
Programming/Game Programming2007/01/03 17:40

[Source] 너구리 게임 소스

Racoon.zip

예전에 받았었는데...

제 홈페이지를 뒤지다 보니 찾게 되었습니다.

Visual C++ 6.0 환경에서 컴파일 해보니 잘 되네요 ^^


"Game Programming" 카테고리의 다른 글
  • [Source] 너구리 게임 소스 (0)2007/01/03
  • 3D로 이뤄진 게임 세계-4 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-3 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-2 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-1 (0)2005/09/12
2007/01/03 17:40 2007/01/03 17:40
Posted by webdizen
Tags 너구리게임
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/2552

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Game Programming2005/09/12 15:02

3D로 이뤄진 게임 세계-4

김익중

행렬 변환과 기본 게임 코드
이제까지 익힌 것들을 바탕으로 다이렉트3D 상에서 간단한 게임 제작의 감각을 익혀보자. 우리가 할 것은 3D 공간을 만들고 그 위에 키입력을 받아 이동하는 비행기를 그려보며 리소스는 SDK 내의 X파일을 사용할 것이다. Direct9 App Wizard로 새 프로젝트를 만들자. 간단한 예제지만 bigship1.x 우주선을 움직여 볼 것이므로 프로젝트 이름만은 Flight라고 정하였다. 이 Teaspot을 만드는 기본 코드를 선택해 키 입력을 받아 회전시키는 대신 우주선을 움직이게 한다. 우주선은 하나의 플레이어 객체이므로 다음과 같이 선언했다.


<리스트 4> Flight.h



<화면 7> 변환을 통해 우주선이 새롭게 놓여졌다.


_MyPlayerObject 클래스는 플레이어 객체를 의미한다. 아주 간단한 예제이므로 초기의 시작 위치만 (0, 0, 0)으로 정해주었다. 하지만 이 클래스 내에는 실제 출력시킬 메시에 대한 값은 들어 있지 않다. CD3DMesh *m_pMyPlayerMesh로 메시 객체를 하나 더 만들었는데 이는 우리의 플레이어 비행기를 담을 메시(X파일이 로딩될)이다. CD3DMesh의 메쏘드인 Render()(내부적으로 DrawSubset()을 호출한다)를 호출하면 우주선이 보일 것이다. 그러나 위치가 맞지 않아 우주선의 한 가운데에 시선이 위치할 것이다.


<리스트 5> Flight.cpp 렌더링 부분에서 변환을 해보자.


여기서 지난 시간에 설명했던 변환을 다시 상기해보자. 일단 다이렉트3D에는 왼손 좌표계에 의한 월드 좌표계가 존재한다. 또한 각 메시(모델)에는 정점을 표시하기 위한 로컬 좌표계가 있다. 따라서 로딩이 되면서 모델의 기준점을 월드 좌표로 바뀌게 된다. 바로 월드 변환이다. 이에 관찰자가 보는 시선으로 다시 바꿔줘야 한다. 바로 뷰 변환이다(그리고 투영변환을 거쳐 모니터에 출력된다). 현재는 우주선을 로컬 좌표로 그린 후 월드 좌표를 회전시키고 있다. 원하는 위치에 우주선을 두기 위해서는 월드 좌표를 모델에 맞게 바꾼 후 우주선을 그리고 다시 원상태로 월드 좌표를 바꿔야 한다(로컬 좌표는 바뀌지 않는다). 카메라 추가까지는 단순 뷰포트였지만 생성시킨 카메라를 사용해 보자.
vAt을 보면 알 수 있듯이 Z값 10에서 (0, 0, 0)을 바라본다. 즉, 화면 뒤쪽에서 우주선을 바라보는 것이다. 실행시켜보면 뒷부분에서 바라본 우주선이 놓여진다. 이제까지 충실히 다뤘던 메쏘드와 인자라 설명할 부분은 없을 듯하다.
그런데 키 입력시 움직이던 방향이 달라져 좌우 움직임이 다른 것을 느낄 것이다. 3D 게임에서 코드 외적으로 이 부분이 힘든 부분인데 1인칭 시점에서 달리던 캐릭터가 3인칭으로 바뀌게 되면 갑자기 키 입력이 힘들어지던 적이 많았을 것이다. 물론 소스 상에서 카메라 위치의 변경에 따라 키 입력도 반대로 해주면 되겠지만 이는 게이머의 입장에서는 상당히 곤란한 부분이다. 카메라 각도 얼마인 시점에서 갑자기 키가 바뀔 것인가? 혹은 시점 변환에 따라 키가 달라지는 것 자체를 싫어하는 게이머도 많음을 기억할 필요가 있다.
지면 관계상 실제 슈팅 게임으로는 진행되지 못했는데 적 우주선과 총알은 플레이어 우주선의 좌표계에 맞춰 같은 방식으로 그리면 될 것이다. 판정을 내리는 방법은 간단히 경계 볼륨 방식을 취하면 될 것이다. 경계 볼륨은 모델의 중심 좌표부터 반지름의 크기를 구한다. 플레이어와 적 우주선의 반지름의 합이 두 모델의 원점을 긋는 선분보다 작으면 충돌이다.
메시로 이뤄진 지평선 끝에 가장 빛나고 있는 정점이 보인다. 월드 좌표의 윗점으로 온 것이다. 그리고 그 가운데에서 빛을 내고 있는 소녀를 보았다.


<화면 7> 카메라의 추가로 뒷부분에서 우주선을 볼 수 있다.


<리스트 6> Flight.cpp 카메라의 추가


다이렉트드로우에서 다이렉트3D까지
겨울이 성큼 왔다. 지난 가을병(?)이 깊어진 탓인지 의욕이 가득했던 마지막 강좌가 온갖 것을 모아두고 마무리 짓는 것 같다. 하지만 2002년 6월 다이렉트드로우를 시작으로 다이렉트3D까지 다이렉트X의 거의 모든 컴포넌트들을 한 번씩 거쳐 온 것은 보람 있게 느껴진다. 연재 강좌라는 특성과 게임 제작이라는 내용상, 어려움과 한계가 많았지만 이 강좌를 통해 한 명의 독자라도 열정을 발산할 기회와 게임을 제작해 볼 용기를 얻었다면 필자는 더 큰 보람을 느낄 것이다. 더 충실하고 유용한 내용으로 새롭게 게임 드라이빙 스쿨을 개장할 날을 기다리며 밀린 그림일기를 오늘밤부터 다시 그려야겠다. 일기를 보고 싶은 독자는 rhea.pe.kr로 오길 바라며 이번 크리스마스를 대비한 ‘기우제’를 함께 준비해 보자.

정리 | 위윤희 | iwish@korea.cnet.com

참+고+자+료
◆ 3D 카페. 무료로 사용할 수 있는 3D 모델을 제공한다. http://www.3dcafe.com/
◆ 무료 3D 모델들이 링크되어 있다. X파일 변환에 알맞은 3DS 파일(법선 처리가 되어있는)들은 이쪽에서 찾을 수 있었다. http://homepage1.nifty.com/hakka/edo/zakki/fdata.html/
◆ 풀벅의 3D 포맷 분석 페이지, http://astronomy.swin.edu.au/~pbourke/geomformats/
◆ GameDev.Net의 타일맵 섹션. 3D 타일맵에 대한 자료도 풍부하다. http://www.gamedev.net/reference/list.asp?categoryid=44
◆ IsoHex 3D 타일맵의 깊이있는 예제들이 있다. http://www.isohex.net IsoHex.
◆ 3D 게임 프로그램 & 컴퓨터 그래픽을 위한 수학 (정보문화사) : 본 강좌에서 다루지 못한 수학을 설명해주고 있다. 특히 어떤 부분에서 어떤 공식이 왜 적용되는지를 자세히 다룬 서적이다.
◆ Special Effect Game Programming with DirectX(민프레스)
"Game Programming" 카테고리의 다른 글
  • [Source] 너구리 게임 소스 (0)2007/01/03
  • 3D로 이뤄진 게임 세계-4 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-3 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-2 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-1 (0)2005/09/12
2005/09/12 15:02 2005/09/12 15:02
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/1510

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Game Programming2005/09/12 14:58

3D로 이뤄진 게임 세계-3

김익중

행렬 헬퍼 함수
확장 함수는 벡터에 이어 행렬 함수도 지원한다. 확장 함수를 위해 행렬 구조체도 D3DXMATRIX를 사용한다.

▶ D3DXMatrixIdentity() : 단위행렬(항등행렬)을 만든다.
▶ D3DXMatrixInverse() : 역행렬 계산
▶ D3DXMatrixIsIdentity() : 해당행렬이 단위행렬인지 검사한다.
▶ D3DXMatrixLookAtLH() : 왼손 좌표계로 바라보는 뷰행렬을 설정한다.
▶ D3DXMatrixLookAtRH() : 오른손 좌표계로 바라보는 뷰행렬을 설정한다.
▶ D3DXMatrixMultiply() : 행렬 곱셈
▶ D3DXMatrixOrthoLH : 왼손 좌표계로 직교 투영 행렬을 설정한다.
▶ D3DXMatrixOrthoRH : 오른손 좌표계로 직교 투영 행렬을 설정한다.
▶ D3DXMatrixPerspectiveFovLH : 왼손 좌표계 기반의 FOV 투영 행렬을 설정한다.
▶ D3DXMatrixPerspectiveFovRH : 오른손 좌표계 기반의 FOV 투영 행렬을 설정한다.
▶ D3DXMatrixRotationAxis() : 임의의 축에 의한 회전 행렬 계산
▶ D3DXMatrixRotationX() : X축으로 회전하는 회전 행렬 계산
▶ D3DXMatrixRotationY() : Y축으로 회전하는 회전 행렬 계산
▶ D3DXMatrixRotationZ() : Z축으로 회전하는 회전 행렬 계산
▶ D3DXMatrixScaling() : X, Y, Z축에 따라 스케일 행렬 계산
▶ D3DXMatrixTranslation() : 이동 행렬 계산


D3DX 확장 함수가 표준으로 사용되며 이상의 함수들을 프레임워크 속에서 필수적으로 만나게 될 것이다. 지면 관계상 더욱 자세한 용도와 증명은 할 수 없지만 예제들을 분석해가며 자신의 것으로 만들자.

버티가 있는 곳으로 가려면 어디로 가야할까? 난 3D 공간 속에서 땅을 만들어 본다. 왠지 이 끝으로 걸어가면 버티가 살고 있던 3D 세계가 있지 않을까. 메시로 드리워진 바닥 위에 한 발자국씩 옮기기 시작했다. 왠지 눈이 감긴다.

다이렉트3D에서 타일맵?
3D에서 타일맵이라니 어울리지 않는다고 생각할 독자가 있을지도 모르겠다. 하지만 다이렉트3D의 가속 기능을 이용한 타일맵은 꽤 오래전부터 사용되어 왔으며 차원수를 막론하고 타일맵은 여전히 가치있는 맵의 형태이다. 디아블로 Ⅱ는 3D 타일맵의 성공적인 사례를 보여준 게임이다. 사족을 달면 그만큼 스타크래프트와 디아블로 Ⅱ는 개발자에게 엄청난 분량의 숙제와 화두를 제공해 주며 몇 년을 곱씹어 볼 역작임이 틀림없다.


<화면 4> 디아블로 II의 한 장면. 정점을 이용해 밤을 표현했으며 특정 물체나 캐릭터 주위의 정점만은 다른 색으로 표시했다.


디아블로 Ⅱ는 2D와 3D를 동시에 지원한다. 3D를 선택했다면 원근감 있는 지형을 볼 수 있다. 즉, 화면 아래쪽의 지형은 크게 보이고 뒤쪽은 조금 작아 보인다. 또한 용암은 무시무시한 빛을 발하며 울렁거린다. 이것은 단순히 2D로 배경 스프라이트를 나열한 것이 아니라 3D 메시로 지형을 만들고 그 위에 지형 텍스처를 맵핑했기 때문이다. 또한 낮과 밤을 효율적으로 만들 수도 있다. 정점의 색깔만 바꿔주면 되기 때문이다. 여기에 캐릭터가 서 있는 위치를 판별하여 해당 정점의 색깔만 밝게 해주면 밤이라도 캐릭터 주변만은 밝게 보인다. 이것을 이용하여 독에 감염되었을 때는 정점을 녹색으로 바꾸는 등 많은 트릭을 구현한 것이다. 즉, 정점이라는 3D만의 요소에 상상력만 동원하면 2D에서 구현하기 힘들었던 각종 효과들을 만들어 낼 수 있다.
이런 것들을 2D의 알파 블렌딩으로 구현하자면 3D보다 더 많은 시간이 구현되며 팔레트 연산 때문에 256컬러로 한정될 수밖에 없다(실제로 디아블로 Ⅱ는 그 화려함에도 불구하고 고작 256컬러만으로 구현된 ‘예술’이다). 하지만 완전한 3D 지형이 아닌 타일맵이기에 나름대로의 이상 현상도 있다. 캐릭터가 절벽위에 서 있더라도 높이는 똑같기에 절벽이란 상황을 무시하고 빛이 휘어지지는 못한다.



<리스트 2> lsomap.cpp


먼저 <리스트 2>의 흥미로운 소스를 주목해 주길 바란다. Isohex (http://www.isohex.net)에서 제공하는 공개 소스를 조금 바꾼 것으로 정점의 위치를 증가시켜 3개의 정점으로 타일을 만들어 낸다.
실행 결과가 무척 흥미롭지 않은가? 여기서 Z 값을 바꾸면 어떻게 될까? 즉, 정점의 높이를 바꾸어 보자. 높이가 계속 달라지며 텍스처를 바꾼다면 파랑이 이는 수면을 만들 수도 있을 것이며 개발자의 상상력에 따라 무한한 응용이 가능할 것이다. 그리고 뷰포트나 변환 코드가 추가된다면 회전 맵의 제작이 가능해진다.
2D와 크게 다를 바 없었던 타일맵이 단지 높이의 증가만으로 새로운 지형으로 바뀌었다. 정점의 한 가지 속성을 바꿈으로써 완만한 언덕이 될 수도 있으며 높은 산을 만들 수도 있다. 완전한 3D 지형물을 만드는 방법은 아니지만 이것을 이용하여 지형 제작에 대한 상상력을 발휘하길 바란다.


<화면 5> lsomap.cpp의 실행 결과. 다이렉트3D로 만들어진 2D 형식의 타일맵이다.


<화면 6> 정점들의 높이를 바꾼 결과


내가 눈을 뜬 곳은 방금까지 내가 있던 곳이 아니었다. 이제까지 모니터 속에서 봐왔던 정점 좌표들은 어마어마한 속도로 이동되고 있었으며 수많은 메시들은 밝은 빛을 내고 있었다. 이곳이 3D 파이프라인을 타고 온 월드 좌표계일까? 중간에 보이는 가장 큰 길, 단위행렬을 따라 난 계속 걸어간다.
"Game Programming" 카테고리의 다른 글
  • [Source] 너구리 게임 소스 (0)2007/01/03
  • 3D로 이뤄진 게임 세계-4 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-3 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-2 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-1 (0)2005/09/12
2005/09/12 14:58 2005/09/12 14:58
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/1509

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Game Programming2005/09/12 14:55

3D로 이뤄진 게임 세계-2

<리스트 1>에서 특별히 주목할만한 부분은 머티리얼 정보를 변환하는 부분이다. pD3DXMtrlBuffer는 모든 머티리얼 정보를 가지므로 메시와 함께 사용하기 위해서 실제 머티리얼 데이터로 변환한다. 이때 사용되는 메쏘드가 ID3DXBuffer::GetBufferPointer이다.


<리스트 1> XFile02.cpp


D3DXMATERIAL *d3dxMaterials =
(D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();


변환된 d3dxMaterials는 머티리얼 개수만큼 순환하는 루프 문장 속에서 해당 메시의 텍스처 파일명을 리턴한다. d3dxMaterials[i]. pTextureFilename를 확인해보면 텍스처 파일들이 나올 것이며 D3DXCreateTextureFromFile()로 텍스처 매핑을 수행하게 된다. 실제 적용시키는 부분은 Render() 함수 내이다. DrawPrimitive()로 화면을 그렸던 지난 시간의 예제들과 비교해보길 바라며 언제나처럼 카메라, 조명 등을 바꿔보자. XFile02.dws에 익숙해지면 SDK내의 OptimizeMesh 예제를 다시 읽어보며 프레임워크 내에서 X파일은 어떻게 로딩되는지도 확인해 보자.

정점 생성, 텍스처 생성, 조명과 카메라 생성, 카메라를 뷰포트로 변환, 파이프라인, 월드 좌표 등 버티가 나에게 가르쳐준 것들을 되뇌이고 또 되뇌인다. 언제나 내가 하는 것은 이것 뿐….


<화면 3> 텍스처와 머티리얼이 포함된 X파일 로딩. 좌우 방향키를 눌러보자.


프레임워크 다시 보기
이상으로 필수 불가결한 다이렉트3D의 요소들을 살펴보았다. 기본 API를 익혔다 하더라도 프레임워크를 공부하며 만나는 낯선 클래스와 함수들은 또 다른 어려움을 줄 것이다. 마치 ::MessageBox()와 AfxMessageBox()의 차이처럼. D3DX 확장 인터페이스는 MSDN을 참조하기 바라며 주요 클래스와 멤버 함수들은 정리해 본다.

CD3DCamera 클래스
이제까지 설정한 카메라가 추상화되어 있다. 모든 함수는 각각의 멤버 변수를 리턴하거나 사용한다. 함수는 각각의 멤버 변수를 리턴하거나 사용하는데 위치와 방향의 D3DXVECTOR3 구조체 벡터 변수들이며 투영 변환과 뷰 변환을 위해서 D3DXMATRIXA16 구조체를 이용한다.

▶ GetEyePt() : 카메라 위치를 반환
▶ GetLookatPt() : 카메라 시선을 반환
▶ GetUpVec() : 상향 벡터 반환
▶ GetViewDir() : 시선 방향 반환
▶ GetViewMatrix() : 뷰 변환 행렬 반환
▶ GetBillboardMatrix() : 빌보드(카메라 방향과 함께 변환되어 항상 카메라 방향에 위치) 매트릭스 반환
▶ GetProjMatrix() : 투영 변환 매트릭스 반환


CD3DFont 클래스
다이렉트3D에서 글자를 쓰기위한 클래스이다. 다이렉트3D 9에서 GDI를 이용할 수도 있지만 속력을 생각하면 CD3DFont 클래스를 사용해야 한다. 물론 CMyD3DApplication::Render() 안에서 호출된다. Text3D 예제를 분석하길 바란다.

▶ DrawText : 2D 텍스트 출력
▶ DrawTextScaled : 크기가 조절된 2D 텍스트 출력
▶ Render3DText : 3D 텍스트 출력.
▶ GetTextExtent : 출력될 텍스트의 크기를 리턴


CD3DMesh 클래스
D3DXLoadMeshFromX()을 이용해 X파일을 로딩한다. OptimizedMesh 예제를 분석하길 바란다.
▶Create : X파일을 읽어 메시 데이터를 생성한다.
▶UseMeshMaterials : 머티리얼을 사용할 것인지 결정
▶SetFVF : 메시를 FVF로 설정한다.
▶Render : 메시 렌더링
▶Destroy : 메시 데이터 해제


헬퍼 함수
D3DUtil.cpp에 포함된 광역 함수들이다.

▶ D3DUtil_CreateTexture() : D3DXCreateTextureFromFileEx() 함수를 호출해 텍스처 생성, D3DXCreateTextureFromFile() 보다 다양한 기능이 있다.
▶ D3DUtil_CreateVertexShader : 정점 세이더 생성
▶ D3DUtil_GetRotationFromCursor : 커서의 이동으로 회전 값 계산
▶ D3DUtil_InitMaterial : D3DMATERIAL9 구조체로 머티리얼 생성
▶ D3DUtil_InitLight : D3DLIGHT 구조체로 조명 생성


벡터 헬퍼 함수
다이렉트3D는 확장 함수 차원에서 개발자의 복잡한 수학 계산을 대신해 준다. 벡터의 가감부터 정규화, 내적, 외적은 함수차원에서 제공된다. D3DVECTOR를 대신할 D3DXVECTOR3는 C++로 재작성되어 연산자 오버로드를 지원한다. D3DXVECTOR2, D3DXVECTOR3, D3DXVECTOR4는 차원 수를 나타내며 함수 역시 각 구조체별로 존재한다.

▶ D3DXVec3Add() : 벡터의 합
▶ D3DXVec2CCW() : 두 개의 2차원 벡터 외적으로 Z요소를 리턴한다.
▶ D3DXVec3Dot() : 벡터의 내적
▶ D3DXVec3Length() : 벡터의 길이
▶ D3DXVec3LengthSq() : 벡터의 길이의 제곱
▶ D3DXVec3Normalize() : 벡터 정규화
▶ D3DXVec3Scale() : 벡터 스케일링
▶ D3DXVec3Subtract() : 벡터의 뺄셈
▶ D3DXVec3TransformCoord() : 행렬(D3DXMATRIX)로 벡터를 변환하고 그 결과를 w=1로 투영. 4차원 벡터에서 사용할 수 없다.
▶ D3DXVec3TransformNormal() : 행렬(D3DXMATRIX)로 법선 벡터를 변환
"Game Programming" 카테고리의 다른 글
  • 3D로 이뤄진 게임 세계-4 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-3 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-2 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-1 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-4 (0)2005/09/12
2005/09/12 14:55 2005/09/12 14:55
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/1508

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Game Programming2005/09/12 14:53

3D로 이뤄진 게임 세계-1

김익중 (rheastrike@hanmir.com)

지난 시간까지 다이렉트3D의 설정, T&L, 모델을 그리는 것과 프레임워크까지 다루었다. 이제 다이렉트3D와 함께 할 마지막 시간이 왔다. 이번 강좌에서는 그래픽 툴에서 만들어진 모델 파일을 다이렉트3D로 불러오는 법과 간단한 지형을 만들어 볼 것이다. 그리고 모든 것들을 통합해 3D 게임을 만드는 감각을 익혀볼 것이다.


김익중 | rheastrike@hanmir.com
살아오며 요즘처럼 번뇌의 무게에 짓눌린 적이 없는 것 같다. 그래도 버티고 있는 이유는 내일에 대한 희망 때문일까? 하지만 이 희망 자체가 나를 속이는 또 다른 장치가 아닐지… 이런 생각과 다르게 현실은 CMM에서 열심히 프로젝트를 진행 중이다.
--------------------------------------------------------------

여기까지가 내게 일어났던 이야기이다. 그렇게 버티가 사라지고 난 후, 버티가 가르쳐준 기술들을 이용해 프로젝트를 성공적으로 수행해왔다. 몇 번의 성공적인 과정이 지나간 후 처음 이야기한대로 난 어느덧 업계에서 조금씩 알려진 개발자가 되었으며 오늘에 이른 것이다. 하지만 언제나처럼 내 방에서 날 귀찮게 하던 그 애가 없는 지금, 그토록 원했던 지금의 모든 것 속에서 일체의 의미를 찾을 수 없다.

메시는 저 너머에 있다, X파일
지난 시간까지 우리는 정점을 다루어 하나의 모델을 완성했다. 그러나 복잡한 모델을 순수 코딩으로 만든다는 것은 상상만 해도 끔찍하다. 이것은 1024×768 해상도에서 Set Pixel()과 for문으로 모나리자 그림을 찍는 것과 같다. 2D에서 포토샵이나 페인터로 이미지와 스프라이트를 그렸듯이, 3D에서도 전용 3D 툴로 모델을 제작하게 된다. 마야, 라이노 3D(Rhino 3D) 등 여러 툴들이 있지만 가장 많이 사용되는 툴은 역시 3D 스튜디오 MAX이다. 3D 스튜디오 MAX는 과거 DOS 시절부터 각광받던 3D 툴로써 3DS라는 자체 모델 포맷을 가지고 있다. 현재 3D MAX는 MAX 포맷을 디폴트로 이용하지만 기존에 광범위하게 퍼졌고 단일 모델을 위해 여전히 3DS 포맷을 지원하고 있다.


<화면 1> 3DS 파일을 X파일로 변환 후 메시 뷰어로 확인


그리고 다이렉트3D 역시 3DS 포맷을 이용한다. 단, 3DS 포맷을 그대로 이용할 수는 없다. 다이렉트3D 공식 3D 모델 포맷인 X파일(이 이름은 정말 마이크로소프트의 네이밍 센스 중 걸작으로 꼽힌다!)로 변환하여 사용해야 하는데 이때 Conv3DS.exe라는 유틸리티가 활용된다. 사용 방법은 ‘Conv3DS 3DS 파일명.3ds’만 해주면 새롭게 X파일이 생성될 것이다. 이 X파일은 SDK 내의 유틸리티인 메시 뷰어(mesh viewer)로 확인할 수 있다.
이제 할 일은 이 X파일을 다이렉트3D에서 읽어오는 것. X파일을 로딩하는 함수는 역시 D3DX의 유틸리티 함수를 이용한다.

HRESULT D3DXLoadMeshFromX( LPCTSTR pFilename,
DWORD Options,
LPDIRECT3DDEVICE9 pDevice,
LPD3DXBUFFER* ppAdjacency,
LPD3DXBUFFER* ppMaterials,
LPD3DXBUFFER* ppEffectInstances,
DWORD* pNumMaterials,
LPD3DXMESH* ppMesh
);


◆ LPCTSTR pFilename : 불러 올 X파일
◆ DWORD Options : 다양한 옵션을 줄 수 있는데 보통 D3DXMESH_ SYSTEMMEM 사용하여 정점과 인덱스를 시스템 메모리에 올린다.
◆ LPDIRECT3DDEVICE9 pDevice : 이 자원을 관리할 장치. 즉, IDirect3 Device9 인터페이스
◆ LPD3DXBUFFER* ppAdjacency : ID3DXBuffer 인터페이스에 대한 포인터. 정점 정보가 들어간다.
◆ LPD3DXBUFFER* ppMaterials : 머티리얼(material) 정보
◆ LPD3DXBUFFER* ppEffectInstances : D3D9에서 추가된 인자로 특수 효과를 지정한다.
◆ DWORD* pNumMaterials : 4번째 인자에 들어간 머티리얼의 수
◆ LPD3DXMESH* ppMesh : 읽어 올 메시 정보


이렇게 읽어 온 X파일은 메시 정보가 LPD3DXMESH 구조체에 담긴다. 따라서 실제로 화면을 그리는 함수는 DrawPrimitive()가 아닌 DrawSubset()를 사용하게 된다.

HRESULT DrawSubset(
DWORD AttribId
);


<화면 2> XFile01.dws의 실행 화면. 메시 뷰어와 같이 상어가 보인다.

인자는 하나뿐인데 화면의 그릴 메시의 ID라고 생각하면 된다. 따라서 DrawSubset()은 한 번의 호출로 이뤄지는 것이 아니라 머티리얼의 수만큼 루프를 돌며 그리게 된다. D3DXLoadMeshFromX를 이용한 것이 XFile01.dsw이다. 지난 시간의 카메라와 조명이 붙은 프로젝트에서 X파일 로딩 부분만 합쳐진 것이다. 각자 카메라와 조명, 머티리얼을 바꿔가며 어떻게 렌더링되는지 살펴보자.
그런데 D3DXLoadMeshFromX의 인자를 살펴보면 알겠지만 X파일에는 정점, 즉 메시 이외에 머티리얼과 텍스처 맵핑 정보가 함께 들어가는 경우가 많다. 이번에는 머티리얼과 텍스처 정보를 가진 X파일을 읽어 들여 더 3D 다운 화면을 렌더링해 보자. SDK 내의 envcube.x 파일을 읽어보자. XFile01.dsw가 메시 정보만 읽었다면 이번에는 머티리얼과 텍스처 정보를 함께 읽는다. 읽어 온 머티리얼과 텍스처 정보는 지난 연재에서 다뤘던 D3DMATERIAL9와 LPDIRECT3DTEXTURE9를 이용한다. 새롭게 추가된 함수는 없다. X파일을 읽으며 그 안에서 D3DXCreateTextureFromFile()로 X파일에서 텍스처 정보를 읽어 들이면 된다.

[ 퀘이크와 메시 포맷 ]

X파일은 오래 전 다이렉트3D 유지모드에서 출발했지만 현재는 다이렉트3D 표준 3D 파일이라고 불러도 무방하다. 하지만 3DS를 비롯한 다양한 메시 파일들은 엔진 형태에 따라 여전히 사용되고 있다. 3DS 파일은 3D MAX SDK에서 자료를 얻을 수 있다. 이와 함께 ASE 포맷도 관심을 가져봐야 하는 포맷이다. ASE는 역시 3D 맥스로 추출할 수 있는데 모델과 애니메이션 정보가 함께 포함되어 있으면서도 특이하게 순수 텍스트 기반의 포맷이다.
많은 포맷들 중 가장 인기를 누린 포맷은 뭐니뭐니해도 MD2와 MD3 포맷일 것이다. 이들은 절대적인 인기를 누린 퀘이크 엔진에 사용된 포맷들로 X파일 이상의 정교한 정보들을 포함하고 셰이더를 포함한 다양한 기능들을 지원한다. 퀘이크 엔진을 분석하는 것은 힘들지만 메시 포맷을 열어보는 것은 존 카멕이 어떤 식으로 코딩을 했는지 알아볼 수 있을 것이다.
자세한 자료를 원한다면 퀘이크 Ⅱ에 사용되었던 MD2 포맷은 ‘Inside Direct3D(정보문화사)’에서 제공하고 있으며 퀘이크 Ⅲ의 MD3 포맷은 ‘Beginning Direct3D Programming(민프레스)’에서 자세히 분석해 두고 있다. 무료인 자료를 찾는다면 폴벅의 홈페이지에서 자세히 분석했으니 찾아가보길 바란다(http://astronomy.swin.edu.au/~pbourke/geomformats/).
"Game Programming" 카테고리의 다른 글
  • 3D로 이뤄진 게임 세계-3 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-2 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-1 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-4 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-3 (0)2005/09/12
2005/09/12 14:53 2005/09/12 14:53
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/1507

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Game Programming2005/09/12 00:49

다이렉트3D 프레임워크를 이용하자-4

김익중 (rheastriker@chol.com)

모든 시작은 d3dapp.h부터
그나마 다행인 것은 아직은 프레임워크가 구성하고 있는 체제는 C++이며 계층은 복잡하지 않다는 사실이다. 클래스의 수가 많은 것은 그만큼 많은 기능들을 지원해준다는 의미로 받아들이면 부담을 느끼지는 않을 것이다. 모든 시작은 d3dapp.h에 있는 CD3DAppli cation 클래스로부터 시작된다. 이름 그대로 이 클래스는 다이렉트3D 기반의 프로그램을 만들기 위한 클래스로 첫 시간에 깊게 파헤쳐 보았던 윈도우의 생성과 다이렉트3D의 생성 임무를 띠고 있다. 이 클래스를 상속받는 클래스가 CMyD3DApplication 클래스로써 자신이 만들 프로그램의 뼈대가 된다. 다른 클래스는 전부 유틸리티 클래스라고 생각하고 클래스 수에 대한 두려움을 버리자.
처음으로 시작되는 메쏘드는 CD3DApplication::Create()로 이 부분에서 Direct3DCreate9()가 호출된다. 이 안에서 눈여겨 볼 메쏘드는 ConfirmDeviceCallback()로 이것은 m_d3dEnumeration에 의해 여러 장치가 나열되고 그 중 애플리케이션이 요구하는 기능에 만족하는 장치를 선택하게 만든다. Create()가 다시 호출하는 함수들은 <그림 4>와 같은데 이 안의 함수들을 따라가며 읽어보길 바라며 세부 구현 사항은 지난 첫 번째 연재를 참조하기 바란다. 이중 다이렉트3D의 설정을 맡는 부분은 Intialize3DEnvironment()로 으로 창 모드와 윈도우 모드를 함께 지원하도록 되어 있다. 전체적인 모습은 세부 설정을 위한 다이얼로그가 추가된 것 이외에는 기존 우리의 코드와 상당히 흡사하다. 이는 개발자에게 다이렉트3D의 복잡한 세부 설정은 숨기고 최대한 애플리케이션 제작에만 전념하도록 디자인해 놓은 것이다.


<그림 4> Create()의 호출



<그림 5> Run()의 호출


애플리케이션을 동작하는 실체는 Run()에서 불려진다. Run()은 윈도우 메시지 처리만 하고 있는 간단한 형태를 취한다. 메시지 처리방식은 기존 우리가 한 것과 조금 모양은 다르지만 실제 역할은 같다. 비활성화, 애플리케이션 중지시에 관한 처리가 되어 있다. 또한 TranslateAccelator()에서 키보드 단축키를 읽는 것이 추가되었는데 으로 인한 단축키를 해석하기 위해서이다. Run()에 호출하는 Render3DEnvironment()에는 렌더링과 화면을 갱신하는 핵심부분이 불려진다.


<리스트 1> Render3DEnvironment()


가장 첫 번째로 나타나는 TestCooperativeLevel()는 현재 디바이스의 상태를 검사하여 그릴 수 있는지 여부를 판단한다. 창 모드, 전체 화면에서의 태스크 스위칭 등 서피스를 복구하는 역할을 하는 것이다. 메시지 펌프와 함께 이제까지 손코딩으로 계속 신경써 온 부분인데 위저드가 자동으로 만들어 준다는 사실에 조금 힘이 빠질지도 모르겠다. 태스크 스위칭 후 표면을 잃게 되면 CD3DApplication:: Reset3DEnvironment()를 호출하는데 Reset3DEnvironment()은 이제까지 거쳐 온 초기화와 같은 과정을 거쳐 화면을 복원시킨다. Render3DEnvironment()은 FPS 관련 정보를 보여주며 실제 렌더링하는 함수, Render()를 다시 호출하고 자신은 Present()만 수행한다. 중요한 것은 타이머를 이용해 FPS를 재면서 여기에 맞춰 렌더링을 할 것인지를 결정한다는 것이다. CMyD3DApplication:: Render()는 상당히 단순한데 Clear()로 화면을 지우고 Begin Scene()과 EndScene()의 일련 과정밖에 없다. 하지만 이 속에 //TODO: 라는 상당히 친숙한 주석을 만나게 될 것이다.
그럼 자신이 만들 정점 위치는 어디에 추가할까? MyD3DAppli cation::InitDeviceObjects()를 살펴보면 정점 위치를 선언한 곳이 있을 것이다. 이곳에 이제까지 공부한 것으로 정점을 바꿔보자.
방향키를 눌러보면 물체가 움직이는데 이는 방금 만든 3D 정점만 움직이는 것이 아닌 D3DXMatrix RotationX()로 월드 행렬 자체를 움직이는 것이다. 빛이나 정점 등 특정 객체만 움직이게 하려면 개발자 스스로 정점을 이동시켜야 한다. 참고로 게임이 아닌 행렬변환이므로 프레임워크에서 기본 키 입력은 다이렉트인풋이 아닌 GetAsyncKeyState()로 받고 있다.
이번 시간에는 조명과 텍스처를 배웠으며 손 코딩이 아닌 다이렉트3D 프레임워크로 이동해 보았다. 이제까지 익힌 것을 바탕으로 다음 시간에는 3D 형태의 맵을 만들고 X파일로 캐릭터를 올려 3D 게임의 실전 감각을 익혀보겠다.

집안으로 들어섰지만 내 방 어디에서 버티는 보이지 않았다. 정점, 메시, 조명, 재질, 텍스처, 그리고 이 모든 과정을 실은 T&L 파이프라인. 그동안 버티가 완성하고자 했던 것들이 완성되자 자신이 있던 곳으로 되돌아간 것일까? 버티가 보고 싶다. 어떻게 하면 좋을까?

정리 | 위윤희 | iwish@korea.cnet.com

[ 프레임워크의 타이머]

DXUtil.h에 포함된 DXUtil_Timer ()는 렌더링을 위해 사용되는 강력한 유틸리티 함수다. 예전에 다이렉트드로우를 공부할 때 timeGetTime()에 의해 화면 플리핑 시간을 제어하는 법을 배웠다. 다이렉트3D에서 역시 마찬가지로 timeGetTime()에 의한 정밀 시간을 계산해 렌더링 여부를 판단하며 플리핑을 수행한다. 프레임워크에서 자주 만나게 될 타이머 함수는 다음과 같은 플래그로 사용하게 된다.

TIMER_RESET : 타이머를 재설정한다.
TIMER_START : 타이머를 시작시킨다.
TIMER_STOP : 정시시키거나 일시 멈춤으로 한다.
TIMER_ADVANCE : 0.1초 단위로 타이머를 진행한다.
TIMER_GETABSOLUTETIME : 시스템의 절대 시간을 얻는다.
TIMER_GETAPPTIME : 현재 시간을 얻는다.
TIMER_GETELAPSEDTIME : TIMER_GETELAPSEDTIME 호출이 있은 후로부터의 경과 시간을 얻는다.
"Game Programming" 카테고리의 다른 글
  • 3D로 이뤄진 게임 세계-2 (0)2005/09/12
  • 3D로 이뤄진 게임 세계-1 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-4 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-3 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-2 (0)2005/09/11
2005/09/12 00:49 2005/09/12 00:49
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/1506

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Game Programming2005/09/12 00:47

다이렉트3D 프레임워크를 이용하자-3

김익중 (rheastriker@chol.com)

이제 메시 위에 올라갈 2D 이미지를 로딩하고 텍스처로 덮어보자. 텍스처를 위한 인터페이스는 IDirect3DTexture8이지만 이번 예제에는 다이렉트3D 8.0부터 지원되는 D3DX 유틸리티 함수를 이용하겠다. 물론 유틸리티 함수를 분석하여 그 속에서 다이렉트드로우 서피스와 CreateTexture() 같은 함수를 찾는 것은 상당히 가치있는 일이다.
유틸리티 함수의 이름은 D3DXCreateTextureFromFile()으로 실제 인자는 간단하다. 텍스처를 생성할 디바이스(IDirect3DDevice9)와 로딩할 이미지의 파일 이름, IDirect3DTexture9의 포인터 주소를 적어준다. 생성된 텍스처를 적용시키려면 IDirect3DDevice9::Set Texture를 호출해준다.

LPDIRECT3DTEXTURE9 g_pTexture = NULL;
D3DXCreateTextureFromFile( pd3dDevice, “texture.jpg”, &g_pTexture );
.............
g_pd3dDevice->SetTexture( 0, g_pTexture );


조명과 텍스처를 함께 합친 예제는 D3D9_4.dsw이다. 계속되는 필자의 피곤함으로 연재 내내 예제가 조금 불친절한 편인데 소스를 직접 고쳐보며 조명, 재질, 텍스처의 사용법을 파악하기 바란다. 특히 텍스처는 조명과 재질의 영향을 직접 받는다. 소스 내에서 조명의 색상이나 재질의 반사를 변경하고 정점 위치와 카메라 위치를 변경해가며 색상, 재질, 텍스처의 변화를 살펴보자.



화면 3, 화면 4. D3D9_4dsw의 실행 결과에서 이제까지 설명한 모든 인자들을 바꾸어보자.


이것으로 다이렉트3D의 기초 요소들은 한번씩 훑어봤다. 여러 가지 한계로 독자들이 원하는 수준만큼 다뤘는지 스스로도 걱정스럽지만 기초 요소와 다이렉트3D가 어떤 것인지 알게 되었다면 필자는 무척 기쁠 것이다.

“죄송해요, 먼저 나가봐야 할 것 같아요.”
난 자리를 일어났다. 그랬다. 나에게 필요한 것은 뛰어난 개발 스킬도 아닌 명성도 아니었다. 지난 몇 달간 버티와 함께 다투며 시끄럽게 지난 시간이 소중했고 앞으로도 그럴 것이다.


다이렉트X 프레임워크
다이렉트X는 복잡한 사용법 때문에 보조 함수(SDK 프레임워크 파일에 있는 유틸리티 함수)들이 다양하게 등장했다. 사실 다이렉트X 개발진이 만들어 SDK와 함께 배포한 것인 만큼 보조 함수들도 정식 SDK라고 보는 것이 옳을 것이다. 이러한 보조 함수들의 파일명은 초기에 DXUtil이란 식의 이름이 붙었다가 다이렉트X 8.0부터 많은 변화가 생겼다. 직접 프로젝트에 포함시켜 사용하는 방법이 아닌(물론 기존 방법도 가능하다) 애플리케이션 위저드가 이것을 자동으로 포함시켜주는 것이다. 따라서 이제까지 빈 프로젝트를 만들어 소스 코드를 채워왔다면 이제는 MFC처럼 기본 코드를 비주얼 스튜디오가 직접 만들어 주며 여기에 다양한 보조 함수가 포함되는 것이다. 보조 함수 사용이 부끄러워 할 필요가 없는 것이 위저드가 만들어 준 기본 코드 역시 보조 함수를 사용하고 있기 때문이다.


화면 5. 다이렉트X의 위저드 화면


이는 마치 기존의 API로 프로그래밍을 하다가 MFC로 돌입하는 경우와 같은데 상당한 양을 차지하는 기본 코드를 위저드가 만들어 주는 것은 기쁜 일이다. 하지만 다이렉트X의 기본 API와 동작 방법을 모르고서는 이 기본 코드를 제대로 사용하는 것은 힘든 일이며 처음부터 기본 코드를 보는 공부하는 것도 좋지 못한 것 같다.
사실 이 기본 코드에 관해서도 개발자들 사이에 논쟁이 많은 편인데 전통적인 다이렉트X 코딩을 따라온 수많은 개발자들이 위저드가 생성해 준 코드가 아닌 자신만의 프레임워크를 만들어 사용하고 있다. 필자 역시 예외는 아니었지만 얼마 전부터 생각을 바꾸었다. 비록 자신만의 프레임워크가 아니라도 추후 발전될 다이렉트X와 소스의 통일성을 쫓는 편이 더 낫다는 판단에서다. 지금 시간에까지 윈도우 프로그래밍을 하며 MFC를 배재한 채 자신만의 프레임워크와 API를 사용하는 개발자는 없지 않은가. MFC로 처음 등장했을 때에도 위저드를 부정하며 곱지 않은 시선으로 보는 개발자들이 있었지만 MFC는 분명 사실상의 표준이 되었다. 다이렉트X 위저드 코드와 프레임워크 역시 앞으로의 시간이 지나면 다이렉트X 프로그래밍의 표준이 되리라 믿는다.

[ 동경 게임쇼 2003 ]

지난 9월 말, 필자는 동경 게임쇼 2003에 참관하기 위해 일본을 다녀왔다. 게이머를 위한 세계 최대의 잔치답게 너무나 볼거리가 많았던 동경 게임쇼 2003(TGS 2003)은 게임의 성지라 불리는 일본 게임 제작사들의 개발 저력을 다시금 느끼게 하는 장소였다. 예상대로 콘솔 기기의 네트워크화와 모바일 게임의 성장이 가장 큰 이슈였는데 지하철부터 시작된 관련 광고는 다름 아닌 ATI의 라데온 칩셋과 국내 게임인 리니지 2였다. 특히 ATI는 다이렉트X 9에 접어들면서 PC와 콘솔 기기와의 관계를 모호하게 만들며 PC 개발자의 관심을 얻으려 노력하는 모습이었다.

아직 게임 시장에서 강력한 플랫폼으로 부상하지는 못하지만 휴대폰을 이용한 모바일 게임도 3D로 발전하고 있었다. 특히 기존 120KB 정도의 VM이 아닌 256KB까지 지원하는 SD 카드가 가장 인상적이었는데 VM의 한계를 하드웨어 저장 매체로 극복하는 것이 느껴졌다. 콘솔의 온라인화는 여전히 뜨거운 화두였다. 특히 스퀘어 에닉스의 Play OnLine 전략은 파이널 판타지 11과 함께 지난 시간동안 볼 수 없었던 대대적인 홍보를 하며 콘솔기기, PC, 그리고 휴대폰을 연결하는 현실적인 유비쿼터스를 강조하고 있었다. 비단 게임뿐만 아니라 게임 캐릭터와 무선 인터넷을 이용한 실시간 커뮤니티 서비스는 무척 흥미로왔다. PS2 네트워크는 ‘네트워크가 된다’는 초기 모습을 벗어나 다양한 네트워크 컨텐츠를 선보여 게이머를 즐겁게 하였으나 X박스는 여전히 컨텐츠보다는 최강의 하드웨어라는 ‘철지난’ 홍보만 되풀이해 조금 씁쓸한 광경을 연출했다.

개발자로써 TGS 2003를 둘려본다면 역시 그란투리스모 4의 실시간 렌더링과 소니의 아이 토이(Eye Toy)가 가장 강렬한 기억으로 남는다. 아이 토이는 PS2용 웹캠으로써 재치 넘치는 데모 프로그램과 함께 전시되었다. 화면 속에는 막대 위에 놓인 접시가 있고 게이머는 카메라를 통해 화면에 비치게 된다. 게이머가 화면 속 접시를 돌리는 동작을 취하면 정말로 접시가 돌아갔다. 접시 이외에도 메뉴라든가 기존의 버튼으로 했던 동작들을 카메라에 비친 게이머의 손동작으로 인터랙티브하게 작용하는 모습은 감탄을 불러 일으켰으며 컨텐츠의 저력을 알고 있는 콘솔 기기 다운 데모 프로그램이었다.
"Game Programming" 카테고리의 다른 글
  • 3D로 이뤄진 게임 세계-1 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-4 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-3 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-2 (0)2005/09/11
  • 다이렉트3D 프레임워크를 이용하자-1 (0)2005/09/11
2005/09/12 00:47 2005/09/12 00:47
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/1505

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Game Programming2005/09/11 18:16

다이렉트3D 프레임워크를 이용하자-2

김익중 (rheastriker@chol.com)

조명 설정에 관련된 구조체를 배웠으니 해당 메쏘드로 실제 조명을 만들어보자. 먼저 조명을 설정하기 전에 습관적으로 현재 조명을 몇 개까지 사용할 수 있는지를 검사해보는 것이 좋다.

D3DCAPS9 Caps;
pd3dDevice->GetDeviceCaps(&Caps);
// nMaxLight에 최대 조명 가능수가 들어가며 이 개수를 초과해서는 안된다.
DWORD nMaxLight = Caps.MaxActiveLights;


IDirect3DDevice9::GetDeviceCaps()는 조명뿐만 아니라 텍스처나 다른 자원들의 여유를 잴 수 있는 유용한 메쏘드이므로 조명 이외에도 실험해보기 바란다. IDirect3DDevice9::SetRenderState()는 지난 시간의 Z버퍼에 이어 조명 설정에도 사용되는 초만능 메쏘드이다. 첫 번째 인자값에 따라 무척 많은 기능들을 수행하는데 먼저 조명을 사용하겠다는 선언부터 해줘야 한다. D3DRS_LIGHTING를 넣어줘 조명을 사용하겠다고 알린다.

m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );


물론 조명보다 먼저 재질을 정의해줘야 한다. 재질이 어떤 색을 반사할 수 있느냐는 말은 결국 재질의 색상을 의미하므로 너무 복잡하게는 생각하지 말자.

D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f;
mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
g_pd3dDevice->SetMaterial( &mtrl );

재질은 직접 조명과 환경 조명이 모든 색을 반사할 수 있도록 R, G, B 모두 1.0f로 주었으며 IDirect3DDevice9::SetMaterial()로 재질 설정을 마쳤다. 다음은 실제 조명이다.

D3DLIGHT9 d3dLight;
ZeroMemory(&d3dLight, sizeof(D3DLIGHT9));
d3dLight.Type = D3DLIGHT_POINT;
d3dLight.Diffuse.r = 1.0f;
d3dLight.Diffuse.g = 1.0f;
d3dLight.Diffuse.b = 1.0f;

d3dLight.Position.x = 0.0f;
d3dLight.Position.y = 5.0f;
d3dLight.Position.z = 120.0f;
d3dLight.Attenuation0 = 1.0f;
d3dLight.Range = 1000.0f;

g_pd3dDevice->SetLight( 0, &d3dLight );


점조명이며 색상은 흰색이다. d3dLight에 설정된 조명 정보는 IDirect3DDevice9::SetLight()를 통해 0번 조명 인덱스에 설정되었다. IDirect3DDevice9::SetLight()는 이렇듯 D3DLIGHT9 구조체를 인덱스로 관리하며 다양한 조명을 관리해 준다. 여기까지는 조명을 만들었으니 IDirect3DDevice9::LightEnable()로 0번 조명을 켜주자. 이제 조명을 만들고 On/Off하는 법을 배웠다.
마지막으로 환경 조명을 함께 다뤄보겠다. 앞서 말한 대로 환경 조명은 결국 3D 세계 내에서 최소 조명을 위해서이며 따라서 주로 검은색이나 회색으로 설정한다.

g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00bfbfbf );


환경 조명 역시 IDirect3DDevice9::SetRenderState()로 설정하며 첫 번째 인자를 D3DRS_AMBIENT로 넣어주며 두 번째 인자로 환경 조명의 색, 다시 말해 3D 세계의 최소 조명 색상을 넣어준다. 직접 조명을 껐을 경우에도 환경 조명은 여전히 작동하고 있는 것을 확인해보기 바란다. 이로써 짧지만 조명에 대한 것은 마친다. 사실 조명은 3D에서 더 아름다운 세계를 구축하기 위해 대단히 중요하게 사용되는 요소이다. 하나의 조명이 첨가될 때 계산량은 엄청나게 늘어난다. 최소한의 조명으로 자신이 원하는 분위기를 만드는 것은 기술과 함께 어느 정도의 예술 감각까지 함께 필요한 것 같다.

버티가 가르쳐준 조명에 관해 잠시 생각해보았다.
“무슨 생각을 그리 하세요?”
“아무것도 아녀요, 잠시 좀...”
버티 녀석, 집을 잘 지키고 있을까? 내가 걱정하고 있는 것은 사실 집이 아니라 나갈 때 잔뜩 성을 내던 버티의 표정이었다.


<화면 1> 이런 멋진 게임 화면도



<화면 2> 텍스처를 벗겨내면 이런 모습이 된다.



<그림 3> 텍셀과 UV 좌표계


다이렉트3D 텍스처링
당구공 정도가 아닌 복잡한 물체들을 표현하기 위해 단지 색으로만 표현할 수 없을 것이다. 실제 게임에서도 텍스처의 중요성은 상상을 넘는데 정점의 부족함과 거기에서 나타나는 어색함을 텍스처로 극복하기 때문이다. 텍스처에 흔히 등장하는 대리석을 생각해보자. 정점만으로 대리석을 표현한다면 도대체 얼마나 많은 정점이 필요하겠는가? 또한 엠보싱 화장지와 같은 면을 만들고자 한다면 작은 반구를 얼마나 생성시켜야 하겠는가? 대리석의 경우, 단순한 면에다가 2차원의 대리석 그림을 입힌다면 쉽게 해결될 것이다. 사각형 상자에 대리석 무늬의 포장지를 씌우듯이 말이다. 엠보싱 화장지라면 텍스처는 범프 맵핑(bump mapping)을 이용하여 2차원의 반구 형태 이미지를 마치 튀어나온 것처럼 표시할 수 있다.
이외에도 텍스처는 평범한 폴리곤 덩어리를 실제 같은 무언가로 바꿔주는데 수많은 트릭과 기능들을 갖추고 있다. 이번 시간에는 실제 범프 맵, 멀티 텍스처, 환경, 볼륨 같은 고급 텍스처 대신 기초만을 다루겠지만 텍스처는 완벽한 3D 환경을 만들기 위해 필수적인 것임을 잊지 말고 텍스처와 관련된 공부를 멈추지 말기 바란다.

텍스처를 위한 UV 좌표계
텍스처 역시 정점의 준비부터 시작한다. FVF에 새롭게 D3DFVF _TEX1를 첨가하자. 이것은 정점에 텍스처 좌표계를 적용하며 만들어진 메시에 텍스처를 입힐 수 있다는 의미이다. 새롭게 텍셀(texture element)라는 단어가 나온다. 텍셀은 픽셀처럼 좌표를 의미하는 것으로 3D 메시의 좌표계이다. 텍스처 좌표는 어떤 텍셀이 해당 정점에 놓여져야 하는지를 Direct3D에게 알려준다. 텍셀에서는 X, Y가 아닌 U, V를 사용하는데 진행 방향은 X, Y와 같다. 그러나 픽셀과는 달리 실제 화면에 찍힐 도트의 수는 아니다. 3D 정점은 카메라를 비롯한 여러 요소들에 의해 변형된다. 따라서 텍셀은 상대적인 위치이지 절대적인 위치는 아님을 기억하라. 참고로 정점 거리, 텍스처의 크기, 카메라 방향을 이용하여 다이렉트3D를 이용한 2D 프로그램을 만들 수 있다(이것을 빌보드라고 한다).

#define D3DFVF_MYVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
typedef struct MYVERTEX
{ // FVF 추가
D3DXVECTOR3 vecPos; // XYZ를 하나로 D3DFVF_NORMAL
D3DXVECTOR3 vecNorm; // 노말
float u; // 텍스처를 위한 U, V 좌표계
float v;
} MYVERTEX, *LPMYVERTEX;
MYVERTEX g_Vertices[4];
정점의 위치 설정과 함께 각각의 정점에 해당 텍셀을 대입시키자.

float fSizeX = 5.0f;
float fSizeY = 5.0f;

g_Vertices[0].vecPos = D3DXVECTOR3(-fSizeX/2,fSizeY/2,0.0f);
g_Vertices[0].u = 0.0f;
g_Vertices[0].v = -1.0f;
// 노말(법선 방향)이 카메라를 향하도록 한다.
g_Vertices[0].vecNorm = D3DXVECTOR3(0.0f,0.0f,1.0f);

g_Vertices[1].vecPos = D3DXVECTOR3(-fSizeX/2,-fSizeY/2,0.0f);
g_Vertices[1].u = 0.0f;
g_Vertices[1].v = 0.0f;
g_Vertices[1].vecNorm = D3DXVECTOR3(0.0f,0.0f,1.0f);

g_Vertices[2].vecPos = D3DXVECTOR3(fSizeX/2,fSizeY/2,0.0f);
g_Vertices[2].u = -1.0f;
g_Vertices[2].v = -1.0f;
g_Vertices[2].vecNorm = D3DXVECTOR3(0.0f,0.0f,1.0f);

g_Vertices[3].vecPos = D3DXVECTOR3(fSizeX/2,-fSizeY/2,0.0f);
g_Vertices[3].u = -1.0f;
g_Vertices[3].v = 0.0f;
g_Vertices[3].vecNorm = D3DXVECTOR3(0.0f,0.0f,1.0f);
"Game Programming" 카테고리의 다른 글
  • 다이렉트3D 프레임워크를 이용하자-4 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-3 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-2 (0)2005/09/11
  • 다이렉트3D 프레임워크를 이용하자-1 (0)2005/09/11
  • 3D 엔진 제작의 실제-1 (0)2005/09/11
2005/09/11 18:16 2005/09/11 18:16
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/1504

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Game Programming2005/09/11 18:13

다이렉트3D 프레임워크를 이용하자-1

T&L이라는 3D 파이프라인을 탔었다. 이제 여기에 컬러와 텍스처를 입혀보자. 컬러와 텍스처 정보 역시 정점들이 관리하게 된다. 여기까지 배웠다면 다이렉트3D의 기초 요소들은 다 훑어 본 셈이다. 기초들을 살펴봤으면 다이렉트3D의 프레임워크를 이용해 좀더 세련된 개발 환경으로 옮겨가 보자.


김익중 | rheastriker@chol.com
현실과 이상은 다르며 어차피 세상은 쓰레기 더미이다. 하지만 아직 젊은 이유는 이 쓰레기 속을 헤치며 현실을 이상으로 만들기 위해서라고 믿고 있다. 요즘은 홈페이지에 올린 일본 동경 게임쇼 배낭여행기가 많은 사람들에게 호응을 얻어 기뻤다고.

“멋져요, 그럼 T&L 가속까지 구사하시네요.”
“아, 네..”
오픈지엘과의 만남은 지금까지 내 일생에서 최대의 이벤트였고 너무나 기쁜 순간이었다. 매일같이 버티의 치닥거리에 시달린 내게 이런 정상적인 만남은 오랜만이었다. 카페 창밖에서 들어오고 있는 달빛과 화려한 상젤리아, 그리고 테이블에 놓여진 촛불. 눈 주위를 감싼 지엘의 엷은 화장은 조명 아래에서 더욱 아름다웠다. 그러고 보니 버티 녀석이 자기도 가끔 화장도 한다고 그랬지? 그러면서 조명발(?)에 속지 말라고 한 적도 있었는데…. 그때 뭐라고 그랬더라?

다이렉트3D 라이팅
지난 시간까지 점과 표면, 카메라에 대해 살펴봤다. 마지막 요소로 조명(light)을 다뤄보겠다. 실제 다이렉트3D는 셰이더(shader)를 통해 개발자가 직접 정의해 사용할 수 있는 더 나은 조명으로 많은 발전을 이룬 것이 사실이다. 안타깝게도 다이렉트3D의 기본 조명이 실제 물리적인 조명과 일치하는 정확한 조명은 아니지만(만약 그랬다면 3D 개발자의 입지가 좁아졌을지도 모른다) 무척 그럴싸한 것은 사실이며 많은 3D 프로그램에 제 역할을 톡톡히 해낸다.
우선 다이렉트3D의 조명은 두 가지로 구분된다. 첫째 환경 조명(ambient light)이다. 참고로 다이렉트3D를 공부하면서 환경이란 단어에 주의하기 바란다. 불행히도 ambient와 environment 모두 다이렉트3D에서 사용되며 ‘환경’이란 단어로 번역된다. 헛갈리기 쉬운데 조명에서 환경이란 말을 만나면 ambient이며 매핑에서 만난다면 environment라고 재해석하길 바란다(자료에 따라 ambient를 주변으로 해석하는 경우도 있다). 다시 환경 조명으로 돌아오면 환경 조명이란 3D 공간 전역에 걸친 조명으로 직접 물체에 투사되는 것은 아니지만 모든 것들에게 최소한의 조명을 해주는 것과 같다. 실제 환경 조명이 극적으로 사용되는 경우는 찾아보기 힘들며 3D 공간 내에서 최소한의 조명을 설정해주기 위해 회색으로 사용되는 경우가 많다.
두 번째 직접 조명은 특별한 위치나 방향을 가진 조명을 만들 때 사용된다. 직접 조명(이제부터 특별한 언급없이 조명이라고 적는다면 직접 조명을 의미한다)에서는 조명 이외에 재질(material)이란 요소가 추가된다. 흔히 ‘조명발에 속지말라’는 말을 하는데 이는 다이렉트3D의 세계에서도 마찬가지다.
조명은 조명 혼자 사용되는 것이 아니기 때문이다. 조명은 표면을 비추게 된다. 우리가 보게 되는 조명이란 빛 그 자체가 아닌 표면의 색과 이 표면으로부터 반사되는 조명을 보는 것이다. 따라서 다이렉트3D에도 조명과 함께 표면에 조명이 어떻게 비춰질 것인지 재질을 설정하게 된다.
조명을 위해서는 조명의 속성을 구성하는 D3DLIGHT9 구조체가 사용된다. 조명 구조체는 다이렉트3D 7.0부터 발전해온 것으로 의외로 손쉽게 조명을 첨가할 수 있게 해준다. 함께 언급한 재질을 위해서는 D3DMATERIAL9 구조체가 사용된다.

D3DLIGHT9 구조체
typedef struct _D3DLIGHT9 {
D3DLIGHTTYPE Type;
D3DCOLORVALUE Diffuse;
D3DCOLORVALUE Specular;
D3DCOLORVALUE Ambient;
D3DVECTOR Position;
D3DVECTOR Direction;
float Range;
float Falloff;
float Attenuation0;
float Attenuation1;
float Attenuation2;
float Theta;
float Phi;
} D3DLIGHT9;



그림1. 점광원



그림2. 스포트라이트


◆ D3DLIGHTTYPE Type : 조명 타입을 설정한다. 조명 타입은 점광원(Point Light Source), 스포라이트(Spot Light), 방향 광원(Directional Light Source)이 지원된다. 점광원이란 백열전구와 같이 모든 방향으로 동일하게 나가는 광원이며 방향 광원은 태양과 같이 무한히 멀리 있는 광원으로 사용된다. 스포트라이트는 말 그대로 원점의 위치와 특정 방향과 각도를 지정할 수 있는 광원이다.
◆ D3DCOLORVALUE Diffuse : 조명에 의해 발산되는 색. 바로 조명의 색상이다. RGB 값을 사용하지만 RGB 매크로가 아닌 D3DCOLORVALUE 구조체임에 주의하라. 따라서 각 색상은 0부터 1.0까지 범위를 가지며 빨간색이라면 (1.0, 0.0, 0.0)이다. 만약 매우 밝은 색이 필요하다면 1.0보다 더 큰 값을 설정할 수 있다.
◆ D3DCOLORVALUE Specular : 조명에 의해 방사되는 반사색
◆ D3DCOLORVALUE Ambient : 조명에 의해 방사되는 환경색
◆ D3DVECTOR Position : 월드 공간에서 조명의 위치. 방향 광원이라면 무시된다.
◆ D3DVECTOR Direction : 조명의 방향. 방향 광원과 스포트라이트에게만 유효하다.
◆ float Range : 조명이 효과를 가지는 거리. 최대값은 D3DLIGHT_RANGE_MAX이며 방향 조명에는 영향을 주지 않는다.
◆ float Falloff : 스포트라이트 설정시 dvTheta 각과 dvPhi 사이에서의 조도 감소를 의미한다. 하지만 조도 감소의 효과는 별달리 신경 쓰이지 않기 때문에 1.0으로 설정한다.
◆ float Attenuation0~2 : 조명 강도가 거리에 따라 변하는 정도. 유효범위는 0부터 무한으로 방향조명에는 영향을 주지 않는다.
◆ float Theta : <그림 2>를 참조하라. 스포트라이트의 내부 원뿔이며 이 각도는 라디안이다.
◆ float Phi : Theta에서 점차 엷어지는 외부 모서리. 이 값은 0과 pi 사이에 있어야 하며 이 값을 넘은 면은 조명되지 않는다.


D3DMATERIAL9 구조체
typedef struct _D3DMATERIAL9 {
D3DCOLORVALUE Diffuse;
D3DCOLORVALUE Ambient;
D3DCOLORVALUE Specular;
D3DCOLORVALUE Emissive;
float Power;
} D3DMATERIAL9;


◆ D3DCOLORVALUE Diffuse : 재질이 조명을 어떻게 반사할 것인지를 결정한다. 재질을 빨간색, 즉 (1.0, 0.0, 0.0)으로 설정했다면 빨간색과 흰색만을 반사한다. 만약 조명의 색상이 녹색이라면 빨간색의 재질은 검은색으로 나타난다.
◆ D3DCOLORVALUE Ambient : 디퓨즈와 같으나 환경 조명만을 반사한다. 환경 조명 반사를 설정할 시에는 반드시 Ambient 값을 채워주자. 재질에서 디퓨즈 값은 환경 조명이 아닌 직접 조명에만 영향을 끼친다는 점을 잊지말자.
◆ D3DCOLORVALUE Specular : 재질의 하이라이트를 나타낸다. 스펙큘라 값이 없다면 스포트라이트의 조명도 하이라이트를 만들지 못한다.
◆ D3DCOLORVALUE Emissive : 이 값을 설정하면 재질이 빛을 발산하는 것처럼 보일 수 있다. 물론 다른 물체가 에머시브로 인해 조명을 받는 것은 아니지만 에머시브(emissive)가 적용된 물체는 빛을 내는 것처럼 보여진다.
"Game Programming" 카테고리의 다른 글
  • 다이렉트3D 프레임워크를 이용하자-3 (0)2005/09/12
  • 다이렉트3D 프레임워크를 이용하자-2 (0)2005/09/11
  • 다이렉트3D 프레임워크를 이용하자-1 (0)2005/09/11
  • 3D 엔진 제작의 실제-1 (0)2005/09/11
  • 3D 세계를 구성하는 필수 요소들-4 (0)2005/09/11
2005/09/11 18:13 2005/09/11 18:13
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/1503

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Game Programming2005/09/11 18:04

3D 엔진 제작의 실제-1

장언일 (uijang@ccr.co.kr)

처음 시작하는 독자라면 간단하고 보기 쉬운 것부터 직접 구현해 보는 것이 중요하다. 필요에 따라 다른 사람이 이미 구현한 소스가 상당한 도움이 되기도 한다. 복잡한 구조의 C++나 템플릿을 마구 남용해서 짜나가는 것보다 간단한 구조부터 복잡한 구조로 잘 짜여진 소스를 보는 것은 프로그래밍 습관에 많은 영향을 미치기 때문이다.


필자가 많은 사람들에게 질문을 받는 것 중 하나가 ‘어떻게 3D를 공부하는가’이다. 3D 학습법은 특별히 정형화된 순서를 가지고 있지 않기 때문에 이것저것 가리지 말고 공부해야 하며 처음부터 난이도 높은 것에 많은 시간을 보내지 말아야 한다. 또한 3D 용어부터 친숙해져야 하며 그러한 용어들이 무엇을 뜻하는지에 대해 계속 지식을 쌓아 나가야 한다. 처음 프로그래밍할 때 ASE 뷰어기(3DS-MAX의 SCENE이 텍스트로 출력된 파일이다)를 만들어 볼 것을 권한다. ASE 뷰어기의 자료는 인터넷이나 3D 관련 책자에 많이 있으니 참고하면 된다. 이것을 만들어 보면 3D에서 자료구조를 어떻게 잡아야 할 것인지에 대해 도움을 받을 것이다.

3D 학습 방법
필자가 3D를 처음 접하던 시절에는 그 흔한 텍스처 맵핑을 구현하는 서적조차 구하기가 어려웠을 정도로 자료가 거의 없었다. 그나마 PC 통신을 통해 해외 FTP에서 자료를 구하면 어셈블리로 구현된 소스(어셈블리를 하는 독자라면 잘 알다시피 분석하는 데에 있어서 상당히 난해하다)를 며칠씩 분석했던 걸로 기억한다. 물론 덕분에 어떻게 하면 텍스처 맵핑을 빨리 하는가에 대해서는 내공을 쌓을 수 있었다.

일단 구현해 봐라?
처음 시작하는 독자라면 간단하고 보기 쉬운 것부터 직접 구현해 보는 것이 중요하다. 필요에 따라 다른 사람이 이미 구현한 소스가 상당한 도움이 되기도 한다. 복잡한 구조의 C++나 템플릿을 마구 남용해서 짜나가는 것보다 간단한 구조부터 복잡한 구조로 잘 짜여진 소스를 보는 것은 프로그래밍 습관에 많은 영향을 미치기 때문이다. 어느 정도 구현 능력이 생기면 구현보다는 문제에 봉착했을 때 어떤 방법으로 해결할 것인가가 매우 중요하다는 것을 깨닫게 될 것이다. 때로는 원하는 알고리즘을 위해 몇백 몇천 라인의 소스를 뒤져서 알아내는 것도 도움이 된다. 존 카멕이 공개한 퀘이크 I 소스 분석은 최고 난이도가 아닐까 싶다.

전체 이론을 파악하라
다른 사람의 소스를 분석하고 자기 것으로 만들어서 구현하는 능력이 생기면 ‘어떻게 만들어야 하는가’에 대한 이론을 신경써야 한다. 물론 하나를 얻기 위해 많은 소스를 본다는 것은 많은 인내심과 노력이 필요하다. 하물며 필자는 누군가 한 마디를 해주면 해결될 일을 며칠씩 고생해서 알아내는 경우도 많았다. 이런 경우 수단과 방법을 가리지 말고 사방에 도움을 요청해 보자.

모르는 것에 대해 두려워 말라
만약 여러분이 상용 게임 엔진 제작자와 만나는 일이 생긴다면 게임 엔진에 관해 이야기하고 싶은 것이 무척 많을 것이다. 그러나 필자 경험상 공부하는 학생들을 만나보면 주눅이 들어서인지, 모른다는 것에 대해 자존심이 상한 것인지 막상 질문하는 경우가 흔치 않다. 배움의 입장에서 자존심을 세우거나 낯가림을 하는 것은 매우 어리석은 일임을 기억해야 한다.
예전에 필자는 DEMO GROUP에서 유명했던 Jmagic이라는 사람에게 잘 쓰지도 못하는 영어로 “당신이 사용한 모션블로 알고리즘을 다오!”라고 영문 메일을 보내서 친절하게 답변을 받았던 적이 있었다. 이처럼 대부분 실력 있는 사람은 지식 공유에 관해 상당히 관대하기 때문에 주저없이 물어보길 바란다(그렇다고 존 카멕에게 BSP 알고리즘을 가르쳐 달라는 것은 무식한 행동일 듯 싶다). 어찌됐건 가끔 그렇게 물어봤던 것들이 그 당시 필자에겐 많은 도움이 됐다.

C++, OOP로 엔진 설계
엔진을 처음 만드는 사람에게는 C++를 함부로 쓰지 말라고 이야기하고 싶다. 잘못된 구조로 프로그램을 계속 짜다보면 나중에는 원점부터 다시 시작해야 하는 상황이 생길 수 있기 때문이다. 물론 처음부터 아예 다시 짤 생각을 하는 고집센 C++ 프로그래머라면 시도해 봐도 무방하다. 하지만 가능하면 직관적인 구조를 지닌 C 스타일을 기반으로 필요한 부분에 C++를 넣어서 프로그램하길 바란다.
배경 엔진
배경 엔진은 가장 기본이 되는 부분으로 실제 눈에 보이는 부분에 대한 처리부터 충돌을 위한 정보와 AI를 구현하기 위한 패스를 얻을 수 있는 방법까지도 포함한다. 이러한 일련의 과정을 제대로 돌아가게 하기 위해서는 배경 엔진 구조가 매우 중요하다. 배경 구조는 엔진이 나아가야 할 방향이 결정되는 기반이라고 할 수 있다.
온라인 게임이든 다른 게임이든 넓은 월드에서 대략 어디에 위치해 있고, 어느 부분을 렌더링 걸어야 하며, 주변에 보이는 캐릭터나 동적인 물체들 또는 총에 의해 깨지는 드럼통을 관리하기 위해서는 월드 구역을 나눠서 관리해야 한다. 요즘은 3D 그래픽카드의 능력이 매우 우수하므로 구조 없이도 가능하지만 많은 제약들이 생길 것이다. 그러한 배경 구조 없이 MMORPG를 만들기 시작한 평범한(?) 프로그래머의 시각에서 본 가상 일기를 살펴보자.

배경 구조 없이 만들어 본 가상 일기
이번 프로젝트는 MMORPG를 만드는 것이다. 그래픽하는 사람들이 폴리곤을 어느 정도 써야 하는지를 물어보기에 여기저기 알아 본 결과 다음과 같은 1차 결론을 얻었다.

◆ 월드의 폴리곤 전체를 4∼5만 개로 만들어야 적당한 속도가 나지 않을까
◆ 최근 게임 추세는 캐릭터에 폴리곤을 많이 쓰던데 나중에 어떻게 될지 모르니까 1500개 정도가 어떨까


이와 같이 그래픽하는 사람들에게 이야기를 하고 나서 화면에 캐릭터를 뿌려보게 되었다. 기획자가 월드는 어느 정도 넓어야 게임이 된다고 해서 4∼5만 개로 월드를 크게 만들고 보니 눈앞에 보이는 배경 폴리곤의 각이 많아져서 시각적으로 부자연스러워 보였다. 이렇게 만들다 보면 배경에 그 흔한 풀조차 세우기가 힘들어질 것 같았다. 이런 상황에서 충돌 체크를 하기 위해 폴리곤 4∼5만 개를 모두 검색해 캐릭터가 서 있는 것을 계산하다 보니 캐릭터를 띄울수록 속도가 많이 떨어지는 것을 느꼈다. 일단 배경 폴리곤 숫자를 2만 개 정도로 줄이고 캐릭터는 1000개 안으로 줄이도록 그래픽 팀에 전했다. 게임 그래픽의 질이 현저히 떨어졌지만 그나마 실행 속도가 빨라진 것 같아 의지대로 작업을 계속 진행해 나갔다. 그러나 게임에 필요한 요소를 넣을수록 실행 속도가 떨어지는 데다 제한 조건이 너무 많아 팀 분위기도 쳐지고 어떻게 해야 할지 모르겠다.

이처럼 가상 일기는 다소 과장된 부분이 있지만 배경 구조는 필수 요소이며 구조 구성에 따라 전체 엔진 성능까지 좌우할 정도로 매우 중요하다. 그럼 배경 구조를 위해 어떤 구조가 있는지 알아보자.
"Game Programming" 카테고리의 다른 글
  • 다이렉트3D 프레임워크를 이용하자-2 (0)2005/09/11
  • 다이렉트3D 프레임워크를 이용하자-1 (0)2005/09/11
  • 3D 엔진 제작의 실제-1 (0)2005/09/11
  • 3D 세계를 구성하는 필수 요소들-4 (0)2005/09/11
  • 3D 세계를 구성하는 필수 요소들-3 (0)2005/09/11
2005/09/11 18:04 2005/09/11 18:04
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/1502

Leave your greetings.

[로그인][오픈아이디란?]

«Prev  1 2 3  Next»

RSS HanRSS
Blog Image
webdizen
이곳은 컴퓨터에 대해 연구하고, 공유하고, 소통하기 위한 연구실입니다. 개인적으로는 OLAP, Data Mining, Semantic Web, Data Modeling에 대해서 연구하고 있습니다.

Categories

전체 (3009)
Webdizen (141)
Life (6)
Diary (16)
Blog (9)
IDEA (2)
Travel (10)
Book (16)
Photo (7)
Movie (8)
Music (14)
Leisure Sports (10)
Funny (6)
Hardware (121)
Software (120)
Windows (5)
Unix & Linux (120)
Installation (5)
Kernel (10)
System (34)
Develop (22)
X-Window (0)
Applicaton (31)
Security (4)
Framework (2)
Hadoop (2)
Programming (804)
Algorithm & Data Structure (1)
Assembly (38)
UNIX/Linux C (95)
C++ (128)
STL (4)
Java (38)
Win32 API (92)
ATL/COM (44)
MFC (151)
.NET (26)
WCF/WPF (4)
C# (28)
Network Programming (17)
Database Programming (12)
OpenGL / DirectX (13)
Multimedia Programming (0)
Game Programming (21)
Parallel Distributed Progra... (0)
Reverse Engineering (0)
Debugging (9)
Python (1)
Ruby (1)
Ruby on Rails (1)
QT (4)
GTK (0)
JSP (0)
PHP (6)
ASP.NET (6)
ASP (2)
Development (28)
Useful Library (2)
Data Modeling (0)
Database (105)
Oracle (4)
MSSQL (41)
MySQL (2)
Data Warehouse (2)
Data Mining (4)
Network (66)
Web (79)
DHTML (4)
XHTML (1)
Javascript (1)
CSS (1)
AJAX (9)
XML (11)
Flex (1)
Silverlight (3)
Security (91)
DoS (1)
Kernel (10)
Scanning (3)
Sniffing (0)
Spoofing (4)
Overflow (28)
Web (11)
Shell (10)
Format String (14)
Window (2)
Embedded (70)
Multimedia (27)
Mobile (14)
Graphic (24)
Management (633)
Knowledge (581)
Hadoop (0)

Notice

  • 메타 블로그 사이트에 등록
  • 새해 맞이 블로그의 변화
  • 블로그 명칭 변경
  • 도메인(www.webdizen.net) 구...
  • TEXTCUBE 1.6.1로 업그레이드...

Tags

  • 크래킹
  • 가치관
  • 프로젝트
  • 분산 프로세스
  • Prado Framework
  • Message
  • Merge-Join
  • 서버 로그인
  • Qrobo
  • 프로세스 정보
  • 캐시 적종
  • 연쇄살인범
  • 사용자 로그인 정보
  • 객체 지향 모델링
  • tr
  • 인문대
  • 통합
  • VBScript
  • inotify
  • 가우디

Recent Articles

  • 트위터(Twitter)의 시작!.
  • 청년 리더의 조건.
  • 애플의 타블렛 PC - 아이패드....
  • 미래의 인터페이스 - 육감 기....
  • 기초발성법 동영상 강좌.

Recent Comments

  • 학교 과제물중 쓰레드에 대하....
    장진혁 03/17
  • 관리자만 볼 수 있는 댓글입....
    비밀방문자 03/12
  • 상대방의 이야기를 열심히 경....
    DoNuts 03/03
  • Lots of students know techn....
    Bobbi35Shannon 02/25
  • 좋은글 잘 보고 갑니다..
    Und_hacker 01/08

Recent Trackbacks

  • printf,scanf를 이용한 형식....
    yundream의 프로그래밍 이야기 03/10
  • 파일 열기/저장하기 CFileDialog.
    은마군의 나태블록 2009
  • World IT Show 2008.
    상우 :: Oranzie's BLOG 2008
  • cvs서버 설치하기.
    3인3색 2008
  • 속속 공개되는 Google Chart....
    PHP와 Web 2.0 2007

Archive

  • 2010/02 (1)
  • 2010/01 (6)
  • 2009/12 (5)
  • 2009/09 (3)
  • 2009/08 (1)

Calendar

«   2010/03   »
일 월 화 수 목 금 토
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Bookmarks

    • Administration
      • IIS.NET
      • NTFAQ
      • OS의 모든 것
      • 리눅스포털
    • Database
      • SQL Server Central
      • SQL Team
    • Development
      • .NET Heaven
      • ASP Alliance
      • ASP.NET 2.0
      • Bullog.net
      • C# Corner
      • C++ (C PlusPlus.com)
      • C++ Reference
      • CodeGuru
      • CodePlex
      • DebugLab
      • Dev Articles
      • Devpia
      • DotNet Junkies
      • DotNet Zone
      • Driver Online
      • GOSU.NET
      • HOONS 닷넷
      • Joinc 팀블로그
      • KOSR
      • MSDN Home Page
      • OSR Online
      • Sky.ph - 개발자 커뮤니...
      • TAEYO.NET
      • The Code Project
      • WindowsClient.net
      • 김상욱의 개발자 Side
      • 조인시 위키
    • Human Networks
      • belief21c's e-space
      • I think I can
      • Invisible Rover's Blog :D
      • Rodman®
      • ■ Feel So Good~! ■
      • 까만 나비
      • 나를 가꾸는 시간.
      • 나만의 즐거움~~!
      • 단녕
      • 상우 :: Oranzie's BLOG
    • Information Technology
      • Microsoft TechNet
      • 지디넷코리아 - 글로벌...
    • Security
      • FoundStone
      • milw0rm
      • NewOrder
      • OpenRCE
      • Phrack.org
      • Reverse Engineering b1...
      • Reverse Engineering Team
      • RootKit
      • SecurityFocus
      • SecurityXploded by Nag...
      • Wow Hacker
      • Zone-H
Textcube
Louice Studio Inc.
Powered by Textcube. Original designed by Tistory.