'게임/영상처리'에 해당되는 글 3건
- 2010.05.12 오브젝트를 전체적으로 알파블렌딩 2
- 2010.04.12 지형 텍스쳐 스플래팅의 여러가지 시도
- 2010.04.09 RenderTarget을 활용한 텍스쳐 스플래팅 1
이 효과는 페이드효과등에서도 쓸 수 있고요. 게임에서는 죽은 몬스터가 서서히 없어지는 장면이라든지, 새로 리스폰된 몬스터가 서서히 생기는 장면에 응용할 수 있겠죠.
오브젝트를 전체적으로 알파블렌딩 하는 방법은 여러가지가 있습니다.
첫번째로 버텍스 데이터를 이용하는 방법.
두번째로 메테리얼의 각 컬러부분의 알파값을 이용하는 방법.
세번째로 알파맵을 이용하는 방법.
네번째로 특정 상수로 지정하는 방법등이 있습니다.
첫번째의 경우 간단하지만, 매번 버텍스 버퍼를 Lock을 걸어주는 수고를 감수해야합니다. 게다가 모든 버텍스를 순회해야겠죠.
두번째의 경우는 첫번째보단 빠르겠지만, 어쨌든 각 재질값의 알파부분을 바꿔줘야겠죠. 확실히 첫번째의 경우보다는 간단하진 않지만(?) 매번 Lock을 할 필요는 없어보입니다.
세번째의 경우는 특정 부분만 알파값을 적용할 수 있는 장점은 있지만(이 경우는 첫번째도 마찬가지긴 합니다.) 매번 알파맵을 Lock을 걸어 모든 픽셀을 순회하면서 알파값을 고쳐줘야합니다... 힘들기도 하고.. 느리겠죠. 물론 텍스쳐맵을 매우 작게한다면 효율적이긴 합니다. 하지만 그것은 상수와 다를바가 없다 생각합니다.
마지막으로 특정상수로 지정하는 방법입니다. 중요한건 이 값을 어떻게 전달하느냐가 문제인데요. 간단하게 두가지가 있겠습니다. 다음은 오브젝트를 전체적으로 196(76%)줬을 때, 알파블렌딩 하는 방법입니다.
TFACTOR를 이용한 방법
pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
pDevice->SetRenderState( D3DRS_TEXTUREFACTOR, 0xc4000000 );
pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR );
pDevice->SetTexture( 0, pDiffuseTex );
CONSTANT를 이용한 방법
pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
pDevice->SetTextureStageState( 0, D3DTSS_CONSTANT, 0xc4000000 );
pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_CONSTANT );
pDevice->SetTexture( 0, pDiffuseTex );
하지만, DX도움말에선, 다음과 같이 CONSTANT지원여부에 대한 언급이 있었습니다.
D3DTSS_CONSTANT
Per-stage constant color. To see if a device supports a per-stage constant color, see the D3DPMISCCAPS_PERSTAGECONSTANT constant in D3DPMISCCAPS. D3DTSS_CONSTANT is used by D3DTA_CONSTANT. See D3DTA.
방식을 선택하는 건 전적으로 프로그래머 몫입니다.
'게임 > 영상처리' 카테고리의 다른 글
지형 텍스쳐 스플래팅의 여러가지 시도 (0) | 2010.04.12 |
---|---|
RenderTarget을 활용한 텍스쳐 스플래팅 (1) | 2010.04.09 |
지형 스펙
셀은 셀간격에 맞추어 정렬되어있다.
텍스쳐 스펙
즉, 베이스 텍스쳐가 한장 깔리고, 알파텍스쳐와 스플래팅용 텍스쳐가 각각 알파값이 섞여 깔림
첫번째. 고정파이프라인에서 nPass렌더링
단점 : 렌더링 속도가 느리다. 그외 별다른 특징없음
두번째. 렌더타겟을 활용해서 처음 로딩할 때, 블렌딩된 텍스쳐를 미리 만들어 놓은 후, 렌더링할때 블렌딩된 텍스쳐를 붙임 → 이 부분은 바로 이전글에 포스팅되어있습니다.
장점 : 렌더링 속도가 배우 빠름
단점 : 타일사이즈(셀개수*셀간격)byte * 타일개수 만큼 메모리가 낭비되고, 용량이 크면 클수록 로딩도 길어진다.(만들 때의 시간) 단, 작은 사이즈(타일의 사이즈)를 갖는 지형의 경우에 쓸만할듯
세번째. 알파부분을 하나의 텍스쳐로 합친 뒤, 픽셀 셰이더 처리
장점 : 속도가 두번째보단 느리지만, 첫번째보단 빠르다.
단점 : 알파텍스쳐3장을 한장으로 줄이긴 했지만, 픽셀셰이더 버전에 따른 텍스쳐 개수의 제한에 대한 부담이 따른다. 경우에 따라선 nPass를 피할 수 없음
'게임 > 영상처리' 카테고리의 다른 글
오브젝트를 전체적으로 알파블렌딩 (2) | 2010.05.12 |
---|---|
RenderTarget을 활용한 텍스쳐 스플래팅 (1) | 2010.04.09 |
지형의 텍스쳐 스플래팅을 프로그래밍하다가 어떤 문제에 부딪혔습니다.
텍스쳐 스플래팅의 경우 텍스쳐의 개수만큼 nPass렌더링을 시도하고 있는데요.
여기서 스플래팅이 완료된 지형에 또 다른 처리를 하고 싶을때 어떻게 해야 하는가에 대한 문제였습니다.
이를테면 스플래팅을 완료한 지형에 조명셰이더를 추가한다던지 하는 문제가 있겠죠. 그렇다면, 스플래팅이 완료된 부분의 텍스쳐를 셰이더에 넘겨줘야하는데요. 셰이더에서는 프레임버퍼로 접근할 수가 없습니다.. 그래서
곰곰이 해결책을 생각해본 결과 해당 타일의 크기만큼(3D세계의 크기) 빈텍스쳐를 생성한 후, 그곳을 렌더타겟을 둬서 렌더링한 후, 그 텍스쳐를 셰이더에 넘겨주면 되겠다 싶어서 그대로 실행해보았습니다. 결과는 성공적이었습니다. 하지만 어떤면에선 실패였습니다. (이건 아래)
렌더텍스쳐에 관한 변수가 다음과 같이 있습니다.
LPDIRECT3DTEXTURE9 m_pRTBackBufferTexture = NULL;
LPDIRECT3DSURFACE9 m_pRTBackBuffer = NULL;
LPDIRECT3DSURFACE9 m_pRTDepthBuffer = NULL;
LPDIRECT3DVERTEXBUFFER9 m_pRTVB = NULL;
D3DXMATRIX m_matRTView;
D3DXMATRIX m_matRTProj;
D3DVIEWPORT9 m_RTViewport = { 0, 0, TILE_WIDTH, TILE_HEIGHT, 0, 1 };
여기에서 m_matRTView, m_matRTProj, m_RTViewport 정도는 static으로 함수내부에 선언해도 무방합니다. 항상 고정적인 값을 가지기 때문입니다.
위부터 설명해본다면,
m_pRTBackBufferTexture : 백버퍼의 서피스
m_pRTBackBuffer : 백버퍼 인터페이스
m_pRTDepthBuffer : 깊이버퍼
m_pRTVB : 테스트용 텍스쳐를 렌더링할 사각형(정점이 4개입니다, 삼각형 2개)
m_matRTView : 전용 뷰행렬
m_matRTProj : 전용 프로젝션행렬
m_RTViewport : 전용 뷰포트
아래는 관련변수 초기화 부분입니다.
if( D3DXCreateTextureFromFile( m_pd3dDevice, "texture.bmp", &m_pRTTexture ) )
return E_FAIL;
if( FAILED( m_pd3dDevice->CreateTexture( TILE_WIDTH, TILE_HEIGHT, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pRTBackBufferTexture, NULL ) ) )
return E_FAIL;
if( FAILED( m_pRTBackBufferTexture->GetSurfaceLevel( 0, &m_pRTBackBuffer ) ) )
return E_FAIL;
if( FAILED( m_pd3dDevice->CreateDepthStencilSurface( TILE_WIDTH, TILE_HEIGHT,
D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &m_pRTDepthBuffer, NULL ) ) )
return E_FAIL;
아래는 테스트용 버텍스버퍼 초기화부분입니다. 타일이 셀이 하나도 없을경우 이렇게 그냥 하시면 되겠죠. 하하.. 일반적으로 그냥 타일을 렌더링해주시면 되므로 실제하실땐 아래부분이 필요없으십니다.
{
{ D3DXVECTOR3( -TILE_WIDTH/2, TILE_HEIGHT/2, 0 ), D3DXVECTOR2(0,0) },
{ D3DXVECTOR3( TILE_WIDTH/2, TILE_HEIGHT/2, 0 ), D3DXVECTOR2(1,0) },
{ D3DXVECTOR3( -TILE_WIDTH/2, -TILE_HEIGHT/2, 0 ), D3DXVECTOR2(0,1) },
{ D3DXVECTOR3( TILE_WIDTH/2, -TILE_HEIGHT/2, 0 ), D3DXVECTOR2(1,1) },
};
TexVertex::FVF, D3DPOOL_DEFAULT, &m_pRTVB, NULL)))
{
return E_FAIL;
}
VOID* pRTVertices;
if(FAILED(m_pRTVB->Lock(0, sizeof(rtVertices), (void **)&pRTVertices, 0)))
return E_FAIL;
m_pRTVB->Unlock();
전용 뷰행렬과 프로젝션 행렬이 눈에 띄실텐데, 이 부분을 제대로 해주셔야 합니다.
D3DXMatrixIdentity( &m_matRTView );
D3DXVECTOR3 target( 0.0f, 0.0f, 1.0f );
D3DXVECTOR3 up( 0.0f, 1.0f, 0.0f );
D3DXMatrixLookAtLH( &m_matRTView, &position, &target, &up );
D3DXMatrixOrthoLH( &m_matRTProj, TILE_WIDTH, TILE_HEIGHT, 0, 300 );
카메라를 0,0,0위치시키고 그저 +z방향을 바라보게 합니다. 또한 투영행렬은 직교투영으로 만들어서 왜곡이 일어나지 않게끔 해주어야 합니다. 이렇게 설정하고, 렌더링되는 정점은 Z=0인 부분에서 X, Y값이 각각
-TILE_WIDTH/2~TILE_WIDTH/2 에 -TILE_HEIGHT/2~TILE_HEIGHT/2걸쳐서 렌더링되게 됩니다. (즉, 화면에 꽉찬단 이야기) 그러나 이것은 테스트 소스라 그대로 하시면 안되시구요. 실제 지형에선 아래를 참고해보세요.
일단 위의 버텍스버퍼설정 부분에서도 x,y가 아니구요 x,z쪽으로 타일을 대신할 사각형 정점정보를 두셔야합니다. 그리고 카메라는 원점에서 Y축만 높이값의 최대위치로 올려줍니다. 물론 밑을 향해바라보고 있어야 하구요. 직교행렬또한 원평면의 변화를 보실 수 있으실 겁니다.
D3DXMatrixIdentity( &m_matViewForBlend );
D3DXVECTOR3 position( 0, MAX_HEIGHT_VALUE, 0 );
D3DXVECTOR3 target( 0, 0.0f, 0 );
D3DXVECTOR3 up( 0.0f, 0.0f, 1.0f );
D3DXMatrixLookAtLH( &m_matRTView, &position, &target, &up );
D3DXMatrixOrthoLH( &m_matRTProj, TILE_WIDTH, TILE_HEIGHT, 0, MAX_HEIGHT_VALUE );
다시 돌아가서...
왜 타일의 크기와 딱 맞게 해주어야할까요? 다들 아시겠지만, 텍스쳐는 정점과 정점사이는 텍스쳐의 선형변환으로 이루어지게됩니다.(물론 다는 아닙니다.) 따라서 타일보다 작게 만들어버리면 그만큼 화질이 안좋아지게됩니다. 메모리 부분을 걱정하신다면 적당한 크기로 하셔도 무방합니다.
아랜 렌더링 부분입니다.
m_pd3dDevice->GetRenderTarget( 0, &pOldBackBuffer );
m_pd3dDevice->GetDepthStencilSurface( &pOldZBuffer );
m_pd3dDevice->GetViewport( &oldViewport );
// 렌더링 타겟을 변경한다.
m_pd3dDevice->SetRenderTarget( 0, m_pRTBackBuffer );
m_pd3dDevice->SetDepthStencilSurface(m_pRTDepthBuffer);
m_pd3dDevice->SetViewport( &m_RTViewport );
// 렌더링 타겟 전용 행렬로 세팅합니다.
// 카메라가 0,0,0에 위치하고 있고 0,0,1을 바라보고 있고요,
// TILE_WIDTH/TILE_HEIGHT의 크기로 직교투영중에 있습니다. 근평면은 0입니다.
// 또한 정점들은 Z축값이 0이며 X, Y값은 각각 -TILE_WIDTH/2~TILE_WIDTH/2 에
// -TILE_HEIGHT/2~TILE_HEIGHT/2걸쳐서 렌더링되게 됩니다.
// 따라서 화면을 꽉차는 텍스쳐가 렌더링됩니다.
// 테스트 소스에는 없지만, 타일들을 원점으로 옮겨질 수 있도록 월드행렬을 세팅해줘야합니다.
m_pd3dDevice->SetTransform( D3DTS_VIEW, &m_matRTView );
m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &m_matRTProj );
// 반드시 해주셔야합니다. 렌더타겟으로 지정되어있는 텍스쳐와 그의 깊이버퍼를 클리어해줍니다.
// 물론 한사이클에 한번씩 클리어 해주셔야 합니다.
// 즉, 베이스 텍스쳐 - 알파텍스쳐 - 조명셰이더 순으로 하신다면
// 렌더타겟(텍스쳐)클리어 - 베이스 텍스쳐 - 알파텍스쳐 - 렌더타겟(프레임버퍼)클리어 - 조명셰이더
m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
// 불러온 텍스쳐를 렌더타겟에 렌더링한다.
m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
m_pd3dDevice->SetTexture( 0, m_pRTTexture );
m_pd3dDevice->SetFVF( TexVertex::FVF );
m_pd3dDevice->SetStreamSource( 0, m_pRTVB, 0, sizeof(TexVertex) );
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
알파옵션켜고 렌더링..
또 렌더링...
이걸 가지고 셰이더코드에 넣어주시면 되겠습니다.
다음은 합성된 텍스쳐를 임의의 사각폴리곤에 렌더링하는 부분입니다.
m_pd3dDevice->SetRenderTarget( 0, pOldBackBuffer );
m_pd3dDevice->SetDepthStencilSurface( pOldZBuffer );
m_pd3dDevice->SetViewport( &oldViewport );
// 반드시 릴리즈 해줘야한다.
pOldBackBuffer->Release();
pOldZBuffer->Release();
m_pd3dDevice->SetTransform( D3DTS_VIEW, &m_matView );
m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &m_matProj );
m_pd3dDevice->SetTexture( 0, m_pRTBackBufferTexture );
m_pd3dDevice->SetFVF( TexVertex::FVF );
m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(TexVertex) );
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );
다음은 위 코드의 실행화면을 캡쳐한 사진입니다.
결론
허나 큰 맵의 경우 메모리를 너무 많이 차지하기때문에 로딩하다가 결국 가상메모리까지 들어가게되는 일이 발생할수도 있습니다.(2기가까지 넘어가는거보고 강제종료해버렸음) 따라서 더블버퍼링으로 실시간으로(카메라의 프러스텀이 닿기 바로 직전의 타일들) 블렌딩하시던지 어떤 대책을 취하셔야합니다. 그게 아니라면 그냥 멀티텍스쳐로 하시는게 나으시겠죠.
하지만 작은 맵의 경우 메모리를 덜 차지하기 때문에 충분히 고려해볼 대상입니다.
그림자처리등으로 멀티패스로 렌더링할때도 조금이나마 부담을 덜어줄 수도 있으니까요.
아니 많은 부담을 덜어줄 수 있습니다.^^
읽어주셔서 감사합니다.
'게임 > 영상처리' 카테고리의 다른 글
오브젝트를 전체적으로 알파블렌딩 (2) | 2010.05.12 |
---|---|
지형 텍스쳐 스플래팅의 여러가지 시도 (0) | 2010.04.12 |