Graphics/DirectX

Direct X - 5. 정점버퍼를 이용한 삼각형 출력

MOLOKINI 2014. 6. 1. 21:04

4강과 같은 삼각형의 출력이지만, 

정점 버퍼

를 사용했다는 점이 다르다.

 
정점버퍼를 사용하는 이유는, 4장처럼 정점 데이터를 그리는 시점에서 직접 전송을 할 경우, 메인루프를 도는 과정에서 매회 데이터를 보내지 않으면 삼각형 표시가 되지 않기 때문에, 처리에 많은 시간이 걸릴 가능성이 있어,,
BUT, 정점버퍼는 정점버퍼를 비디오메모리(GPU : 그래픽카드)에 배치할 수 있기 때문에 성능이 좋아져^^ 특히! 3차원 데이터를 그릴 때, 훨씬 그 퍼포먼스는 좋아지지(정점의 수가 많아지니까!)
 
일단 소스를 보자
 
using System;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System.Windows.Forms;
using System.Drawing;

namespace MDXSample
{
    /// <summary>
    /// 메인 샘플 클래스
    /// </summary>
    public partial class MainSample : IDisposable
    {

        /// <summary>
        /// 정점 버퍼
        /// </summary>
        private VertexBuffer _vertexBuffer = null;

        public bool InitializeApplication(MainForm topLevelForm)
        {
            // 폼의 참조를 보관 유지
            this._form = topLevelForm;

            try
            {
                // Direct3D 디바이스 작성
                this.CreateDevice(topLevelForm);
                // 폰트의 작성
                this.CreateFont();

            }
            catch (DirectXException ex)
            {
                // 예외 발생
                MessageBox.Show(ex.ToString(), "에러", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            // 삼각형 다각형을 표시하기 위한 정점 버퍼를 작성
            this._vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored),
                3, this._device, Usage.None, CustomVertex.TransformedColored.Format, Pool.Managed);

            // 3점의 정보를 보관하기 위한 메모리를 확보
            CustomVertex.TransformedColored[] vertices = new CustomVertex.TransformedColored[3];

            // 각 정점을 설정
            vertices[0] = new CustomVertex.TransformedColored(
                200.0f, 50.0f, 0.0f, 1.0f, Color.Red.ToArgb());
            vertices[1] = new CustomVertex.TransformedColored(
                350.0f, 50.0f + 150.0f * (float)Math.Sqrt(3), 0.0f, 1.0f, Color.Blue.ToArgb());
            vertices[2] = new CustomVertex.TransformedColored(
                50.0f, 50.0f + 150.0f * (float)Math.Sqrt(3), 0.0f, 1.0f, Color.Green.ToArgb());

            // 정점 버퍼를 잠근다
            using (GraphicsStream data = this._vertexBuffer.Lock(0, 0, LockFlags.None))
            {
                // 정점 데이터를 정점 버퍼에 씁니다
                data.Write(vertices);

                // 정점 버퍼의 락을 해제합니다
                this._vertexBuffer.Unlock();
            }
            return true;
        }

        /// <summary>
        /// 메인 루프 처리
        /// </summary>
        public void MainLoop()
        {
            // 화면을 단색(파랑색)으로 클리어
            this._device.Clear(ClearFlags.Target, Color.DarkBlue, 1.0f, 0);

            // 「BeginScene」와「EndScene」의 사이에 화면에 출력할 내용을 코딩
            this._device.BeginScene();


            // 정점 버퍼를 디바이스의 데이터 스트림에 바인드
            this._device.SetStreamSource(0, this._vertexBuffer, 0);

            // 그릴려는 정점의 포맷을 세트
            this._device.VertexFormat = CustomVertex.TransformedColored.Format;

            // 렌더링(그리기)
            this._device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);

            
            // 좌표 x=0 y=0 의 위치에 흰색으로 출력
            this._font.DrawText(null, "정점 버퍼를 사용한 2D 삼각형 출력", 0, 0, Color.White);
            // 화면출력은 여기까지
            this._device.EndScene();

            // 실제의 디스플레이에 출력
            this._device.Present();

        }

