텍스쳐 렌더링


 텍스쳐에 렌드링하는 방법에 대해서 설명하겠습니다.  사용 용도는 TV, 레이싱 게임의 백 미러, MMORPG 게임의 캐릭터 창에 나오는 캐릭터등에 활용 할 수 있습니다.

<텍스쳐 렌더러와 표면의 차이점>

1. 렌더러
CreateTexture() 생성시D3DUSAGE_RENDERTARGET를 이용하여 생성
장점: 렌드링 결과물을 텍스쳐로 사용
단점: 락을 걸어 수정하거나 읽는게 불가능, (CPU 연산 불가)

2
CreateRenderTarget()을 이용하여 생성
장점: 렌더링 결과를 CPU상에서 락을 걸고 읽는게 가능.
단점: 표면은 텍스쳐로 사용 불가. 최종 결과물이거나 락을 걸어 사용할 용도로 적당.

Tutorial04를 기본으로 하여 추가되거나 수정된 사항에 대해 설명하겠습니다.

<사용 방법>

1. 텍스쳐 선언

IDirect3DTexture9*  g_pRenderTexture = NULL;
IDirect3DSurface9*  g_pSurface = NULL;
IDirect3DSurface9*  g_pBackBuffer = NULL;
//버텍스 구조체와 타입 선언
struct CUSTOMVERTEX { FLOAT x, y, z, rhw; DWORD color; FLOAT u, v;};
#define D3DFVF_CUSTOMVERTEX ( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
LPDIRECT3DVERTEXBUFFER9 g_VertexBuffer = NULL; // our VertexBuffe

비디오 메모리를 텍스쳐로 사용하기 위해서 g_pRenderTexture를 선언 합니다,
비디오 메로리로 선언한 텍스쳐의 표면을 가져오기 위해 g_pSurface를 선언합니다.
원래의 표면으로 타겟을 설정하기 위해 g_pBackBuffer를 선언합니다.

텍스쳐를 보여주기 위해 CUSTOMVERTEX 구조체와 D3DFCF_CUSTOMVERTEX와 g_VertexBuffer를 선언합니다.

그리고  RenderInit() 함수에서 2D 화면으로 렌더러 텍스쳐를 보여주기 버텍스 버퍼를 생성합니다.

        CUSTOMVERTEX g_Vertices[] =
        {
                {  20.0f,  20.0f, 0.0f, 1.0f, 0xffffffff, 0.0f, 0.0f,},
                { 150.0f,  20.0f, 0.0f, 1.0f, 0xffffffff, 1.0f, 0.0f,},
                {  20.0f, 150.0f, 0.0f, 1.0f, 0xffffffff, 0.0f, 1.0f,},
                {  20.0f, 150.0f, 0.0f, 1.0f, 0xffffffff, 0.0f, 1.0f,},
                { 150.0f,  20.0f, 0.0f, 1.0f, 0xffffffff, 1.0f, 0.0f,},
                { 150.0f, 150.0f, 0.0f, 1.0f, 0xffffffff, 1.0f, 1.0f,},
        };

        g_d3d_Device->CreateVertexBuffer (6*sizeof(CUSTOMVERTEX), 0,                 D3DFVF_CUSTOMVERTEX,
                D3DPOOL_MANAGED,
                &g_VertexBuffer, NULL);

        VOID* pVertices;
        g_VertexBuffer->Lock (0, sizeof(g_Vertices), &pVertices, 0);
        memcpy (pVertices, g_Vertices, sizeof(g_Vertices));
        g_VertexBuffer->Unlock();

 

2D 화면으로 보여줄 때는 밉맵이 필요없습니다. 그래서, D3DSAMP_MIPFILTER옵션을 D3DTEXF_NONE으로 설정합니다

    g_d3d_Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE

2. 렌더러 텍스쳐 생성

D3DUSAGE_RENDERTARGET옵션을 주고 텍스쳐를 생성합니다
렌더타겟으로 생성한 텍스쳐는 D3DPOOL_DEFAULT로만 만들어야 합니다.
또한 텍스쳐의 락이 불가능합니다.(물론 IDirect3DDevice9::UpdateSurface(), IDirect3DDevice9::UpdateTexture()를 사용하는 방법이 있습니다.)
텍스쳐 표면을 얻어오고, 렌더링 할 때, 원래 표면으로 복구하기 위해 백버퍼를 얻어 옵니다.

        g_d3d_Device->CreateTexture(256, 256, 0,
                      D3DUSAGE_RENDERTARGET,
                      D3DFMT_A8R8G8B8,
                      D3DPOOL_DEFAULT,
                      &g_pRenderTexture, NULL);
        g_pRenderTexture->GetSurfaceLevel(0, &g_pSurface);        
        g_d3d_Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &g_pBackBuffer);

3. 렌더러 텍스쳐의 렌더링

화면 중앙에 박스가 회전하고 있고 왼쪽 상단에 박스하나가 회전하고 있습니다.
왼쪽 상단의 박스는 렌더러 텍스쳐를 이용해서 화면에 2D로 그려주고 있습니다.

외쪽 상단의 박스를 그리는 순서는 다음과 같습니다.

        1. 렌더 타겟으로 표면 설정한다.
            :렌더 타겟으로 렌더러 텍스쳐의 표면으로 설정하고 표면을 클리어 합니다.

        2. 렌더 타겟의 표면에 그린다.
            :렌더 타겟에 박스를 그립니다.

        3. 렌더 타겟의 텍스쳐를 2D로 백버퍼에 그린다.
            :백버퍼 표면으로 타겟을 설정한후에 2D 화면으로 렌더 텍스쳐를 그립니다.

 //1. 렌더 타겟으로 표면 설정한다.
g_d3d_Device->SetRenderTarget(0, g_pSurface);
hr = g_d3d_Device->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

 //2. 렌더 타겟의 표면에 그린다.
for(int i = 0; i < g_nNumSubsets; i++)
{
       g_d3d_Device->SetTexture( 0, g_pTextures[i] );
       g_pMesh->DrawSubset( i );
}

//3. 렌더 타겟의 텍스쳐를 2D로 백버퍼에 그린다.
g_d3d_Device->SetRenderTarget(0, g_pBackBuffer);
g_d3d_Device->SetFVF (D3DFVF_CUSTOMVERTEX);
g_d3d_Device->SetStreamSource (0, g_VertexBuffer, 0, sizeof(CUSTOMVERTEX));
g_d3d_Device->SetTexture(0, g_pRenderTexture);
g_d3d_Device->DrawPrimitive (D3DPT_TRIANGLELIST, 0, 2);
g_d3d_Device->SetTexture(0, NULL);

4. 리소스 해제
사용 했던 렌더러 텍스쳐 리소스를 DestroyDirect3D()에서 해제 합니다.

_RELEASE_<IDirect3DSurface9*>(g_pBackBuffer);
_RELEASE_<IDirect3DSurface9*>(g_pSurface);
_RELEASE_<IDirect3DTexture9*>(g_pRenderTexture);
_RELEASE_<LPDIRECT3DVERTEXBUFFER9>(g_VertexBuffer)
;

다음장에서는 표면을 이용하여 그리는 방법에 대해서 애기하겠습니다.

- 2006.11.22 dolphin -