[openGL] Depth

나우히즈·2024년 10월 10일

Graphics

목록 보기
12/17

서론

화면을 출력하는데 있어서 다양한 옵션으로 여러가지 결과를 나타내게 할 수 있다.
그 중 Depth, Stencil, Blending 이라는 요소들에 대해 알아보고 이들을 어떻게 조절하느냐에 따라 어떻게 렌더링이 되는지를 알아보도록 하자.


Depth

앞에 있는 물건이 뒤에 있는 물건을 가리는 것은 당연한 이치다. 그래픽스 오브젝트가 나란히 있다고 할 때, 바라보는 방향에 따라 한 물체가 다른 물체를 가릴 수 밖에 없다. 오브젝트는 각각의 위치좌표를 가지고 있는데, 그 중 Z 좌표가 카메라에서 멀고 가깝고를 결정한다.

따라서 우리는 이 Z값을 비교해서 가까이 있는 물체의 픽셀을 찍어내고, 멀리있는 물체의 픽셀은 찍지 않기로 한다.

화면마다 Depth buffer를 두고 모든 물체의 값을 받아 각 픽셀에서 찍혀질 물체의 Z값을 담는다. Z좌표는 0~1 사이의 값으로 나오는데, 작을수록 카메라에 가깝게 되고 이 때의 Z값이 Depth buffer에 담긴다.

Depth testing

glEnable(GL_DEPTH_TEST);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glClearDepth(1.0f);
glDepthFunc(GL_LESS);
  1. glEnable(GL_DEPTH_TEST); / glDisable(GL_DEPTH_TEST);
    • 기능: 깊이 테스트를 활성화(glEnable) 또는 비활성화(glDisable)하는 함수
    • 설명: 깊이 테스트는 렌더링할 때 각 픽셀의 깊이 값을 비교하여, 더 가까운 픽셀만 렌더링되게 한다. 만약 깊이 테스트를 비활성화하면, 그리려는 순서대로 렌더링이 이루어지며, 깊이 관계는 고려하지 않는다.

  2. glDepthMask(GL_FALSE);

    • 기능: 깊이 버퍼 쓰기를 비활성화하는 함수입니다. (GL_TRUE로 설정하면 쓰기를 다시 활성화할 수 있습니다.)
    • 설명: 이 함수는 깊이 테스트는 활성화하되, 깊이 버퍼에 값을 쓰지 않도록 설정. 이 기능은 깊이 정보를 읽지만, 새로운 깊이 정보를 기록하지 않고자 할 때 유용한데, 투명한 객체를 렌더링할 때 주로 사용함.

  3. glClearDepth(1.0f);

    • 기능: 깊이 버퍼를 지울 때 사용할 깊이 값을 설정하는 함수.
    • 설명: glClearDepth()는 깊이 버퍼를 glClear(GL_DEPTH_BUFFER_BIT)로 지울 때 채워질 값(기본 깊이 값)을 설정한다. 즉, 깊이 버퍼를 지울 때 모든 픽셀이 가장 먼 거리(1.0f)에 있다고 설정.

  4. glDepthFunc(GL_LESS);

    • 기능: 깊이 테스트에서 두 깊이 값을 비교하는 기준을 설정하는 함수.
    • 설명: 이 함수는 렌더링할 픽셀의 깊이 값과 이미 렌더링된 픽셀의 깊이 값을 비교할 때 사용할 조건을 설정.
    • GL_LESS는 새 픽셀이 더 가까울 때만 렌더링하라는 의미. 기본적으로 활용.
    • 다른 비교 연산자로는 GL_GREATER, GL_EQUAL, GL_ALWAYS 등이 있으며, 각각 다른 조건을 설정할 수 있습니다.

Depth의 왜곡

일반적은 카메라의 시선은 perspective view 이다. 이 과정을 위해 perspective projection 을 사용하여 카메라공간으로 물체들이 이동되는데, 이 과정에서 동차좌표계를 (x, y, z, 1)로 맞춰주기 위해 Z값이 w로 나눠지는 계산을 진행하게 된다.

이렇게 원근감을 살리는 렌더링이 이루어지는데, 이에 따라 z의 값은 1/x 함수 형태로 분포하게 된다.

이로인해 함수 형태 상, 멀리있는 z값들 간에는 큰 차이가 보이지 않게 되고 컴퓨터 계산 상의 오차로 왜곡이 나타나게 된다.

Z-fighting

Z-fighting은 컴퓨터 그래픽스에서 발생하는 시각적 아티팩트로, 두 개 이상의 오브젝트가 화면상에서 같은 깊이 값을 갖는 경우에 발생한다. 이로 인해 어떤 픽셀이 어떤 오브젝트에 속하는지 정확히 결정하지 못해, 오브젝트들이 겹치는 부분에서 픽셀이 깜빡거리거나 빗살무늬로 깨지는 결과가 나타나는 현상을 Z-fighting이라고 한다.

Z-fighting의 주된 원인

  • 깊이 버퍼의 정밀도 부족: 깊이 버퍼가 충분히 많은 비트를 사용하지 않으면, 깊이 값의 차이를 충분히 정확하게 구별할 수 없게 된다.

  • 카메라 근처/멀리 위치한 오브젝트들: 카메라의 near, far plane 설정이 너무 넓으면 깊이 버퍼의 정밀도가 멀리 있는 오브젝트 사이의 차이를 제대로 반영하지 못할 수 있다.

  • 두 오브젝트의 동일한 위치: 두 오브젝트가 같은 위치에 있거나 매우 가깝게 겹쳐 있을 떄 Z-fighting이 자주 발생한다.

Z-fighting 해결 방법

    1. Near, Far plane 최적화: Projection Matrix에서 near plane과 far plane의 값을 최적화해 Z-buffer 정밀도를 높일 수 있다. 일반적으로 near plane은 너무 작게 설정하지 않고, far plane은 너무 크게 설정하지 않는게 좋다.
    1. 폴리곤 오프셋(Polygon Offset): 렌더링 시 두 개의 겹치는 오브젝트가 있을 경우, 하나의 오브젝트에 약간의 오프셋을 주어 Z-fighting을 완화할 수 있다. 특히나 openGL에서는 glPolygonOffset 함수를 주어 Z-fighting을 완화할 수 있다.
    1. 깊이 버퍼 비트수 확대: 깊이 버퍼의 정밀도를 높이기 위해 더 많은 비트를 사용하여 깊이 정보를 표현하는 방식.

0개의 댓글