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

+ Recent posts