티스토리 뷰

Application/C/C++

관리되는 DirectX 9.0 튜토리얼

알 수 없는 사용자 2008. 2. 20. 14:27

출처 : DirectX 9.0 SDK 온라인 도움말
번역 : jacking@korea.com

Tutorial 1: 디바이스의 작성


CreateDevice 튜토리얼 프로젝트에서는, Microsoft? Direct3D?를 초기화 하고, 단순한 청색의 화면을 렌더링하고, 최후에 셧 다운을 한다.

패스

소스의 위치: (SDK 루트)SamplesC#Direct3DTutorialsTutorial1

순서

애플리케이션 윈도우 작성

Microsoft? Windows? 애플리케이션이 실행시에 처음에 꼭 해야되는 것은, 애플리케이션 윈도우의 작성이다. 그 때문에 다음 샘플 코드의 Main() 함수에서는, 애플리케이션에서 정의한 CreateDevice 클래스의 컨스트럭션를 제일 처음에 호출한다. 이 클래스는, 디스플레이 윈도우의 사이즈, 윈도의 외형, 윈도우의 아이콘을 설정한다.

CreateDevice는, Microsoft .NET Framework에서 사용되어지는 System.Windows.Forms.Form 클래스로부터 만들어져, 애플리케이션 내의 윈도우를 나타낸다.

using System;

using System.Drawing;

using System.Windows.Forms;

using Microsoft.DirectX;

using Microsoft.DirectX.Direct3D;

namespace DeviceTutorial

{

    public class CreateDevice : Form

    {

        // Global variables for this project

        Device device = null; // Rendering device

        public CreateDevice()

        {

            // 폼의 크기를 지정

            this.ClientSize = new System.Drawing.Size(400,300);

            // 캡션 지정

            this.Text = "Direct3D Tutorial 01: CreateDevice";

            // 아이콘 지정

            this.Icon = new Icon(this.GetType(), "directx.ico");

        }

        .

        .

        .

    }

    .

    .

    .

}

Direct3D 오브젝트의 초기화

애플리케이션 윈도우를 작성하면, 장면 렌더링에 사용하는 Direct3D 오브젝트의 초기화를 하는 것이 가능하다. 이 처리에서는, 오브젝트를 작성하고, 프리젠테이션 파라메터를 설정하고, 최후에 Direct3D 디바이스를 작성한다.

public bool InitializeGraphics()

{

    try

    {

        // Create a PresentParameters object

        PresentParameters presentParams = new PresentParameters();

        // Don't run full screen

        presentParams.Windowed = true;

        // Discard the frames

        presentParams.SwapEffect = SwapEffect.Discard;

        // Instantiate a device

        device = new Device(0,

        DeviceType.Hardware,

        this,

        CreateFlags.SoftwareVertexProcessing, presentParams);

        return true;

    }

    catch { return false; }

}

상기의 샘플 코드는, 윈도우 표시특성의 설정에 사용하는 PresentParameters 오브젝트에 의해 달라진다. 예를들면, Windowed 프로퍼티를 TRUE로 설정하면, 표시되는 윈도우 사이즈는 풀 스크린보자 작게된다. 이 디폴트의 작은 윈도우 포맷에는, 메뉴와 자식 윈도우는 표시되지 않지만, 윈도우 화한 애플리케이션에 통상 표시 되는, [최소화], [최대화], [닫기] 버튼은 표시된다.
이 경우, 버퍼 메모리를 시스템 메모리로 빠르게 바꾸어 원래대로 되돌리는 기능은, SwapEffect.Discard 플라그에 의해 무효하게 된다. Windowed 프로퍼티가 FALSE의 경우에는, 만들어진 윈도우는, 최전면(最前面 )의 윈도우를 제외한 모든 윈도우 보다도 앞에 배치되어, 윈도우가 액티브로 되지 않았도 최전면 그 대로 표시되어진다.
초기화 순서의 마지막 단계는, Direct3D 디바이스의 작성이다. 이 예에서는, Device(Int32,DeviceType,Control,CreateFlags,PresentParameters)f오의 입력 플라그로, 하드웨어 디바이스를 우선하고, 정점 처리는 소프트웨어로 실행하도록 지정한다. CreateFlags.HardwareVertexProcessing를 설정하고
하드웨어 정점 처리를 사용하도록 시스템에 지시하면, 하드웨어 정점처리를 서포트 하는 비디오 카드에서는 퍼포먼스가 대폭적으로 향상 된다.

Direct3D 오브젝트의 렌더링

애플리케이션은, Application.DoEvents 메소드를 사용하는 루프 내에서 계속 동작한다. 이 경우, 이 메소드는 frm 이라는 이름의 CreateDevice 오브젝트를 인수로 취한다. DoEvents는, 표준적인 Windows 애플리케이션 메시지 루프를 현재의 스레드 위에서 실행한다.

static void Main()