        /// <summary>
        /// 자원의 파기
        /// </summary>
        public void Dispose()
        {
            // 정점 버퍼를 해제
            if (this._vertexBuffer != null)
            {
                this._vertexBuffer.Dispose();
            }

            // 폰트 자원을 해제
            if (this._font != null)
            {
                this._font.Dispose();
            }

            // Direct3D 디바이스의 자원 해제
            if (this._device != null)
            {
                this._device.Dispose();
            }
        }
    }
}
 
 
그럼 소스분석을 해보자꾸나
private VertexBuffer _vertexBuffer = null;
정점 버퍼를 사용하려면 VertexBuffer 클래스를 사용하기 때문에 미리 선언해두자
 
this._vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored),
                3, this._device, Usage.None, CustomVertex.TransformedColored.Format, Pool.Managed);
맨 위에서 선언했던 VertexBuffer(정점버퍼클래스)를 사용하자.
 
VertexBuffer
typeVertexType : 사용하는 정점 데이터 구조체의 타입 클래스를 지정, typeof를 사용하여 클래스를 지정한다.
numVerts : 정점의 수, 여기서는 삼각형이니까 3이야
device : Direct3D 디바이스(디바이스 선언해준거 쓰면됭)
usage : 사용법인데, 별거없으면 Usage.Noneㄱㄱ
vertexFormat : 사용하는 정점 데이터 구조체의 정점 포맷을 지정(정점데이터 배열에서 실제적으로 사용할 정점 형식을 말하는거야^^)
pool : 자원을 배치하는 유효한 메모리 클래스의 지정, 별거없으면 pool.Managed
 
 
CustomVertex.TransformedColored[] vertices = new CustomVertex.TransformedColored[3];

// 각 정점을 설정
vertices[0] = new CustomVertex.TransformedColored(
    200.0f, 50.0f, 0.0f, 1.0f, Color.Red.ToArgb());
vertices[1] = new CustomVertex.TransformedColored(
    350.0f, 50.0f + 150.0f * (float)Math.Sqrt(3), 0.0f, 1.0f, Color.Blue.ToArgb());
vertices[2] = new CustomVertex.TransformedColored(
    50.0f, 50.0f + 150.0f * (float)Math.Sqrt(3), 0.0f, 1.0f, Color.Green.ToArgb());
저번 4강때 정점데이터와 같은 내용, 정점구조체 선언하고 삼각형이니까 세개
나머지 인자들은 4강의 내용과 같다.
 
 
  using (GraphicsStream data = this._vertexBuffer.Lock(0, 0, LockFlags.None))
{
    // 정점 데이터를 정점 버퍼에 씁니다
    data.Write(vertices);

    // 정점 버퍼의 락을 해제합니다
    this._vertexBuffer.Unlock();
}
정점데이터를 정점 버퍼에 쓰는 부분.
정점 버퍼에 쓸 때에는 반드시 MUST, 메모리를 잠궈야해
_vertexBuffer.Lock : 이 부분이 바로 정점버퍼를 LOCK하는 부분 이렇게 하면 잠겨진 정점 버퍼를 얻을 수 있다.
Lock인수가 특별한 것이 없다면, 위에처럼 세개(0, 0, LockFlags.None)로도 충분하다.
Write 메서드를 사용해서 메모리에 기록한다. (앞의 data는 GraphicsStream)
그리구 정점버퍼의 락을 해제해야하는데, Lock와 Unlock의 개수는 일치시켜야해, 그렇지 않으면 실패.
using을 명시하고는 있지만, 꼭 그렇게 하지 않아도 되는데, 왠만하면 이렇게 하는게 보기도 좋고 쓰기도 좋겠지요?^^
 
 
// 정점 버퍼를 디바이스의 데이터 스트림에 바인드
this._device.SetStreamSource(0, this._vertexBuffer, 0);
// 그릴려는 정점의 포맷을 세트
this._device.VertexFormat = CustomVertex.TransformedColored.Format;
// 렌더링(그리기)
this._device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
그리기부분이야, 전보다 한줄이 늘었다.
우선,
Device.SetStreamSource 메서드로 사용하는 정점 버퍼를 먼저 지정해. 인자는 저렇게써도 크게 지장없엉
4강에서는 맨 마지막줄이 DrawUserPrimitives였는데, 이번에는 DrawPrimitives야
큰 차이는 없어
DrawPrimitives
primitiveType : 랜더링하는 소스의 타입, 삼각형 하나니까 PrimitiveType.TriangleList
startVertex : 읽어들이는 최초의 정점 인덱스, 통상 0
primitiveCount : 랜더링하는 소스의 갯수, 삼각형 한개니까 1!!