Z-Fighting
1. 깊이 버퍼의 크기를 16Bit로 되어 있으면 24Bit로 사용한다.
깊이 버퍼의 대역을 늘려줌으로써, 수용 가능한 좌표계를 늘린다.
D3DParams.AutoDepthStencilFormat = D3DFMT_D24S8;
D3DParams.EnableAutoDepthStencil = TRUE;
2. 좌표계를 작게 사용한다.
위와 같은 맥락으로, Z버퍼는 한정적인데, 무한하게, 맵을 키울경우 Z- Fighting이 발생하기 때문에,
애초에 좌표계를 너무 큰 것을 사용하지 않는 것이 좋다.
쉽게 얘기하면, 맵을 mm로 기준 단위로 나눈다든지.
너무 큰 맵을 사용한다든지,(물론 기준 단위도 크면 상관없지만,)
그러면 나중에 Z들끼리 싸우는 수준이 아니라, 정말 Z와 Fighting하여야 한다.
3. NearZ - FarZ(Z투영 밀어내기)
정상적인 방법이라기 보다는,
사실 Z-Fighting에서 정상적인 방법은 1번,2번까지다. 1번,2번의 한계를 넘으면 발생하는 것이 Z-Fighting이니까..
d3dx9math.h
// Build a perspective projection matrix. (left-handed)
D3DXMATRIX* WINAPI D3DXMatrixPerspectiveFovLH ( D3DXMATRIX *pOut, FLOAT fovy, FLOAT Aspect, FLOAT zn, FLOAT zf );
Perspective 위 함수 단어에서도 알 수 있듯이, 원근이다. 이 원근값은 NearZ - FarZ를 기초로 해서, 행렬을 만들게 된다.
이 투영 행렬을 살짝 변경 시켜서, Z-Fighting을 일으키는 오브젝트를 투영된 화면 속에서 살짝 밀어내는 방법이다.
D3DXMATRIX mProjMat; // 현재 투영 행렬 저장
D3DXMATRIX mZBiasedProjMat; // ZBias 적용된 투영행렬 저장
float g_fNearClip = 1.0f; // 투영 행렬 제작 시 사용될 기본 NearClip값
float g_fFarClip = 100.0f; // 투영 행렬 제작 시 사용될 기본 FarVisuality값
float g_fNearClipBias = 0.0f; //투영을 살짝 변경 시킬 때 사용될 NearClip값
float g_fFarClipBias = 0.5f; //투영을 살짝 변경 시킬 때 사용될 FarVisuality값
// 투영 행렬은 렌더링 함수 외부에서 계산을 수행할 때 가장 혼동이 적다.
D3DXMatrixPerspectiveFovLH( &mZBiasedProjMat, D3DX_PI/4,(mProjMat._22/mProjMat._11),
g_fNearClip + g_fNearClipBias,
g_fFarClip + g_fFarClipBias );
// 원래 투영 행렬 로드시킴
m_pd3dDevice ->SetTransform( D3DTS_PROJECTION, & mProjectionMat);
뒤에 그려질 오브젝트를 그려주자.
// 살짝 변경된 투영을 셋트시킨다.
m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mZBiasedProjectionMat);
앞에 그려질 오브젝트를 그려주자.
// 원래 투영 로드됨...
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, & mProjectionMat);
결국 두 오브젝트는 겹쳐 있으면서도 Z버퍼로 다른 값을 가지게 되기 때문에, Z-Fighting 현상이 해결된다.
이 방식은 모든 그래픽 카드에서 적용되기 때문에, 매우 유용하다.
4. NearZ - FarZ(잘못됐지만, 적당히 넘어가기 좋은 방법)
물론 처음부터 각잡고 개발한 경우에는 이런 경우가 없지만, 항상 예외의 상황은 있는 법.
예를 들면 어떤 모듈 Dll을 사용하고, 그 Dll에서 Rendering을 하는데,
어떤 놈이 만들었는지 모르겠지만, Z-Fighting이 신나게 발생한다. 이미 그 개발자는 사라지고 없다.
내부적으로 Rendering에 어떤 제어를 전혀 할 수 없는 상황이다.(개발자에게는 참 여러가지 상황이 닥치지요.)
이럴 때, 사용하기 좋은 법이라 할 수 있다.
Z-Fighting이 줄어 들 때까지, NearZ를 줄여나간다. 물론 너무 많이 줄이면 중간에 구멍이 생기기 때문에,
한계가 있는 방법이지만,
24bit일 때 FarZ가 10만 이하 정도라면, 티도 안나게 Z파이팅을 해결 될 수도 있다.
이렇게까지 해도, 안 잡히면, 그때는 말로 풀자 -.-.
5. ViewPort
3번과 같은 맥락이다. 다만 이미 만들어진 ViewPort를 약간 변경 시킬 뿐이다.
D3DVIEWPORT9 mViewPort; // 현재 뷰포트 저장
D3DVIEWPORT9 mNViewPort; // 새로운 뷰포트 저장
// 뷰포트 변경을 의해 사용될 값
// 1의 ZBIAS 값을 강제 연산 MinZ - 256/(2^24-1), MaxZ - 256/(2^24-1)
// 2^24 는 설정한 Z버퍼,
//256은 Intel (R) Integrated Graphics 나타낸다. 16의 배수라면 어떤 것이라도 상관없다.
float g_fViewPortBias = 0.0000152588f;
//기존 ViewPort저장
m_pd3dDevice->GetViewport(&mViewport);
// 기존 ViewPort를 mNewViewport에 복사.
mNewViewport = mViewport;
// bias 적용
mNewViewPort.MinZ -= g_fViewportBias;
mNewViewPort.MaxZ -= g_fViewportBias;
// 기존 뷰포트 셋팅
m_pd3dDevice->SetViewport(&mViewport);
후면에 그릴 것
// 새로운 뷰포트 셋팅
m_pd3dDevice->SetViewport(&mNewViewport);
앞면에 그릴 것
// 기본 뷰포트 셋팅
m_pd3dDevice->SetViewport(&mViewport);
6. Depth Bias.
Z-Fighting해결법 중에 가장 형식 있어 보이지만, 그래픽 카드에서 지원을 해줘야 한다. Caps로 먼저 확인하자.
방식은 D3DRS_SLOPESCALEDEPTHBIAS 및 D3DRS_DEPTHBIAS 렌더 옵션을 가지고, 적당히 offset을 주면,
Z-Fighting을 그래픽 카드에서 핸들을 알아서 해준다.
물론 내부적으로 어떻게 움직이는지는 알 수가 없고, 추측만 난무할 뿐이다.
BOOL m_bDepthBiasCap; // 장치가 DepthBias 기능을 가지고 있으면 TRUE
// Depth Bias 가 사용하는 전역 변수
float g_fSlopeScaleDepthBias = 1.0f;
float g_fDepthBias = -0.0005f;
float g_fDefaultDepthBias = 0.0f;
// 새로운 depth bias 기능을 지원하는지 검사
if ((pCaps->RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS) &&
(pCaps->RasterCaps & D3DPRASTERCAPS_DEPTHBIAS))
{
m_bDepthBiasCap = true; // DepthBias 기능이 있다면 TRUE
}
// 빌보드 렌더링됨 ...
// DepthBias 적용됨
if ( m_bDepthBiasCap ) // DepthBias가 지원된다면 TRUE
{
// z-fighting 을 줄이기 위해서 평면상의 프리미티브에
// bias 가 적용될 크기를 결정하기 위해서 사용됨
// bias = (max * D3DRS_SLOPESCALEDEPTHBIAS) + D3DRS_DEPTHBIAS,
// 여기에서 max 는 렌더링되는 삼각형의 최대 깊이 기울기(slope) 이다.
// (역주 : F2DW 는 float 을 DWORD 처럼 읽기 위한 매크로)
m_pd3dDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS,
F2DW(g_fSlopeScaleDepthBias));
m_pd3dDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW(g_fDepthBias));
}
// 포스터가 렌더링된다...
if ( m_bDepthBiasCap ) // DepthBias 가 지원된다면 TRUE
{
// DepthBias 적용한다.
// 그것을 다시 0(기본값)으로 설정한다.
m_pd3dDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS,
F2DW(g_fDefaultDepthBias));
m_pd3dDevice->SetRenderState(D3DRS_DEPTHBIAS,
F2DW(g_fDefaultDepthBias));
}
[출처] Z-Fighting - Handle|작성자 인생의CORE
'수학 (Mathematics) > 3D수학' 카테고리의 다른 글
라디오시티 (0) | 2012.11.02 |
---|---|
에르미트 (0) | 2012.11.02 |
직교투영 확대 축소 (0) | 2012.11.02 |
폴리곤중간의 텍스처 좌표 구하기 (0) | 2012.11.02 |
[D3DX] Vertex Normal (0) | 2012.11.02 |