{

    using (CreateDevice frm = new CreateDevice())

    {

        if (!frm.InitializeGraphics()) // Initialize Direct3D

        {

            MessageBox.Show("Could not initialize Direct3D. This tutorial will exit.");

            return();

        }

        frm.Show();

        // While the form is still valid, render and process messages

        while(frm.Created)

        {

            frm.Render();

            Application.DoEvents();

        }

    }

}

만들어진 CreateDevice Form 오브젝트가 유효한 동안은, 애플리케이션에서 정의한 Render 메소드를 호출하고, Direct3D 오브젝트를 렌더링 한다.
먼저, Device.Clear 메소드에서, 뷰 포트(열려 있는 윈도우)를 균일한 청색으로 설정한다. Device,BeginScene 메소드를 사용하여, 장면 렌더링을 시작한다. 렌더링이 끝났다면, EndScene 메소드와 Present 메소드를 계속해서 호출하고, 장면(Scene)을 종료 한다.

private void Render()

{

    if (device == null)

    return;

    //Clear the backbuffer to a blue color (ARGB = 000000ff)

    device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);

    //Begin the scene

    device.BeginScene();

    // Rendering of scene objects can happen here

    //End the scene

    device.EndScene();

    device.Present();

}

[번역] DirectX 9.0( Managed - .Net 기반) Direct3D Tutorial ? 2
출처 : DirectX 9.0 SDK 온라인 도움말
번역 : jacking@korea.com

Tutirial 2: 정점 렌더링


Microsoft? Direct3D?에서 만들었던 애플리케이션은, 정점을 사용하여 지오메트릭 형태를 묘화(描? ) 한다. 각 3차원(3D) Scene은, 이와 같은 지오메트릭 형태를 하나 또는 복수 포함하고 있다. Vertices tutorial 프로젝트에서는, 처음에 “Tutorial 1: 디바이스의 작성”의 초기화 순서를 실행하고, 계속해서 가장 단순한 도형인 삼각형을 만들어 디스플레이에 렌더링 한다.

패스

소스의 장소 : (SDK 루트)SamplesC#Direct3DTutorialsTutorial2

순서

이 tutorial에서는 3개의 정점을 사용하여 2D의 삼각형을 렌더링 한다. 여기서는, 정점 버퍼의 개념을 사용하고 있다. 정점 버퍼는, 통상은 정점을 저장 및 렌더링 할 때에 사용하는 VertexBuffer 오브젝트이다.

정점은, CustomVertex 커스텀 정점 클래스로 이용 가능한 구조체를 사용하여 여러가지 방법으로 정의 할 수 있다. 이 tutorial에서는 정점은 트랜스폼 되어 있으므로, 정점은 2D 윈도우 좌표로 표시되어 있다. 이를 테면 정점(0,0) 은 좌 상단 이고, 양의 x 축은 우방향, 양의 y 축은 아래방향으로 되어 있다. 또 이들 정점은 Direct3D의 라이팅도 사용하지 않지만, 대신에 독자의 디퓨즈(difuse) 색을 제공한다. 이 같은 특징은, 다음의 코드에서 나타나듯이 CustomVertex.TransformedColored 구조체에서 정점 버퍼를 초기화 하는것으로 제공한다.

public class Vertices : Form

{

    // Global variables for this project

    Device device = null; // Rendering device

    VertexBuffer vertexBuffer = null;

    .

    .

    .

    public void OnCreateDevice(object sender, EventArgs e)

    {

        Device dev = (Device)sender;

        // Now create the vertex buffer

        vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);

        vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);

        this.OnCreateVertexBuffer(vertexBuffer, null);

    }

    public void OnCreateVertexBuffer(object sender, EventArgs e)

    {

        VertexBuffer vb = (VertexBuffer)sender;

        GraphicsStream stm = vb.Lock(0, 0, 0);

        CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[3];

        .

        .

        .

        vb.Unlock();

    }

}

위의 코드에서는, VertexBuffer.Lock 메소드를 호출하고, 정점 버퍼의 데이터에 CPU가 직접 액세스 할 수 있도록 하고 있다. Lock을 호출하는 경우는, 그럴 때마다 뒤에 UnLock를 호출하지 않으면 안된다. Lock와 UnLock에 대한 자세한 사항은 “3. 리소스의 Lock”를 참조 한다.

위의 코드에서 만들고 있는 verts 오브젝트는, 3개의 TransformedColored 구조체의 배열이며, 삼각형 3개의 정점마다 하나의 구조체를 사용한다.
각 정점 구조체의 (X,Y,Z) 필드, Rhw 필드, Color 필드는, 다음 코드에서 초기화 된다. 필요한 ARGB 32 비트형식으로 색 데이터를 제공 할 때에는 ToArgb 메소드를 사용한다.

verts[0].X=150;verts[0].Y=50;verts[0].Z=0.5f; verts[0].Rhw=1;

verts[0].Color = System.Drawing.Color.Aqua.ToArgb();

verts[1].X=250;verts[1].Y=250;verts[1].Z=0.5f;verts[1].Rhw=1;

verts[1].Color = System.Drawing.Color.Brown.ToArgb();

