제 질문에 대한 감자닷넷의 감자님의 답변입니다.
---------------------------------------------

질문] 3D스프라이트에서 텍스쳐 영역...

안녕하세요? 벌날개입니다.

직교투영행렬을 이용해서 D3DX의 ID3DXSPRITE 와 같은 기능을 구현하고 있습니다.
대부분 잘 작동하는데...

텍스쳐의 일부 RECT영역만 출력하게 하는 걸 구현했습니다.

RECT를 얻어서 버텍스버퍼를 다시 설정해주었습니다.
일단 기능은 잘 작동하는데...
이 함수가...
D3DX의 ID3DXSPRITE에서 텍스쳐영역을 바꾸는 것보다 10프레임 정도 느리더군요...
다음은 제가 작성한 SETRECT함수입니다.
왜 D3DX 것보다 10프레임정도가 느릴까요? 다른 조건은 전부 같게 한다음 실험했습니다만...

void C3DSprite::SetRectEx(int _Left, int _Top, int _Right, int _Bottom)
{
                // RECT영역이 전과 같다면 무시한다.
if( m_Rect.left!=_Left || m_Rect.top!=_Top || m_Rect.right!=_Right || m_Rect.bottom!=_Bottom )
{
  int _Width  = _Right-_Left; // 영역의 가로길이
  int _Height = _Bottom-_Top;          // 영역의 세로길이
  FLOAT _tu1 = (FLOAT)_Left/m_nWidth;
  FLOAT _tu2 = (FLOAT)_Right/m_nWidth;
  FLOAT _tv1 = (FLOAT)_Top/m_nHeight;
  FLOAT _tv2 = (FLOAT)_Bottom/m_nHeight;

  // 버퍼설정
  SPRITEVERTEX* Vertex;
  m_pVB->Lock( 0, 0, (VOID**)&Vertex, 0 );

  Vertex[0].p = D3DXVECTOR3( float(m_nX)-0.5f, float(m_nY)-0.5f, 0.0f );
  Vertex[0].tu=_tu1; Vertex[0].tv=_tv1;
  Vertex[1].p = D3DXVECTOR3( float((m_nX-0.5f)+_Width) , float(m_nY-0.5f), 0.0f );
  Vertex[1].tu=_tu2; Vertex[1].tv=_tv1;
  Vertex[2].p = D3DXVECTOR3( float(m_nX)-0.5f, float((m_nY - 0.5f)+_Height), 0.0f );
  Vertex[2].tu=_tu1; Vertex[2].tv=_tv2;
  Vertex[3].p = D3DXVECTOR3( float((m_nX-0.5f)+_Width)  , float((m_nY-0.5f)+_Height), 0.0f );
  Vertex[3].tu=_tu2; Vertex[3].tv=_tv2;
  
  m_pVB->Unlock();

}
}

LOCK과 UNLOCK에서 오버헤드가 발생하는건 맞는데... LOCK과 UNLOCK을 안하고 텍스쳐 영역을 바꾸는 다른 방법이 있을까요?

답변>
3D로 2D그릴때 Lock 없이 하기.

방법이 있긴 있습니다.
최적화를 고려한다면, 우선 2D를 그리기 전에 해주어야 할것들이 좀 있습니다.
저는 Begin2D(), End2D() 따위를 만들어 쓰시는걸 권하고 싶네요.

o. 직교투영행렬을 설정. ( 월드변환행렬은 단위행렬로 초기화 )    
( 나중에 오픈지엘로의 변환을 고려한다면 -0.5를 직교투영행렬에 포함시키는게 바람직하다 )

o. Vertex format을 설정    
struct CUSTOMVERTEX    {     
   D3DXVECTOR3 position; // The position    };    
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ)        
g_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );

o. 버텍스버퍼를 만들고 좌표가 (0,0)-(1,1)인 사각형으로 초기화.   
 (이건 그냥 어플초기화시 하나만들어 두시는게 낳을지도...)
o. SetStreamSource을 사용해 위에서 초기화한 버텍스 버퍼를 사용하도록 설정  
  (이제부터 모든 2D는 이 버텍스버퍼하나로 다 처리할겁니다.)
o. 텍스쳐 변환행렬을 사용한다는것을 알려줌    
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION );    
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
실제 렌더링은 아래처럼 하면 됩니다.

    g_pd3dDevice->SetTransform( D3DTS_VIEW, &m_PositionMatrix );
    g_pd3dDevice->SetTransform( D3DTS_TEXTURE0, &m_TextureMatrix );
    g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN , 0,2 );

텍스쳐 영역이 바뀔때마다 하는 SetRectEx 함수는...
void C3DSprite::SetRectEx(int _Left, int _Top, int _Right, int _Bottom)
{    // RECT영역이 전과 같다면 무시한다.
    if( m_Rect.left!=_Left || m_Rect.top!=_Top ||
        m_Rect.right!=_Right || m_Rect.bottom!=_Bottom )
    {   int _Width  = _Right-_Left; // 영역의 가로길이
        int _Height = _Bottom-_Top; // 영역의 세로길이
        FLOAT _tu = (FLOAT)_Left/m_nWidth;
        FLOAT _tv = (FLOAT)_Top/m_nHeight;
        FLOAT _tw = (FLOAT)_Width/m_nWidth;
        FLOAT _th = (FLOAT)Height/m_nHeight;
                //m_PositionMatrix,m_TextureMatrix 는 D3DXMATRIX 입니다.
        D3DXMatrixScaling( &m_PositionMatrix, _Width,_Height,1 );
        m_PositionMatrix._41 = m_nX; // -0.5는 직교투영행렬에 넣었다고 가정합니다.
        m_PositionMatrix._42 = m_nY;
        D3DXMatrixScaling( &m_TextureMatrix, _tw,_th,1 );
        m_TextureMatrix._41 = _tu;
        m_TextureMatrix._42 = _tv;
        D3DXMATRIX _inv_view;
        D3DXMatrixInverse( &_inv_view, NULL, &m_PositionMatrix );//이것도 최적화가 가능하지만 일단은 이해하기 좋게...
        D3DXMatrixMultiply( &m_TextureMatrix, &_inv_view, &m_TextureMatrix );    }}

속도차가 얼마나 나는지 테스트 결과좀 올려주셨으면 감사하겠습니다.
빨라지긴 하는건지...
일단 Lock이 빠지고 버텍스버퍼도 달랑 한개만 계속 재사용하고 하니...좀 낳아지지 않을까 싶네요.

감자 성수올림...@~

PS. 버텍스버퍼에 Lock을 안걸려면 버텍스버퍼에 색상을 넣을수가 없습니다.
이럴땐 Begin2D 같은데서
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TFACTOR );
이렇게 설정하시고, 실제 렌더링할때
g_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, color );
이렇게 해주면되죠. 다만...SetRenderState를 자주 호출하는게 좀 껄끄럽네요.