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

XNA에서 조명 설치

지금까지 우리는 지형에 색을 칠하고 Z-buffer를 설정하여 꽤 그럴싸하게 보이게 만들어 보았습니다. 아마도 여기에 조명을 더하면 더욱 그럴싸해 보일 것입니다. 이번 tutorial에서는 간단하게 두 개의 삼각형을 만들고 여기에 조명을 설정 해보겠습니다.

지형에 조명을 적용하는 것이 아니기 때문에 이번 tutorial에서는 이전 tutorial이 아닌 4번째 tutorial인 World Space에서 시작하겠습니다. 새 Windows Game 프로젝트를 생성하고 해당 tutorial에서 필요한 파일들을 복사해 옵시다.

이번 tutorial에서 우리는 직사광(directional light)을 사용합니다. 태양광(sunlight)를 상상해 봅시다. 직사광은 태양광과 같이 모든 빛이 하나의 동일한 방향으로 향해 있습니다. 빛이 삼각형 표면에 반사되는 효과를 계산하기 위해 XNA에서는 모든 vertex마다 normal값을 필요로 하게 됩니다.

다음 그림을 살펴봅시다.



만약 우리가 a)와 같은 광원을 사용하고, 3개의 표면에 비추고 있다면 XNA는 어떻게 1번 표면이 3번 표면보다 더 밝게 빛나는지 알 수 있을까요? (물론 우리의 눈에는 당연한 사실이지요.) b)에서 보이는 붉은색 선들의 길이는 각 표면들이 반사해야 할 빛의 양을 아주 잘 나타내고 있습니다. 그렇다면 이 붉은색 선들의 길이는 어떻게 계산할 수 있을까요? 사실은, XNA가 이 계산을 해줍니다. b)에서 보이는 파란색 화살표들과 붉은색 선들과의 관계를 살펴보면 쉽게 이해할 수 있습니다. (간단한 cosine 투영이지요.)

이것이 우리의 vector에 Normal이 필요한 이유 입니다. 따라서 우리는 더 이상 VertexPositionColor를 쓰지 않을 것 이지만 불행히도 XNA는 위치값(Position)과 색상값(Color), 그리고 Normal을 모두 담고 있는 구조체(Struct)를 제공하지 않습니다. 그러나 쉽게 우리가 새로운 구조체를 만들어 쓸 수 있으므로 그리 큰 문제는 아닙니다. 우리 입맛에 맞는 구조체를 만들기 위해 Class 가장 상단에 다음과 같은 코드를 추가합시다.

 public struct VertexPositionNormalColored
 {
     public Vector3 Position;
     public Color Color;
     public Vector3 Normal;
 
     public static int SizeInBytes = 7 * 4;
     public static VertexElement[] VertexElements = new VertexElement[]
     {
         new VertexElement( 0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0 ),
         new VertexElement( 0, sizeof(float) * 3, VertexElementFormat.Color, VertexElementMethod.Default, VertexElementUsage.Color, 0 ),
         new VertexElement( 0, sizeof(float) * 4, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0 ),
     };
 }

언뜻 보기에 복잡해 보이는 구조체이지만 사실은 처음 3줄의 라인만 이해하면 됩니다. VertexPositionNormalColored구조체는 Position, Color, Normal을 모두 담고 있습니다. SizeInByte필드는 여기서는 사용하지 않지만 추후 IndexBuffer를 설정할때 1개의 vertex가 몇 byte인지 지정해 줄 때 사용합니다. 그리고 마지막 VertexElements 필드는 VertexPositionNormalColored로 생성된 Vertex가 가지게 될 요소(Position, Color, Normal)를 정의합니다. 이 필드 또한 IndexBuffer를 사용할 때 필요합니다.
지금까지 사용했던 VertexPositionColor 대신 새로 만든 VertexPositionNormalColored를 사용하여 기존의 vertices 전역 변수를 재정의 해줍시다.

 VertexPositionNormalColored[] vertices;

이제 그려야 할 삼각형을 Normal값을 포함하여 재정의해야 합니다. 하지만 그전에 먼저 다음 그림을 보도록 합시다.



만약 간단하게 각 표면에 직각으로 Normal vector를 정의한다면 반사되는 빛은 a)에서 보이는 것과 같이 모서리(edge)를 가지게 될 것입니다. 오른쪽 표면이 왼쪽 표면보다 더 많은 빛을 반사하기 때문입니다. 그리고 두 표면은 확실히 분리되어 보이겠지요. 하지만 두 표면이 맞닫아 있는 최상단의 Normal vector를 b)에서 보이는 것과 같이 정의한다면 XNA는 두 표면에서 반사되는 빛을 보간하여 빛이 부드럽게 반사되도록 합니다. 이 vector는 a)에서 보이는 두 상단 Normal vector의 평균입니다.

