정점 버퍼

2022. 8. 14. 21:57Public/GraphicsAPI

    /// 삼각형을 렌더링하기위해 세개의 정점을 선언
    CUSTOMVERTEX vertices[] =
    {
        { 150.0f,  50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color
        { 250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },
        {  50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },
    };

3차원 공간의 x,y,z 값과 rhw 값, 그리고 각 정점마다 다른 색을 할당하고 있다. 색의 경우 

0xAARRGGBB의 순서로 값을 주게 되는데, 다음과 같다.

A : Alpha 값으로 0x00 ~ 0xff 값을 갖는다.

R,G,B : Red,Green,Blue의 값으로 0x00 ~ 0xff 값을 가질 수 있다.

 

이제부터 설명하는 정점 버퍼(vertex buffer)는 D3D에서 가장 중요한 개념 중 하나며, 하드웨어 가속을 위해서는 반드시 사용해야 하는 것이므로 잘 알아 두도록 하자.

 

일단 정점 버퍼란 정점을 모아두는 일종의 메모리라고 보면 된다.

이 메모리가 단순한 배열이나 new , malloc() 등에 의한 메모리와 구별되는 것은 정점 처리만을 위해 만들어진 특수한 메모리이기 때문에 훨씬 효율적이라는 것이다. 정점 버퍼는 크게 두 가지의 메모리를 사용하는데, 비디오 메모리와 시스템 메모리다. 

 

비디오 메모리에 생성된 정점 버퍼는 비디오 카드의 GPU(Graphic Processing Unit)에 의해서 정점 셰이더, T&L 등의 강력한 하드웨어 가속을 사용할 수 있지만, 비디오카드 자체의 메모리 용량을 벗어날 수는 없다. 게다가 텍스처와 함께 사용해야 하기 때문에 사용 가능한 메모리는 더욱 적을 수밖에 없는 것이다. 이에 반해 시스템 메모리에 생성되는 정점 버퍼는 T&L등의 강력한 하드웨어 가속은 사용할 수 없지만, 풍부한 용량으로 상대적으로 많은 정점 버퍼를 관리할 수 있다. 

물론 정점 버퍼 외에도 배열을 사용하여 직접 정점을 관리하는 것도 가능하지만 이런 경우는 매우 특별한 경우에 해당한다.

 

 

 

정점 버퍼의 생성

    if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3*sizeof(CUSTOMVERTEX),
                                                  0, D3DFVF_CUSTOMVERTEX,
                                                  D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
    {
        return E_FAIL;
    }

 

CreateVertexBuffer( ) 함수가 정점 버퍼를 생성하는 함수다.

Length - 생성할 정점 버퍼의 바이트 단위 크기

Usage - 정점 버퍼의 종류, 혹은 처리방식(SH,SW) 지정

FVF - 정점 정보 구조체에 다라 선언된 FVF 프래그 값

Pool - 정점 버퍼가 저장될 메모리의 위치(비디오카드,시스템 메모리)와 관리방식 지정

ppVertexBuffer - 반환될 정점 버퍼의 인터페이스

pSharedHandle - 예약되었음, 현재는 무조건 NULL값.

 

 

해당 예제의 경우 3개의 정점을 처리하는 정점 버퍼를 비디오 카드에 생성하여 g_pVB에 보관한다.

일단 생성한 정점 버퍼는 쓰레기 값으로 가득 차 있기 때문에 값을 넣어줘야 한다. 그러기 위해서는 Lock() 을 사용해서 메모리 포인터를 얻어내야 한다.

 

OffsetToLock - Lock을 할 버퍼의 시작점, SizeToLock과 함께 양쪽 모두 0이면 전체 버퍼

SizeToLock - Lock을 할 버퍼의 크기, OffsetToLock과 함께 양쪽 모두 0이면 전체 버퍼

PpbData - 읽고 쓸 수 있게 된 메모리 영역의 포인터

Flags - Lock을 수행할 때 함께 사용하는 플래그

 

 

우리가 CreateVertexBuffer( )로 생성한 정점 버퍼는 정확히 말해서 정점 버퍼의 인터페이스다. 이 인터페이스의 Lock()이라는 함수를 사용해서 실제 정점을 읽고 , 쓸 수 있는 메모리 포인터를 얻어내야 한다. 일단 Lock()으로 얻어진 ppbData 포인터는 일반 메모리처럼 마음대로 사용할 수 있다. 이때 주의할 것은 정점 버퍼를 비디오 메모리에 생성한 경우 읽기 동작은 정상적으로 수행되지 않을 수도 있다는 것이다. 그리고 정상적으로 수행된다고 하더라도 PCI-Express 등의 슬롯을 통해서 접근해야 하기 때문에 매우 느리다. 따라서 정점 버퍼의 값을 읽어오는 것은 가능하면 하지 않는것이 좋다.

 

다음의 함수 호출이 정점 버퍼에 정보를 쓰는 과정을 나타낸다.

 memcpy( pVertices, vertices, sizeof(vertices) );
    g_pVB->Unlock();

 

여기서 사용자들이 주의할 것은 Lock()을 수행한 정점 버퍼는 반드시 UnLock()을 호출해 주어야 한다는 것이다. Unlock()을 하지 않을 경우 그래픽카드가 다운될 수 있다. 즉, Lock() 과 Unlock()은 한 쌍으로 조합해서 사용해야 한다.

이상과 같은 과정을 거치면 정점 버퍼를 생성하여 사용할 준비가 완료된 것이다. 이제 남은 것은 정점 버퍼의 내용을 화면에 그리는 일 뿐이다.

 

'Public > GraphicsAPI' 카테고리의 다른 글

행렬 01  (0) 2022.08.15
그리기 (Render)  (0) 2022.08.14
FVF  (0) 2022.08.14
일반적인 WIN32 구조와 D3D 비교  (0) 2022.08.10
삼각형  (0) 2022.08.06