verts[2].X=50;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1;

verts[2].Color = System.Drawing.Color.LightPink.ToArgb();

stm.Write(verts);

위의 2개의 코드에서는, GraphicsStream 클래스(stm오브젝트)를 사용했다.
쉐이더를 사용하는 입력 레지스터에 데이터를 바이드 할 때에는, 그래픽스 스트림을 사용한다. 이 코드에서는 GraphicsStream 오브젝트가 정점 버퍼에 직접 액세스 할 수 있도록 하고 있다. 바꿔 말하면, 정점 버퍼의 내용을 그래픽스 스트림에 두고, 스트림 내의 현재의 위치를 정점 버퍼의 길이 만큼 나아가고 있다.

다음 코드에서는, 스트림 소스, 정점 포맷, Device 오브젝트의 프리미티브 렌더링을 초기화 하도록, tutorial 1의 private 메소드 Render을 확장하는 방법을 나타낸다. Tutorial 1의 경우와 같게, 현재의 Vertices 오브젝트(frm)이 유효(有?)한 동안 또는 시스템의 묘화(描?) 이벤트가 트리거 되면, Render는 디스플레이에 렌더링을 한다.

private void Render()

{

    if (device == null)

    return;

    // Clear the back buffer to a blue color (ARGB = 000000ff)

    device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);

    // Begin the scene

    device.BeginScene();

    // New for Tutorial 2

    device.SetStreamSource( 0, vertexBuffer, 0);

    device.VertexFormat = CustomVertex.TransformedColored.Format;

    device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);

    // End the scene

    device.EndScene();

    device.Present();

}

[번역] DirectX 9.0( Managed - .Net 기반) Direct3D Tutorial ? 3
출처 : DirectX 9.0 SDK 온라인 도움말
번역 : jacking@korea.com

Tutorial 3: 행렬의 사용법


Matrices tutotial 프로젝트에서는, 행렬의 개념과 그 사용법을 나타낸다.
행렬은, 정점의 좌표를 트랜스 폼 하기도 하고, 카메라와 뷰 포트를 설정하는 등에 사용한다.

패스
소스의 위치 : (SDK 루트)SamplesC#Direct3DTutorialsTutorial3

순서

주 : Microsoft? Direct3D? 의 초기화、Microsoft Windows? 메시지의 처리, 렌더링, 셧 다운에 대해서는 ‘Tutorial 1 : 디바이스의 작성’을 참고 바람.

‘Tutorial 2 : 정점 렌더링’에서는, 2D의 정점을 렌더링 했어 삼각형을 묘화 했다. 이 tutorial에서는, 3D 정점 트랜스 폼을 사용하여 삼각형을 회전하는 처리를, Tutorial의 코드에 추가한다.

이 프로젝트에서는 삼각형 오브젝트에 트랜스 폼을 적용하기 위해, Tutorial 2에서 트랜스 폼 한 2D 윈도우 좌표를 사용하는 것이 아닌, 이하의 코드에서 나타내는 것과 같이, CustomVertex.PositionColored 구조체로 정점 버퍼를 초기화 한다.

Device dev = (Device)sender;

// Now create the vertex buffer.

vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), 3, dev, 0, CustomVertex.PositionColored.Format, Pool.Default);

그 위에, private의 Render 메소드에 대해서, 디바이스의 정점 포맷을 PositionColored 포맷으로 초기화 한다. 지오메트리를 렌더링 하기 전에, 애플리케이션에서 정의 한 SetupMatrices 메소드를 Render에서 호출한다.
이 메소드는, 삼각형 오브젝트의 3D 행렬 트랜스 폼을 작성하고 설정한다.

private void Render()

{

    .

    .

    .

    // Set up the world, view, and projection matrices.

    SetupMatrices();

    device.SetStreamSource(0, vertexBuffer, 0);

    device.VertexFormat = CustomVertex.PositionColored.Format;

    device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);

    // End the scene.

    device.EndScene();

    device.Present();

}

