XNA for C#
DirectX 9 for C#
DirectX 9 for C++
DirectX 9 for VB
Forum
   
My XNA Book
      
       Go to section on this site

Additional info


Latest Forum posts

 Account settings
  Posted by: Anonymous
  When: 07/05/2014 at 09:48:39

 forced subtitle
  Posted by: Applefly
  When: 07/05/2014 at 06:00:48

 convert DVD into PMS
  Posted by: Applefly
  When: 07/05/2014 at 05:55:25

 DVD to Digital Copy easily
  Posted by: VIKIVannessa
  When: 05/05/2014 at 06:52:29

 DVD on Xbox 360/Xbox One Console
  Posted by: VIKIVannessa
  When: 05/05/2014 at 06:51:47

 Extract .Srt Subtitles
  Posted by: Applefly
  When: 04/05/2014 at 03:54:38

 Encode Movie collection
  Posted by: Applefly
  When: 04/05/2014 at 03:52:41

 Convert DVD to WMV
  Posted by: Applefly
  When: 29/04/2014 at 05:53:50

 rip DVDs into digital files
  Posted by: Applefly
  When: 29/04/2014 at 05:51:20

 iTunes movies/music to Kindle Fire
  Posted by: ciciyu80
  When: 29/04/2014 at 05:10:20


Ads

파일을 사용한 지형 생성

이번 tutorial에서는 넓은 지형(landscape)을 그려보겠습니다. 지금까지는 삼각형들의 좌표값을 일일히 지정하는 방법을 사용해 왔습니다만, 넓은 지형은 수백, 혹은 수천 개의 vertex들을 다루어야 하므로 그런 수동적인 방법으로 표현하기는 무리가 있습니다. 이제부터는 파일의 내용을 읽어오는 방법으로 vertex들의 좌표값을 다루도록 합시다.

이번 tutorial에서 그릴 지형은 64*64의 지형입니다. 4096개의 vertex가 필요하니 꽤 넓은 지형이 되겠네요. 이전 tutorial을 참고해보면 지형을 그리는데 있어서 x축, y축 좌표값은 항상 일정한 값을 유지하게 되고, 사실상 지형을 표현하는데 의미를 가지는 값은 z축 좌표값임을 알 수 있습니다. 64*64 지형의 z축 좌표값을 표현하기 위해 우리는 64*64크기의 grayscale 이미지 파일을 사용할 것입니다. 이런 종류의 이미지를 일반적으로 height map이라고 부르며 각 pixel의 ‘white value’가 바로 z축 좌표값을 의미합니다. ‘white value’는 검은색(=0=00)과 흰색(=255=ff)사이의 값입니다. 예를 들어 [5,5] pixel이 검은색이라면 색상값이 00이므로 [x=5,y=5] 위치의 vertex의 z축 좌표값은 0이됩니다. [10, 10] pixel이 흰색이라면 색상값이 255이므로 [x=10,y=10] 위치의 vertex의 z축 좌표값은 255가 됩니다. 이렇게 grayscale로 z축 좌표값(높이값)을 나타내는 이미지가 가장 기본적인 height map이며 실제로는 grayscale 이미지 외에도 다양한 방법으로 height map을 표현하고 있습니다.

우리가 grayscale 이미지를 직접 만드는 대신에 여기서는 Reimer씨가 만들어둔 example 이미지를 사용하도록 합시다. 물론 Reimer씨의 example 이미지 대신에 자신이 직접 64*64 크기의 이미지를 만들어 써도 좋습니다.



이제 새로운 Windows Game 프로젝트를 생성하고 필요한 파일들을 이전의 tutorial에서 복사해 옵시다.

이미지 파일을 읽기 위해 가장 먼저 할 일은 namespace 추가 입니다. 우리 모두 C#을 이미 알고 있으니 당연하게 느껴질 것 입니다.

 using System.IO;

그리고 우리는 64*64의 지형을 표현할 것이므로 기존의 두 전역 변수, WIDTH와 HEIGHT의 값을 변경해 줍시다.

 int WIDTH = 64;

이제 파일을 읽기 위해 기존의 LoadHeightData함수의 내용을 다음과 같이 수정합시다.

 private void LoadHeightData()
 {
     heightdata = new int[WIDTH, HEIGHT];
 
     FileStream fs = new FileStream("../../../XNA.raw", FileMode.Open, FileAccess.Read);
     BinaryReader br = new BinaryReader(fs);
 
     for (int y = 0; y < HEIGHT; y++)
     {
         for (int x = 0; x < WIDTH; x++)
         {
             int height = (int)(br.ReadByte() / 50);
             heightdata[x, HEIGHT - 1 - y] = height;
         }
     }
 
     br.Close();
 }

