글수 39
제 질문에 대한 감자닷넷의 감자님의 답변입니다.
---------------------------------------------
질문] 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를 자주 호출하는게 좀 껄끄럽네요.
---------------------------------------------
질문] 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를 자주 호출하는게 좀 껄끄럽네요.