통상, 3D Scene에는 3 종류의 트랜스 폼이 설정된다. 트랜스 폼은 모두,
Device.Transform 프로퍼티로부터 액세스 하는 Transforms 오브젝트의 프로퍼티로써 정의된다. 어느 것이라도 Direct3D의 표준적인 왼손좌표계를 사용한다. ‘3D 좌표계’를 참조한다.

  1. 월드 트랜스 폼 행렬 : 이 tutorial에서는, 다음의 샘플 코드에서 나타나듯이 Matrix.RotateY 메소드를 호출하는 것으로, y축을 중심으로 했어 삼각형을 회전 시킨다. Matric는 범용의 Microsoft.DirectX 이름공간의 일부로 있다는 것에 주의 한다.
    이 호출에서는, 시스템의 Environment.TickCount 메소드의 값을 스케일링 값으로 나누었던 것을, 라디안 단위의 RotateY 인수로서 사용한다.
    이 순서에 의해, 삼각형은 y축의 주변을 부드럽게 회전하는 것 같이 된다.
  2. 뷰 트랜스폼 행렬 : 뷰 트랜스폼 행렬은, Scene 카메라 뷰를 생성한다. 이 샘플 코드에서는, Matrix.RotateY 메소드를 호출하는 것으로 행한다.
    3개의 Vector3 벡터가, 왼손(LH) 좌표계 뷰 행렬을 작성하는 LookAtLH 메소드의 인수를 형성한다. 3개의 벡터는, 각각 눈의 위치,
    카메라의 주시대상(이 경우는 원점), 현재의 월드의 위쪽을 나타낸다.
  3. 투영 트랜스 폼 행렬 : 투영 트랜스폼 행렬은, 3D 뷰 공간에서 2D 뷰 포트 공간에 지오메트리를 트랜스 폼 하는 방법을 정의 한다. 이 샘플
    코드에서는 , 왼손 좌표계의 PerspectiveFovLH 메소드로부터 반환되는 행렬로부터 형성한다. 메소드에 대하는 인수는, 시야각(라디안 단위), aspect 비( 공간의 높이를 폭으로 나눈 값), 가까운 클립면의 거리, 먼 클립면의 공간이다.

트랜스 폼 행렬을 작성하는 순서는, Scene 내의 오브젝트의 레이 아웃에는 영향을 주지 않는다. 정확히, Direct3D는, 상기의 순서로 Scene에 행렬을 적용한다.

private void SetupMatrices()

{

    // WORLD MATRIX: Just rotate the object about the y-axis.

    device.Transform.World = Matrix.RotationY(Environment.TickCount / 150.0f );

    // VIEW MATRIX: A view matrix can be defined given an eye point,

    // a point to look at, and a direction for which way is up. Here, set the

    // eye five units back along the z-axis and up three units, look at the

    // origin, and define "up" to be in the y-direction.

    device.Transform.View = Matrix.LookAtLH(

    new Vector3( 0.0f, 3.0f,-5.0f ),

    new Vector3( 0.0f, 0.0f, 0.0f ),

    new Vector3( 0.0f, 1.0f, 0.0f ) );

    // PROJECTION MATRIX: Set up a perspective transform (which

    // transforms geometry from 3-D view space to 2-D viewport space), with

    // a perspective divide making objects smaller in the distance. To build

    // a perspective transform, use the field of view (1/4 pi is common),

    // the aspect ratio, and the near and far clipping planes (which define

    // at what distances geometry should be no longer be rendered).

    device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, 1.0f, 1.0f, 100.0f );

}

렌더링의 특성은, RenderStates 클래스의 프로퍼티를 설정하는 것으로 제어 한다. 다음의 코드에서 나타나듯이, 이 처리는 애플리케이션에서 정의한 메소드 OnResetDevice에서 하고 있다.

public void OnResetDevice(object sender, EventArgs e)

{

    Device dev = (Device)sender;

    // Turn off culling, so the user sees the front and back of the triangle

    dev.RenderState.CullMode = Cull.None;

    // Turn off Direct3D lighting, since object provides its own vertex colors

    dev.RenderState.Lighting = false;

}

이 경우, 후면 컬링과 Direct3D 라이팅은 어느쪽이라도 off로 되어 있다. 이 설정에 의해 전심도(全深度)로 3D 오브젝트는 오브젝트 자체의 색으로 표신된다.

Tutorial 4: Material과 Light의 사용법


Lights Tutorial 프로젝트에서는, Light와 Material을 추가했어, 보다 리얼한
Microsoft? Direct3D? 오브젝트를 작성한다. Scene 내의 각 오브젝트는,
사용하는 Light타입에 근거를 두고 Light가 주어진다.
Material은, 폴리곤이 ambient light와 difuse light를 반사하는 방법, 폴리곤
의 Specular high light의 표현방법, 폴리곤이 빛을 반사하는가 어떤가를 나타낸다.

위치

소스의 위치 : (SDK 루트)SamplesC#Direct3DTutorialsTutorial4

순서

’Tutorial 3 : 행렬의 사용법”에서는, 오브젝트의 정점을 3D로 트랜스 폼 했었다. 이 Tutorial에서는, Material과 Light의 작성을 Tutorial 3의 코드에
추가한다.

심도 스텐실 초기화

이 프로젝트에서는, 다음 코드에서 나타나듯이, z 버퍼(심도 버퍼)와 심도
스텐실을 사용하도록 하는 초기화 순서도 Tutorial 3의 초기화 처리에 추가
한다. 심도 스텐실을 사용하면, 렌더링 한 Image의 일 부분을 마스크로
가려 표시되지 않는 하는 것이 가능하다. 여기서는 최초에 심도 스텐실을
유효하게 한 후. 포맷을 16비트 z 버퍼 심도로 설정한다.

public bool InitializeGraphics()

{

    .

    .

    .

    // Turn on a depth stencil

    presentParams.EnableAutoDepthStencil = true;

    // Set the stencil format

    presentParams.AutoDepthStencilFormat = DepthFormat.D16;

    .

    .

    .

}

