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에서는 지형을 그려볼 텐데, 우선 간단한 것 부터 시작해봅시다. 4*3의 vertex들이 연결되어 있는 형태의 지형을 그려보도록 하겠습니다. 사실 지형은 보통 대규모로 표현되고 때로는 변화하기도 하기 때문에 대규모의 vertex들을 동적으로 다룰 필요가 있습니다. 대규모의 vertex들을 다루는 방법에 대해서는 다음 tutorial에서 다루겠습니다.

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

4*3의 vertex들을 다루기 위해서 두 개의 전역변수가 추가됩니다.

 int WIDTH = 4;
 int HEIGHT = 3;

쉽게 생각해서 WIDTH는 x축에 대한 vertex개수, HEIGHT는 y축에 대한 vertex개수라고 생각하면 됩니다. 총 vertex개수는 4*3=12가 되겠네요. 그런데 vertex의 좌표값은 반드시 x, y, z축 3개의 좌표값으로 구성되는데 아직까지는 z축에 대한 좌표값이 없습니다. 지형을 그리는데 있어서 z축 좌표값은 높이(height)값이라 부르기도 하며 지형 표현하는데 있어서 가장 중요한 데이터 입니다. 4*3, 즉 12개의 vertex에 대해 z축 좌표값을 지정해주기 위해 전역 변수를 하나 더 추가해줍니다.

 int[,] heightdata;

그리고, 이 2차원 배열에 z축 좌표값을 채워주기 위해 다음과 같은 새로운 함수를 만듭니다.

 private void LoadHeightData()
 {
     heightdata = new int[WIDTH, HEIGHT];
 
     heightdata[0,0] = 0;
     heightdata[1,0] = 0;
     heightdata[2,0] = 0;
     heightdata[3,0] = 0;
     heightdata[0,1] = 1;
     heightdata[1,1] = 0;
     heightdata[2,1] = 2;
     heightdata[3,1] = 2;
     heightdata[0,2] = 2;
     heightdata[1,2] = 2;
     heightdata[2,2] = 4;
     heightdata[3,2] = 2;
 }

함수를 만들었다면 Initialize함수에서 호출해 줘야겠지요.

 protected override void Initialize()
 {
     // TODO: Add your initialization logic here
 
     base.Initialize();
 
     LoadHeightData();
 
     SetupXNADevice();
 
     SetupVertices();
     SetupIndices();
 
     SetupCamera();
 }

유의할 점은 반드시 SetupVertices함수와 SetupIndices함수 전에 호출되어야 한다는 점입니다.

이제 우리는 vertex들을 만들 수 있습니다. 지금까지와 같이 SetupVertices함수를 수정하는 것으로 쉽게 4*3=12개의 vertex들을 정의할 수 있습니다. 다만, 아직 z축 좌표값은 쓰지 않기로 합시다. z축 좌표값은 잠시 후에 적용하겠습니다.

 private void SetupVertices()
 {
     vertices = new VertexPositionColor[WIDTH * HEIGHT];
 
     for (int x = 0; x < WIDTH; x++)
     {
         for (int y = 0; y < HEIGHT; y++)
         {
             vertices[x + y * WIDTH].Position = new Vector3(x, y, 0);
             vertices[x + y * WIDTH].Color = Color.White;
         }
     }
 
     vb = new VertexBuffer(device, VertexPositionColor.SizeInBytes * WIDTH * HEIGHT, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic);
     vb.SetData(vertices);
 }

2개의 중첩된 반복문으로 우리는 비교적 간단하게 12개의 vertex에게 각각의 좌표값과 색상값을 지정했습니다. vertex buffer에 배열을 저장할 때 buffer의 크기를 정확하게 지정해야 함을 기억해두기 바랍니다. (VertexPositionColor.SizeInBytes * WIDTH * HEIGHT)

다음은 조금 어려운 작업입니다. 12개의 vertex들을 삼각형으로 연결해주는 index buffer를 작성해야합니다. 가장 좋은 방법은 12개의 vertex들을 두 개의 삼각형들의 묶음으로 나누어 다루는 것 입니다. 다음 그림을 살펴봅시다.



일단, 우리는 굵은 실선으로 그려진 삼각형들을 먼저 그려보도록 하겠습니다. 이를 위해 SetupIndices함수를 다음과 같이 수정해야 합니다.

 private void SetupIndices()
 {
     int[] indices = new int[(WIDTH - 1) * (HEIGHT - 1) * 3];
 
     for (int x = 0; x < WIDTH; x++)
     {
         for (int y = 0; y < HEIGHT - 1; y++)
         {
             indices[(x + y * (WIDTH - 1)) * 3 + 0] = (x + 1) + (y + 1) * WIDTH;
             indices[(x + y * (WIDTH - 1)) * 3 + 1] = (x + 1) + (y + 0) * WIDTH;
             indices[(x + y * (WIDTH - 1)) * 3 + 2] = (x + 0) + (y + 0) * WIDTH;
         }
     }
 
     ib = new IndexBuffer(device, sizeof(int), (WIDTH - 1) * (HEIGHT -1) * 3, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic);
     ib.SetData(indices);
 }

