블로그 이미지
자신의 단점을 메꾸는 것을 단(鍛)이라 하고 자신의 강점을 갈고 닦는 것을 련(鍊)이라 하여, 두가지를 합친 것을 단련이라고 부른다. 붕대마음

카테고리

전체목록 (657)
참고사이트 (8)
Goal (4)
Travel (10)
My Life (99)
Game (35)
Game Review (7)
Game Plan (0)
Books (5)
English (1)
Optimizing (12)
Study (214)
유용한 것들_etc (44)
유용한 것들_func (20)
Unity (48)
Unreal (87)
작업장 (54)
RenderMonkey (6)
정리요망 (1)
따라잡기 시리즈 (0)
링크용 (0)
Total333,073
Today61
Yesterday50

Z 충돌 이슈를 수정하기 위해

 

 Z 바이어스를 사용하는 것에 대한 대안들

 

 

소개

 

By Matt McClellan and Kipp Owens

 

3D 응용프로그램 내에는 두 개의 폴리곤들이 같은 평면 상에 놓여 있는 많은 인스턴스들이 존재한다. 예를 들면 총알 자국이나 벽의 포스터와 같은 이펙트의 경우이다. 이런 폴리곤들은 같은 평면상에 놓여 있기 때문에 그것들은 같은 z-buffer 값을 공유하며, 이것은 "z-fighting" 이슈를 발생시킬 수 있다. 이것은 렌더링 순서에 의해서 다양하게 나타날 수 있다. 과거에는 DirectX* 가 개발자가  "z-bias" 를 동일 평면상의 폴리곤에 적용할 수 있게 함으로써 z-fighting 이슈를 해결할 수 있게 해 주었다. z-bias 를 적용하는 것은 효율적인 해결책이기는 하지만 그것은 모든 그래픽 하드웨어 상에서 같은 결과를 산출하지는 않는다.

 

운나쁘게도 DirectX9 이전 버전에서는 그래픽 카드 제조사들이 z-bias 기능에 대한 DirectX 의 세부 명세를 서로 다르게 해석했다. 그 결과 그래픽 카드 제조사들은 z-bias 를 사용하는 응용프로그램을 다루기 위해 각자 약간 다른 알고리즘을 적용하게 되었다. 그런데 이 보다 문제는 이들 서로 다른 드라이버들의 행동들을 고려하는 응용프로그램들이 많이 생겨났다는 것은 서로 다른 하드웨어 제조사들이 좀더 일관된 행동을 위해 드라이버를 지속적으로 변경하지 않을 것임을 의미했다(원문 : Worse, a legacy of applications taking these different driver behaviors into account meant that the different hardware vendors could not subsequently change their driver behaviors to be more consistent).

 

개발자 커뮤니티에 있어서 이러한 불확실성은 z-bias 값에 대한 많은 사용자 정의 '변경(tweaking)'을 유발했고, 다양하고 광범위한 하드웨어에서 연속적으로 테스트를 하게 만들었다; 요약하면 각 하드웨어는 서로 다르게 행동할 것이다. Microsoft 는 DirectX9 에서 z-bias 를 "depth-bias"로 변경함으로써 이 문제를 해결했다. 그들은 z-figting 이슈를 제거하기 위한 더욱 예측 가능하고 단일한 기법을 제공하기를 원했다.

 

DirectX 8 이전의 버전에서는 D3DRS_ZBIAS 렌더링 상태가 사용되었지만, DirectX 9 에서는 D3DRS_DEPTHBIAS 렌더링 상태가 사용된다. 이 기사는 D3DRS_ZBIAS 로부터 기원한 세 가지 대안에 대해 약술한다(원문 : This article outlines three alternatives to using the legacy method of D3DRS_ZBIAS).

 


Figure 1. 동일 평면상의 폴리곤에서의 z-fighting
 
위의 Figure 1 은 동일 평면상의 폴리곤에서의 z-fighting의 영향을 보여 준다. ZFightingDemo 는 Billoard 를 수정한 버전인데, DirectX SDK 에서 찾아볼 수 있으며 이는 z-fighting 에 대해서 설명한다.
 