정점버퍼와 렌더링 State의 초기화

Light를 사용하기 위한 조건의 하나는, 각 Surface가 법선 벡터를 가지고 있어야 되는 것 이다. 이 프로젝트에서는, 이제까지 Tutorial과는 다른 커스텀 정점 타입인 PositionNormal 구조체를 사용한다. Direct3D는, 이 구조체에 포함되는 3D 위치와 Surface 법선을 사용하여, 내부적인 라이팅 계산을 한다.

public void OnCreateDevice(object sender, EventArgs e)

{

    Device dev = (Device)sender;

    // Now create the vertex buffer

    vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionNormal), 100, dev, Usage.WriteOnly, CustomVertex.PositionNormal.Format, Pool.Default);

    vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);

    this.OnCreateVertexBuffer(vertexBuffer, null);

}

다음에 나타나듯이, 이 샘플 코드에서는, RenderStates 프로퍼티를 사용하여 Scene 지오메트리를 효율 좋게 저장 할 수 있도록 z 버퍼(심도 버퍼)의 사용을 유효하게 하고, Direct3d 라이팅도 유효하게 하고 있다.

public void OnResetDevice(object sender, EventArgs e)

{

    Device dev = (Device)sender;

    // Turn off culling, so the user sees the front and back of the triangle

    device.RenderState.CullMode = Cull.None;

    // Turn on the z-buffer

    device.RenderState.ZBufferEnable = true;

    device.RenderState.Lighting = true; // Make sure lighting is enabled

}

원주 오브젝트의 작성

디바이스의 초기화( 위에 나타낸 OnCreateDevice)에서는, 애플리케이션에서 정의한 OnCreateVertexBuffer 메소드를 호출하여, 원주 오브젝트를 만들고 있다, 다음 샘플 코드에서 나타나듯이 정점 버퍼를 초기화 하여 원주 포인트를 저장한 후, 원주 위의 각 포인트의 위치와 법선을 정점 버퍼에 로드 하고있다.

public void OnCreateVertexBuffer(object sender, EventArgs e)

{

    VertexBuffer vb = (VertexBuffer)sender;

    // Create and lock a vertex buffer (which will return the structures)

    CustomVertex.PositionNormal[] verts = (CustomVertex.PositionNormal[])vb.Lock(0,0);

    for (int i = 0; i < 50; i++)

    {

        // Fill up the structs

        float theta = (float)(2 * Math.PI * i) / 49;

        verts[2 * i].SetPosition(new Vector3( (float)Math.Sin(theta), -1, (float)Math.Cos(theta)));

        verts[2 * i].SetNormal(new Vector3( (float)Math.Sin(theta), 0, (float)Math.Cos(theta)));

        verts[2 * i + 1].SetPosition(new Vector3( (float)Math.Sin(theta), 1, (float)Math.Cos(theta)));

        verts[2 * i + 1].SetNormal(new Vector3( (float)Math.Sin(theta), 0, (float)Math.Cos(theta)));

    }

    // Unlock (and copy) the data

    vb.Unlock();

}

Tutorial 3에서 나타나듯이, SetupMatrices private 메소드의 월드 트랜스
폼 행열을 사용하여, 원주를 회전시킨다.

Material의 작성

Material은, 지오메트리 오브젝트에 light가 비추어 졌을 때, 지오메트리
오브젝트의 Surface로부터 반사되는 색을 정의 한다. 다음 샘픔 코드에서는,
Material 구조체를 사용하여, 백색의 Material을 만들고 있다.
이 Material의 diffuse 색 프로퍼티와 Ambient 색 프로퍼티는, 백색으로
설정된다. 이 호출을 한 후, 색 프로퍼티에 다른 값을 설정 할 때까지는,
이 Material을 사용하여 각 프리미티브가 렌더링 된다.

private void SetupLights()

{

    System.Drawing.Color col = System.Drawing.Color.White;

    // Set up a material. The material here just has the diffuse and ambient

    // colors set to white. Note that only one material can be used at a time.

    Direct3D.Material mtrl = new Direct3D.Material();

    device.Material = mtrl;

    .

    .

    .

}

라이트의 작성

Direct3D에서 이용 할 수 있는 light는, Point Light, Directional Light, Spot Light의 3 종류가 있다. 이 Tutorial 프로젝트에서는, 빛이 한방향을 비추어주는 Directional light을 만들고, light의 방향을 주기적으로 변화 시킨다. 다음 샘플 코드에서는, Light 오브젝트를 사용하여, 어두운 청록색의 Directional light을 만들고 있다.
Scene 내의 모든 오브젝트는, 낮은 레벨의 모노크롬(클레어)의 Ambient light에 의해서도 비추어진다.

private void SetupLights()