vertex들을 재정의 하기 전에 camera를 먼저 재정의 해 줍시다.

 Matrix viewMatrix = Matrix.CreateLookAt(new Vector3(0, -40, 100), new Vector3(0, 50, 0), new Vector3(0, 1, 0));
 Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, this.Window.ClientBounds.Width / this.Window.ClientBounds.Height, 1.0f, 200.0f);

그리고 SetupVertices함수에서 2개의 삼각형을 그리기 위한 6개의 vertex들을 정의해 줍니다.

 private void SetUpVertices()
 {
     vertices = new VertexPositionNormalColored[6];
 
     vertices[0].Position = new Vector3(0f, 0f, 50f);
     vertices[0].Color = Color.Blue;
     vertices[0].Normal = new Vector3(1, 0, 1);
     vertices[1].Position = new Vector3(50f, 0f, 00f);
     vertices[1].Color = Color.Blue;
     vertices[1].Normal = new Vector3(1, 0, 1);
     vertices[2].Position = new Vector3(0f, 50f, 50f);
     vertices[2].Color = Color.Blue;
     vertices[2].Normal = new Vector3(1, 0, 1);
 
     vertices[3].Position = new Vector3(-50f, 0f, 0f);
     vertices[3].Color = Color.Blue;
     vertices[3].Normal = new Vector3(-1, 0, 1);
     vertices[4].Position = new Vector3(0f, 0f, 50f);
     vertices[4].Color = Color.Blue;
     vertices[4].Normal = new Vector3(-1, 0, 1);
     vertices[5].Position = new Vector3(0f, 50f, 50f);
     vertices[5].Color = Color.Blue;
     vertices[5].Normal = new Vector3(-1, 0, 1);
 }

2개의 삼각형(표면)이 맞닫아 있도록 했고 z축 좌표값을 설정하여 camera의 시선에서 볼 때 기울어 보이도록 했습니다. Normal vector는 위 그림의 a)와 같이 각 vertex에 직각으로 설정했습니다.

이제 Draw함수를 수정할 차례입니다. Draw함수의 삼각형을 그리는 해당 코드를 다음과 같이 설정 합시다.

 device.VertexDeclaration = new VertexDeclaration(device, VertexPositionNormalColored.VertexElements);
 device.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, 2);

마지막으로 조명을 설치해야 합니다. Draw함수의 effect.begin() 전에 다음과 같은 코드를 추가하여 조명을 설치할 수 있습니다.

 effect.CurrentTechnique = effect.Techniques["Colored"];
 effect.Parameters["xEnableLighting"].SetValue(true);
 effect.Parameters["xLightDirection"].SetValue(new Vector3(0.5f, 0, -1.0f));

이 코드는 조명 계산을 가능하게 하고(이때 technique가 Normal vector를 필요로 합니다.) 빛이 비추는 방향을 설정합니다. 좀더 보기 좋도록 배경을 검은색으로 설정하는 것도 좋겠네요.

이제 F5(디버그) 키를 눌러보면 그림의 a)와 같이 모서리(edge)가 있는 두 삼각형(표면)을 보게 될 것입니다. 왼쪽 삼각형은 밝게 보이고 오른쪽 삼각형은 어둡게 보여 두 표면이 확실히 구분이 될 것입니다.



이번에는 두 삼각형의 상단 Normal vector를 평균내어 기존 vertex들에 적용해 봅시다. (-1.0f, 0.0f, 1.0f)와 (1.0f, 0.0f, 1.0f)의 평균인 (-1.0f + 1.0f, 0.0f, 1.0f + 1.0f) / 2 = (0.0f, 0.0f, 1.0f)를 사용하면 됩니다.

 vertices[0].Position = new Vector3(0f, 0f, 50f);
 vertices[0].Color = Color.Blue;
 vertices[0].Normal = new Vector3(0, 0, 1);
 vertices[1].Position = new Vector3(50f, 0f, 00f);
 vertices[1].Color = Color.Blue;
 vertices[1].Normal = new Vector3(1, 0, 1);
 vertices[2].Position = new Vector3(0f, 50f, 50f);
 vertices[2].Color = Color.Blue;
 vertices[2].Normal = new Vector3(0, 0, 1);
 
 vertices[3].Position = new Vector3(-50f, 0f, 0f);
 vertices[3].Color = Color.Blue;
 vertices[3].Normal = new Vector3(-1, 0, 1);
 vertices[4].Position = new Vector3(0f, 0f, 50f);
 vertices[4].Color = Color.Blue;
 vertices[4].Normal = new Vector3(0, 0, 1);
 vertices[5].Position = new Vector3(0f, 50f, 50f);
 vertices[5].Color = Color.Blue;
 vertices[5].Normal = new Vector3(0, 0, 1);

F5(디버그)키를 눌러 실행해 보면 왼쪽 삼각형의 밝은 영역에서 오른쪽 삼각형의 어두운 영역까지 빛이 매우 자연스럽게 반사되고 있음을 확인할 수 있습니다. 그리고 이 조명 효과를 우리의 지형에 적용한다면 아주 보기 좋겠네요.






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!