대안 기법 1 : 투영 행렬
 
 
여기에서 다루는 첫 번째 기법은 새로운 투영 행렬의 사용이다. 이 새로운 투영행렬은 (관찰자에서 멀어지는 방향으로) 밀어 내어 지는 가까운 절단면 및 먼 절단면과 함께 로드된다. 새로운 'closer' 투영 행렬은 'far' 오브젝트 후에, 그리고 개발자가 전면에 나타나게 하고자 하는 오브젝트나 오브젝트들 전에 로드된다. 원하는 'front' 오브젝트들은 z-buffer 내에서 관찰자에 가깝도록 효율적으로 배치된다. 그러나 뷰 공간에서 그것들의 위치는 별로 변하지 않는다. 예제 코드는 이 기법을 구현했다. 이 경우 그것은 포스터에 z-bias 를 적용하고 있다.
 
다음 코드는 DirectX z-bias 호출을 대체하는 Projection Matrix 를 보여주는 간단한 코드이다.
 
// ZFighting 해결책 #1 - 투영행렬

D3DXMATRIX mProjectionMat;   // 현재 투영 행렬 저장
D3DXMATRIX mZBiasedProjectionMat; // ZBias 적용된 투영행렬 저장

// 투영 행렬이 사용하는 전역 변수

float g_fBaseNearClip =   1.0f;
float g_fBaseFarClip = 100.0f;
 
// 코드는 변경을 지시하지 않는다. 즉 '밀어 내어진 가깝고 먼 절단면'이라는 문장은
// 단지 먼 절단면만 밀어내어진 것처럼 보이게 한다
float g_fNearClipBias =   0.0f;
float g_fFarClipBias =   0.5f;

// 투영 행렬은 렌더링 함수 외부에서 계산을 수행할 때 가장 잘 작동한다.

// "zbias 적용된" 투영은 밀어내어진 가깝고 먼 절단면을 가진다
D3DXMatrixPerspectiveFovLH( &mZBiasedProjectionMat, D3DX_PI/4,(mProjectionMat._22/mProjectionMat._11), 
g_fBaseNearClip + g_fNearClipBias,
g_fBaseFarClip + g_fFarClipBias  );

. . .

// 원래 투영 행렬 로드됨
m_pd3dDevice ->SetTransform( D3DTS_PROJECTION, & mProjectionMat);

// 빌보드 렌더링됨...

// "zbias 적용된" 투영 로드됨...
m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mZBiasedProjectionMat);

// 포스터 렌더링됨...

// 원래 투영 로드됨...
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, & mProjectionMat);

. . .
 
 

원하는 결과를 획득하기 위해서는 투영 행렬에 대한 약간의 조정이 아직까지 필요하지만, 이 기법은 다양한 그래픽 하드웨어 상에서 더욱 일관적이다. 대안 해결책의 결과가 아래에 그림으로 나와 있다 :

 


Figure 2. 투영 수정 해결책을 사용해 해결된 z-fighting
 

대안 기법 2 : 뷰포트

 

 뷰포트 기법은 그것이 z-buffer 내에서 사용자에 가까운 선택된 오브젝트를 효율적으로 밀어낸다는 점에서 투영 행렬 기법과 유사하다. 뷰포트 기법은 새로운 뷰포트 오브젝트를 최대 및 최소 z-value 와 함께 로드함으로써 이 해결책을 구현한다. 아래의 샘플 코드는 포스터에 z-bias 를 적용함 으로써 이를 구현한다. 그래서 그것들은 빌보드 상에서 올바르게 디스플레이 된다.

 

다음 코드는 DirectX z-bias 호출을 대체하는 뷰포트를 보여주는 간단한 코드이다.

 

// ZFighting 해결책 #2 - 뷰포트


D3DVIEWPORT9 mViewport;   // 뷰포트 데이터 저장
D3DVIEWPORT9 mNewViewport; // 새로운 뷰포트 데이터 저장

// 뷰포트에 의해 사용되는 전역 변수
// 다음 식을 사용해서 1 의 ZBIAS 값을 하드코딩
//          MinZ - 256/(2^24-1) 과
//          MaxZ - 256/(2^24-1)
// 2^24 는 Zbits 의 개수로부터 나온다. 그리고  256 은 
// Intel (R) Integrated Graphics 를 위해 동작한다,

// 그러나 그것은 16의 배수라면 어떤 것이라도 상관없다.
float g_fViewportBias = 0.0000152588f;

// 투영 행렬이 적용된다.
// 뷰 행렬이 적용된다.
m_pd3dDevice->GetViewport(&mViewport);