{

    .

    .

    .

    // Set up a colored directional light, with an oscillating direction.

    // Note that many lights may be active at a time (but each one slows down

    // the rendering of the scene). However, here just one is used.

    device.Lights[0].Type = LightType.Directional;

    device.Lights[0].Diffuse = System.Drawing.Color.DarkTurquoise;

    device.Lights[0].Direction = new Vector3( (float)Math.Cos(Environment.TickCount / 250.0f), 1.0f, (float)Math.Sin(Environment.TickCount / 250.0f));

    device.Lights[0].Commit(); // Let Direct3D know about the light

    device.Lights[0].Enabled = true; // Turn it on

    // Finally, turn on some ambient light.

    // Ambient light is light that scatters and lights all objects evenly.

    device.RenderState.Ambient = System.Drawing.Color.FromArgb(0x202020);

    .

    .

    .

    .

Tutorial 5 : 텍스쳐 맵의 사용법


Textures Tutorial 프로젝트에서는, Microsoft? Direct3D? 오브젝트에 텍스쳐를 추가 한다.
light와 material에 의해 Scene는 더욱 리얼하게 되었지만, 가장 리얼함이 증가하는 것은 Surface에 텍스쳐를 추가할 때 이다. 텍스쳐는, Surface에 쏙 입혀진 벽지라고도 생각 할 수 있다. 예를들면, 나무 텍스쳐를 입방체에 붙이는 것에 의해, 그 입방체가 나무와 같이 보이는 것이 가능하다. 이 Tutorial프로젝트에서는, ‘Tutorial 4 : material와 light 사용법’에서 작성한 원주 오브젝트에 ‘바나나 껍질’의 텍스쳐를 추가한다.

위치

소스의 위치 : (SDK 루트)SamplesC#Direct3DTutorialsTutorial5

순서

‘Tutorial 4 : Material와 light 사용법’에서는, Direct3D 오브젝트에 Material과 light를 작성했다. 이 Tutorial에서는, Tutorial 4의 코드에 텍스쳐를 로드 하고, 정점을 설정하고, 텍스쳐를 갖춘 오브젝트를 표시하는 순서를 추가한다.

텍스쳐의 작성

텍스쳐를 사용 할 때에는, 커스텀 정점 포맷으로 텍스쳐의 좌표를 가진 정점 버퍼를 작성할 필요가 있다. 텍스쳐 좌표는, 프리미티브 내의 각 벡터에 대해서 텍스쳐를 배치하는 장소를 Direct3D에 가리킨다. 텍스쳐 좌표의 범위는 0.0 부터 1.0 까지로, (0.0, 0.0)은 텍스쳐의 좌상을 나타내고, (1.0, 1.0)은 텍스쳐의 우하를 나타낸다.

새로운 Texture 오브젝트를 초기화 한 후 , 다음 샘플 코드에서는, PositionNormalTextured 구조체를 사용하여 정점 버퍼 포맷을 설정 하고 있다. 이 초기화를 하면, 정점 버퍼는, (x, y, z) 위치와 (x, y, z) 법선 데이터 및 1 셋트의 (tu, tv) 텍스쳐 좌표를 받아 들이는 것이 가능하도록 된다.

public class Textures : Form

{

    // Our global variables for this project

    Device device = null; // Our rendering device

    VertexBuffer vertexBuffer = null;

    Texture texture = null;

    .

    .

    .

    public void OnCreateDevice(object sender, EventArgs e)

    {

        Device dev = (Device)sender;

        // Now create the vertex buffer

        vertexBuffer = new VertexBuffer(

        typeof(CustomVertex.PositionNormalTextured), 100, dev, Usage.WriteOnly, CustomVertex.PositionNormalTextured.Format, Pool.Default);

        vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);

        this.OnCreateVertexBuffer(vertexBuffer, null);

    }

}

텍스쳐 데이터 로드

렌더링 State의 설정(디스플레이 인수)는, Tutorial 4와 거의 같다.
정확하게, Direct3D의 라이팅이 무효하게 되어 있는 원주 오브젝트의 색이 표시되는 것과 TextureLoader.FromFile 메소드를 사용하여 비트맵 파일로부터 “바나나 껍질” 텍스쳐를 로드라고 있는 것이 다르다.

public void OnResetDevice(object sender, EventArgs e)

{

    Device dev = (Device)sender;

    // Turn off culling, so the user sees the front and back of the triangle

    dev.RenderState.CullMode = Cull.None;

    // Turn off Direct3D lighting

    dev.RenderState.Lighting = false;

    // Turn on the z-buffer

    dev.RenderState.ZBufferEnable = true;

    // Now create the texture

    texture = TextureLoader.FromFile(dev,

    Application.StartupPath + @"....banana.bmp");

}

다음의 샘플 코드에서 나타나듯이, 원주 오브젝트의 프로퍼티에서 정점 버퍼를 로드하는 순서는, Tutorial 4의 애플리케이션 정의 메소드 OnCreateVertexBuffer 와 같다.
정확하게, 각 포인트에 대한 텍스쳐 좌표 (tu, tv)가 추가되어 있다. 이 순서에 의해, 렌더링하면 텍스쳐는 원주의 주변을 매끄럽게 둘러싸, 텍스쳐는 원래의 원주에 고정되어진 채로 된다.