그림을 살펴보면 알 수 있지만 그려야 하는 vertex의 개수는 12개지만 그릴 삼각형의 개수는 6개입니다. (=(4-1)*(3-1)=6) 그리고 하나의 삼각형은 3개의 vertex로 구성되어 있으므로 필요한 index의 개수는 18개 입니다. (=(4-1)*(3-1)*3 = 18) 즉 우리는 12개의 vertex를 사용하는 18개의 index로 6개의 삼각형을 그리는 것 입니다. 또한 18개의 index를 지정할 때, 우리는 다시금 culling에 대해서 기억해내야 할 필요가 있습니다. 카메라의 시점에서 볼 때 시계 방향(clock-wise)으로 그려진 삼각형만이 화면에 표시된다는 사실(culling)은 언제 어디서나 통용되는 진리이고 지형을 그릴 때도 역시 마찬가지 입니다. 코드의 수식은 이 법칙을 준수하고 있습니다. 첫 번째 index는 top-right 위치의 vertex, 두 번째 index는 bottom-right, 세 번째 index는 bottom-left 위치의 vertex입니다. 코드의 수식과 data를 비교해보면 금방 이해할 수 있을 것입니다. 마지막으로 index buffer의 크기를 수정해 주는 일도 잊어서는 안됩니다.

이제 vertex buffer와 index buffer가 모두 준비되었습니다. 지금까지의 결과를 화면에 띄워봅시다. 다만 그 전에 Draw함수를 약간 수정해 주어야 합니다. Draw함수에서 삼각형을 그리는 코드인 DrawIndexedPrimitive함수의 parameter를 다음과 같이 수정해 줍시다.

device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, WIDTH * HEIGHT, 0, (WIDTH - 1) * (HEIGHT - 1));

12(=4*3)개의 vertex를 사용하여 6(=(4-1)*(3-1))개의 삼각형을 그리는 코드입니다.

마지막으로 결과를 좀 더 가까이서 살펴보기 위해 카메라의 위치를 옮겨둡시다. 여기서는 z축 좌표값을 15.0f로 수정했습니다. SetupCamera함수의 카메라 view matrix 생성 코드를 다음과 같이 수정합니다.

 Matrix viewMatrix = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 15.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));

이제 디버그(F5)키를 누르면 6개의 삼각형으로 우리가 그릴 지형의 절반이 표현되어 있음을 확인할 수 있습니다.



화면에는 6개의 삼각형이 그려져 있을 것 입니다. 이 삼각형들은 우리가 최종적으로 표현하고자 하는 지형의 절반입니다.

이제 나머지 6개의 삼각형을 그리는 것과 동시에, z축 좌표값 또한 적용해 봅시다. 카메라를 z축의 위치로 옮겨보면 확인할 수 있지만, 지금은 모든 vertex가 동일한 z축 좌표값을 가지고 있으므로 모든 면은 평평한(=flat=same level) 상태입니다. 지형의 z축 좌표값인 heightdata를 vertex에 적용해 봅시다. SetupVertices의 vector를 지정하는 코드를 다음과 같이 수정합니다.

 vertices[x + y * WIDTH].Position = new Vector3(x, y, heightdata[x,y]);

다음은 나머지 6개의 삼각형을 마저 그리겠습니다. SetupIndices함수를 다음과 같이 수정합니다.

 private void SetupIndices()
 {
     int[] indices = new int[(WIDTH - 1) * (HEIGHT - 1) * 3 * 2];
 
     for (int x = 0; x < WIDTH - 1; x++)
     {
         for (int y = 0; y < HEIGHT - 1; y++)
         {
             indices[(x + y * (WIDTH - 1)) * 3 * 2 + 0] = (x + 1) + (y + 1) * WIDTH;
             indices[(x + y * (WIDTH - 1)) * 3 * 2 + 1] = (x + 1) + (y + 0) * WIDTH;
             indices[(x + y * (WIDTH - 1)) * 3 * 2 + 2] = (x + 0) + (y + 0) * WIDTH;
             indices[(x + y * (WIDTH - 1)) * 3 * 2 + 3] = (x + 1) + (y + 1) * WIDTH;
 
             indices[(x + y * (WIDTH - 1)) * 3 * 2 + 4] = (x + 0) + (y + 0) * WIDTH;
             indices[(x + y * (WIDTH - 1)) * 3 * 2 + 5] = (x + 0) + (y + 1) * WIDTH;
         }
     }
 
     ib = new IndexBuffer(device, typeof(int), (WIDTH - 1) * (HEIGHT -1) * 3 * 2, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic);
     ib.SetData(indices);
 }

6개 삼각형의 2묶음, 12개의 삼각형을 그리기 위해 *3 뒤에 *2를 추가하고 늘어난 index를 추가로 지정해 주었습니다. 삼각형을 추가로 그리기 위해서는 배열의 크기에 항상 신경을 써야 합니다. 물론 추가되는 두 번째 삼각형 묶음도 vertex를 그리는 순서는 시계 방향이 되어야 할 것입니다. (culling) data와 vertex가 그려지는 순서를 비교해보길 바랍니다.

draw함수 또한 수정해줍시다. DrawIndexedPrimitives함수의 parameter 중, 삼각형의 개수에 *2를 해주어야 합니다.

 device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, WIDTH * HEIGHT, 0, (WIDTH - 1) * (HEIGHT - 1) * 2);

이제 디버그(F5)키를 누르면 12(=4*3)개의 vertex로 12(=(4-1)*(3-1)*2)개의 삼각형을 그려 표현된 지형이 나타날 것 입니다.






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!