// 이전의 뷰포트를 새로운 뷰포트에 복사.
mNewViewport = mViewport;

// bias 변경
mNewViewport.MinZ -= g_fViewportBias;
mNewViewport.MaxZ -= g_fViewportBias;


. . .

// 원래 뷰포트 로드됨 …
m_pd3dDevice->SetViewport(&mViewport);

// 빌보드 렌더링됨 …

// 새로운 뷰포트 로드됨 …
m_pd3dDevice->SetViewport(&mNewViewport);

// 포스터 렌더링됨 …

// 원래 뷰포트 다시 로드됨 …
m_pd3dDevice->SetViewport(&mViewport);

. . .

대안 기법 3 : Depth Bias

 

이 기사에서 소개되는 마지막 메서드는 DirectX 9 Depth Bias 기법을 사용해 z-fighting 을 해결한다. depth bias 를 수행하기 위한 기능을 그래픽 카드가 가지고 있는지 여부를 검사할 필요가 있다. Intel Integrated Graphics 는 Grantsdale 이라는 이름의 차세대 그래픽 코어 코드에서 depth bias 를 지원할 것이다. 그래픽 카드가 depth bias 를 지원하는 지를 검사하기 위해서 cap 비트를 확인한 후에, 이 기법은 D3DRS_SLOPESCALEDEPTHBIAS 및 D3DRS_DEPTHBIAS 에 원하는 효과를 얻기 위한 적절한 값을 설정할 것을 요구한다.

 

다음 코드는 DirectX z-bias 호출을 대체하는 depth-bias 를 보여주는 간단한 코드이다.

 

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-bias 처럼) 약간의 변경은 필요하다. 그러나 D3DRS_SLOPESCALEDEPTHBIAS 및 D3DRS_DEPTHBIAS 는 광범위한 그래픽 장치들에서 z-fighting 을 해결하기 위한 상대적으로 일관적인 기법이다. 다음 그림은 이 대안 해결책의 결과를 보여 준다 :

 

Figure 4. depth bias 해결책을 사용해 해결된 z-fighting

 

Figure 4 가 보여주듯이 D3DRS_SLOPESCALEDEPTHBIAS 와 D3DRS_DEPTHBIAS 를 설정하는 데 주의를 기울여야만 한다. 그것들은 매우 민감하며 아래와 같이 먼 거리의 오브젝트에 대한 또 다른 이슈를 불러 일으킬 수 있다 :


Figure 5. depth-bias 해결책이 만들어 낼 수 있는 이슈 : 원하지 않는 겹친 폴리곤
 
결론
 
동일 평면상의 폴리곤을 다룰 때 z-fighting 은 피할 수 없는 문제이다. 이 문서에서는 세 가지 기법을 보여 주었다 - 새로운 투영 행렬 로드, 새로운 뷰포트 로드, 새로운 DirectX 9 Depth Bias 사용. 이 기법들은 모두 z-bias에 대한 대안으로서 매우 성공적이다. 이들 기법들은 solid 테스트에 대한 필요성을 줄여주지는 않지만, z-bias 의 비일관적인 행동으로부터 발생하는 새로운 문제들 때문에 요청되는 변경의 횟수를 제한해 줄 수 있다(역주 : solid 테스트라는 것은 값을 변경하면서 적당한 값을 찾는 것을 의미하는 듯).
 
포함된 샘플 코드는 개발자에게 z-fighting 을 줄이기 위해서 사용될 수 있는 z-bias 대체물들에 대한 간단한 예제를 제공한다.
 
관련 리소스들
 
다음 링크들은 이 기사의 독자들에게 특별한 재미를 부여할 것이다 :
 
  • Intel® Extreme Graphics 2 Home Page provides an in-depth overview of the chipset features and capabilities associated with Intel Extreme Graphics 2.

  • DirectX 9 SDK* contains the DirectX* 9.0b runtime and software required to create DirectX 9.0-compliant applications.

  • ATI Depth Bias Example* is a sample application that demonstrates the use of depth bias to eliminate z-fighting.

  • Intel® Digital Media Developer Center provides insight, tips, tools, and training to create top-notch media applications.

  • Intel® Games Developer Center presents coding resources for game developers on Intel® architecture.
     

  • Posted by 붕대마음

    최근에 달린 댓글

    최근에 받은 트랙백

    글 보관함