public void OnCreateVertexBuffer(object sender, EventArgs e)

{

    VertexBuffer vb = (VertexBuffer)sender;

    // Create a vertex buffer

    // Lock the buffer (which will return the structures)

    CustomVertex.PositionNormalTextured[] verts = (CustomVertex.PositionNormalTextured[])vb.Lock(0,0);

    for (int i = 0; i < 50; i++)

    {

        // Fill up the structures

        float theta = (float)(2 * Math.PI * i) / 49;

        verts[2 * i].SetPosition( new Vector3( (float)Math.Sin(theta), -1, (float)Math.Cos(theta) ) );

        verts[2 * i].SetNormal( new Vector3( (float)Math.Sin(theta), 0, (float)Math.Cos(theta) ) );

        verts[2 * i].Tu = ((float)i)/(50-1);

        verts[2 * i].Tv = 1.0f;

        verts[2 * i + 1].SetPosition( new Vector3((float)Math.Sin(theta), 1, (float)Math.Cos(theta) ) );

        verts[2 * i + 1].SetNormal( new Vector3((float)Math.Sin(theta), 0, (float)Math.Cos(theta) ) );

        verts[2 * i + 1].Tu = ((float)i)/(50-1);

        verts[2 * i + 1].Tv = 0.0f;

    }

}

Scene 렌더링

텍스쳐 스테이지에 의해, 텍스쳐를 렌더링 하는 동작을 정의 할 수 있다. 예를 들면, 복수의 텍스쳐를 하나씩 블렌딩 할 수 있다. 이 Tutorial 프로젝트에서는, Tutorial 4의 private 메소드 Render에서 시작하여, Direct3D 디바이스가 렌더링에 사용하는 텍스쳐 스체이지를 0으로 설정한다. 하나의 디바이스는 최댜 8개의 텍스쳐를 가지는 것이 가능하므로, 최대 스테이지는 7 이다. 정확히 이 Tutorial 프로젝트에서는, 다만 하나의 텍스쳐를 사용하고, 그것을 스테이지 0에 배치한다. 0은, Device.SetTexture 메소드의 stage 인수 및 Device.TextureState 프로퍼티에 대한 배열값 양쪽이 사용되고 있다.

텍스쳐의 렌더링 방법을 제어 할 때 에는, TextureOperation 열거와 TextureArgument 열거의 정수를 사용한다. 예를들면, 이 코드에서의 설정에 의해, 출력 칼라는 텍스쳐 칼라와 diffuse 색을 합한 것이 된다. 텍스쳐에 있어 칼라 블렌딩의 자세한 것에 대해서는 ’텍스쳐와 정점 칼라 블렌드’를 참고 한다.
private void Render()