코드에서 보여지는 것과 같이 이미지 파일을 읽는 코드는 C#의 그것과 전혀 다른것이 없습니다. 두 번째 라인부터 raw 이미지 파일을 읽습니다. 이미지 파일의 format에는 여러 가지가 있습니다만 굳이 raw 이미지를 사용한 이유는 raw format은 header가 존재 하지 않고 순수하게 data로만 구성되어 있어서 파일 읽기가 매우 간편하기 때문입니다. 예를 들어 jpeg 이미지는 손실형 압축 이미지 이므로 디코딩이 필요하며 pixel의 색상값도 디코딩 할 때마다 약간씩 오차가 있을 수 있으므로 height map 표현에 잘 쓰이지 않는 이미지 format 입니다. 다만 raw 이미지의 경우 지형의 크기에 비례해서 파일의 크기도 증가한다는 단점이 있습니다. 다시 코드로 돌아와서, 4번째 라인은 raw 이미지를 byte형식으로 읽기 위한 binary reader를 생성하는 코드입니다. 그리고 총 64*64번, 4096번 data(=byte)를 읽어와서 배열의 해당 위치에 값을 지정합니다. 이때 읽어온 byte를 50으로 나누어 주는 이유는 현재 raw 이미지 data를 그대로 사용하게 되면 최대값과 최소값 사이의 차이 너무 크기 때문입니다. 최소값은 0이고 최대값은 255인데 이 data를 그대로 z축 좌표값으로 사용한다면 미관상 보기 안 좋겠지요. 게다가 이렇게 너무 급격한 경사를 가져서야 지형이라고 부르기도 힘들 것 입니다. 50으로 나누어주면 z축 좌표값은 최소 0부터 최대 5까지의 값을 가지므로 꽤 보기 좋은 지형이 나올 것 같습니다.
다음으로 유의해야 할 점은 배열에 data를 채우는 순서입니다. raw 이미지의 data는 뒤집혀서(inversely) 저장되어 있습니다. 그러므로 배열에 data를 저장할 때는 파일은 위에서 아래로(top→bottom)으로 읽어서 배열의 아래부터 위로(bottom→top)으로 저장해야 합니다. (heightdata[x, HEIGHT - 1 - y])

이제 지형을 그릴 준비는 모두 끝난 셈이지만 이대로 실행하면 지형의 위치와 카메라의 위치 때문에 전체 지형이 보이지 않습니다. 먼저, 지형의 위치를 정중앙으로 옮겨보겠습니다. 지형의 정중앙이 좌표계의 원점(0.0f, 0.0f, 0.0f)이 되도록 변환된 월드 좌표계를 생성해야 합니다. Draw함수의 월드 좌표계 생성 코드를 다음과 같이 변형합시다.

 Matrix worldMatrix = Matrix.CreateTranslation(-HEIGHT / 2, -WIDTH / 2, 0);

지형이 이제 화면 중앙에 위치하게 되었으니 카메라의 위치를 옮겨 봅시다. SetupCamera함수의 view matrix와 projection matrix 생성 함수를 다음과 같이 수정합시다.

 Matrix viewMatrix = Matrix.CreateLookAt(new Vector3(0.0f, -40.0f, 60.0f), new Vector3(0.0f, -5.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
 Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Window.ClientBounds.Width / Window.ClientBounds.Height, 1.0f, 150.0f);

카메라의 위치를 뒤로 옮겨서 더 넒은 공간을 바라볼 수 있게 했습니다. 여기서 한가지 유의할 점은 시야각이 넓어진 만큼 projection matrix의 시야 거리 또한 증가시켜서 더 멀리까지 볼 수 있게 해주어야 한다는 점 입니다. 기존의 시야 거리는 50.0f 였는데, 지금은 카메라와 좌표계 원점과의 거리가 40.0f 이므로 그대로 두면 카메라와 50.0f 이상의 거리를 가지는 가장자리 부분은 화면에 보이지 않게 됩니다. 시야 거리를 150.0f 정도로 충분히 늘려줍시다. Matrix.CreatePerspectiveFieldOfView함수의 마지막 parameter가 시야 거리 입니다. 자세한 내용은 MSDN을 참조하길 바랍니다.

이제 디버그(F5)키를 눌러 실행시키면 우리가 만든 64*64의 지형을 확인할 수 있습니다. Example로 제공된 XNA.raw 이미지와 우리가 만든 지형의 모습을 비교해보고, 그 외에도 다른 grayscale 이미지를 적용하여 그 결과를 직접 확인해 보길 바랍니다.






Google
 
Webwww.riemers.net


If you appreciate the amount of time I spend creating and updating
these pages, feel free to donate -- any amount is welcome !



- Website design & XNA + DirectX code : Riemer Grootjans -
©2003 - 2011 Riemer Grootjans
Translations

This site in English
This site in Korean
This site in Czech

Microsoft MVP Award



2007 - 2011 MVP Award
DirectX - XNA

Contents

[Tutorials]
[XNA in C#]
Series 1: 지형
XNA의 시작
이펙트 파일
첫 번째 삼각형
월드 좌표계
회전, 위치 변환
인덱스
지형 생성의 기본
파일로부터 지형 생성
키보드 입력
[tut10]
[tut11]
[tut12]
[tut13]
-- Expand all --


Thank you!

Support this site --
any amount is welcome !

Stay up-to-date

I don't have the time to keep a News section, so stay informed about the updates by clicking on this RSS file!