{

    .

    .

    .

    // Set up our texture. Using textures introduces the texture stage states,

    // which govern how textures get blended together (in the case of multiple

    // textures) and lighting information. In this case, modulate (blend)

    // the texture with the diffuse color of the vertices.

    device.SetTexture(0,texture);

    device.TextureState[0].ColorOperation = TextureOperation.Modulate;

    device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;

    device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;

    device.TextureState[0].AlphaOperation = TextureOperation.Disable;

    .

    .

    .

Tutorial 6 : Meshe 사용법


복잡한 지오메트리는 통상 3D 모델링 소프트웨어를 사용하여 모델이 되어지며, 파일에 보존된다. 예를 들어, .x 파일 포맷등이 있다. Microsoft? Direct3D?에서는, Mesh를 사용하여 이런 파일로부터 오브젝트를 로드 한다. Meshes Tutorial 프로젝트에서는, Mesh에 관한 토픽을 설명하고, Mesh를 로드, 렌더링, 언 로드 하는 방법을 나타낸다.

Mesh에는, 복잡한 모델에 대한 데이터가 포함 되어 있다. Meshe는, 텍스쳐랑 Material등의 리소스, 위치 데이터랑 순접성 데이터등의 속성을 보존하고, 추상적인 데이터 콘테이너 이다. Mesh는 약간 복잡하지만, Direct3D에는 Mesh의 사용을 쉽게 하는 함수가 포함되어 있다.

위치
소스의 위치 : (SDK 루트)SamplesC#Direct3DTutorialsTutorial6

순서

”Tutorial 5 : 텍스쳐 맵의 사용법”에서는 Direct3D 오브젝트에 텍스쳐를 만들었다.
이 Tutorial에서는 파일로부터 Mesh를 취급하는 순서를 Tutorial 5의 코드에 추가한다.
한편으로, 정점 버퍼의 작성에 사용되었던 애플리케이션 정의 메소드 OnCreateDevice와 그것에 관련하는 디바이스 작성의 호출은 제거 한다. 여기에서 사용하는 순서는, Mesh 함수의 호출 중에서 비명시적으로 정점 버퍼를 취급하고 있다.

Meshe 오브젝트의 초기화

이 Tutorial 프로젝트에서는, 이하에 나타나듯이, 복수차원의 Material과 텍스쳐 배열을 초기화 한다. System.ComponentModel 이름공간 및 System.IO 이름 공간의 using 선언에도 주의한다.

using System;

using System.Drawing;

using System.ComponentModel;

using System.Windows.Forms;

using System.IO;

using Microsoft.DirectX;

using Microsoft.DirectX.Direct3D;

using Direct3D = Microsoft.DirectX.Direct3D;

public class Meshes : Form

{

    Device device = null; // Rendering device

    Mesh mesh = null; // Mesh object in system memory

    Direct3D.Material[] meshMaterials; // Materials for the mesh

    Texture[] meshTextures; // Textures for the mesh

    PresentParameters presentParams = new PresentParameters();

    .

    .

    .

}

애플리케이션에서 정의한 OnResetDevice 함수는, Material 구조체에 Mesh 파일 데이터를 캡쳐하기 위해서 사용되어지는 ExtendedMaterial 오브젝트를 초기화 한다. 이 함수는, 디렉토리 패스를 Mesh 파일에 설정하고, 디바이스를 초기화 하고, z 버퍼와 흰색의 Ambient 라이트를 유효하게 한다.

public void OnResetDevice(object sender, EventArgs e)

{

    ExtendedMaterial[] materials = null;

    // Set the directory up to load the right data, because the

    // default build location is Bindebug or Binrelease.

    Directory.SetCurrentDirectory(Application.StartupPath + @"....");

    Device dev = (Device)sender;

    // Turn on the z-buffer.

    dev.RenderState.ZBufferEnable = true;

    // Turn on ambient lighting.

    dev.RenderState.Ambient = System.Drawing.Color.White;

    .

    .

    .

}

Meshs 오브젝트의 로드

이하의 코드에서 나타나듯이, OnResetDevice 함수는 다음에 텍스쳐 맵화 된 3D의 호랑이를 표현하는 Mesh를 tiger.x 파일로부터 로드 한다. 이 Mesh.FromFile 함수의 호출에 대해서, MeshFlags 열거의 SystemMemory 정수는, 일반적으로는 디바이스로부터 엑세스할 수 없는 시스템 RAM에 Mesh를 로드하는 것을 나타내고 있다. Mesh가 로드 되어지면, meshMaterial Material 오브젝트는, Mesh 파일로부터 로드 된 Material ExtendedMaterial 오브젝트의 Material 구조체를 멤버에 설정한다. Material에 Ambient 생의 설정도 행하여진다. 마지막으로 TextureLoader.FromFile 함수의 호출에 의해, meshTextures Texture 오브젝트가 텍스쳐와 같이 파일로부터 로드 되어진다. meshMaterial과 meshMaterial는 어느쪽이라도 파일로부터 로드된 materials 구조체의 차원(Length)에 초기화 되어진다.

public void OnResetDevice(object sender, EventArgs e)

{

    .

    .

    .

    // Load the mesh from the specified file.

    mesh = Mesh.FromFile("tiger.x", MeshFlags.SystemMemory, device, out materials);

    if (meshTextures == null)

    {

    // Extract the material properties and texture names.

    meshTextures = new Texture[materials.Length];

    meshMaterials = new Direct3D.Material[materials.Length];

    for( int i=0; i<materials.Length; i++ )

    {

        meshMaterials[i] = materials[i].Material3D;

        // Set the ambient color for the material. Direct3D

        // does not do this by default.

        meshMaterials[i].Ambient = meshMaterials[i].Diffuse;

        // Create the texture.

        meshTextures[i] = TextureLoader.FromFile(dev, materials[i].TextureFilename);

        }

    }

}

Mesh 오브젝트의 렌더링

Mesh를 로드 했다면, private 멤버의 Render를 호출하여 Mesh 오브젝트를 렌더링 한다.
Tutorial 5에서 하였던 것과 같이, 이 함수는, 최초에 Scene를 개시하고, 애플리케이션 정의 함수 SetupMatrices를 호출한다. 렌더링 하기 위해서 Mesh는 로드된 Material마다 하나씩 서브셋에 분할되어져 있다. 다음의 코드에서 나타나듯이, 루프를 실행하고 각 Material 서브셋을 렌더링 한다. 루프에서는, Material마다 이하의 처리를 한다.

  • 디바이스의 Material 프로퍼티에、meshMaterials Material 구조체를 설정한다.
  • 디바이스의 텍스쳐 스테이지 0에、meshTextures Texture 구조체를 설정한다.
  • Material 서브셋을 DrawSubset 함수로 묘화한다. 이 함수는、BaseMesh 클래스로부터 계승한다.

private void Render()

{

    .

    .

    .

    for( int i=0; i<meshMaterials.Length; i++ )

    {

        // Set the material and texture for this subset.

        device.Material = meshMaterials[i];

        device.SetTexture(0, meshTextures[i]);

        // Draw the mesh subset.

        mesh.DrawSubset(i);

    }

    // End the scene.

    device.EndScene();

    device.Present();

}

ps : 부산의 게임개발자분든은 www.bgda.org 로 오세요^^