본문 바로가기

공돌이의 오늘생각/나는야 엔지니어

Z 버퍼, 깊이 버퍼 정밀도! OpenGL 물체 겹침, 깜빡임 문제해결

Z-Buffer가 안되!    Z-Buffer를 적용해도 겹쳐보여!    왜?! 왜?!!!

오늘 연구실에서 DirectX로 3D Model의 동영상을 만들려고 하는데, 어째 아무리 해봐도 B-spline의 곡면의 제어점들이 z-buffer적용이 안되는 것이다. 이걸로 몇시간 소비했다ㅠ 하지만 그 답을 알아냈으니, 아마 절대 잊어버리지 못할정도로 뼈저리게 배웠으니 보람은 있었다...ㅠ 내 하루...ㅠㅅㅜ 

OpenGL도 항상 다뤄오면서 건드렸던 부분이지만 어째 별 생각없었던 부분이었고, 다른사람들도 모를꺼라고 생각하기에 공유하려고 합니다. 정말 잘 설명해준 영문글이 있어서 번역해놓으려고 합니다. 

구글에 검색해보니 "z-buffer 정밀도", "z-buffer가 안되요","z-buffer 겹쳐보여요"등등의 검색결과가 꾀나 hit했기때문에 관련작업을 하시는분들은 궁금해하시지 않을까싶다. 번역은 완벽한 번역이 아니라, 중간중간 내맘대로 줄이고 고쳐서 적어봅니다.


영어원문 : Learning to Love Z-Buffer by Steve Baker


Introduction

OpenGL프로그래밍에서 자주 맞닥들이는 문제가 Z buffer의 낮은 정밀도이다. 예전컴퓨터들은 16bit의 z buffer를 이용하는경우가 대다수였고, 24비트를 이용하는경우도 있었고, 아주 좋은 경우에서야 32비트를 이용했었다. 운이 좋아 32비트의 z buffer를 이용하고 있다면, 아마 z buffer정밀도에대해 전혀 신경쓰지 않아도 될 것이다. 하지만, 프로그램을 더 가볍게 만들려고 한다면, 차분히 생각해봐야할 문제일 것이다.

z buffer정밀도는 어떤 물체가 더 앞에있고 더 뒤에있는지를 판단하는데 중요한 요소이다. 어떠한 두물체의 거리를 충분히 구별할 수 없다면 두 물체는 서로 통과해 같이 보이거나, 아예 보이지 않거나 할 것이다. 어떤때는 지그재그로, 스트라이프선으로 보이기도 할 것이다. 

이 문제는 flimmering 또는 Z-fighting으로 불리는 문제인대, 프로그래머를 아주 곤란하게 하곤 한다.


The Near Clip Plane ( zNear 값 )

Near Clip Plane (줄여서는 zNear )는 주로 gluPerspective() 또는 glFrustum()에서 인수로 설정되는 값이다. - GL_PROJECTION 매트릭스에 직접 설정할수도 있다.

일부 그래픽 프로그래머들은 zNear를 'hither', zFar를 'yonder'라고 하기도 한다.


"초보 프로그래머들은 zNear를 아주 짧은 위치로 설정해서 (예를들어 0.001 또는 0.0) 카메라 시점에 가까운 물체가 near plane에 잘려 표시안되는 현상을 회피하곤한다" 


뭐, 어떻게 설정해야될지 몰라서 그렇기도 하지만.

하지만 카메라시점에 아주 가까운 zNear의 값이 flimmering (z-buffer의 정밀도가 낮아 제대로 표현되지 않는현상)의 원인이 되곤 한다. 


The Resolution of Z. Z의 정밀도

많은 사람들이 간과하고 넘어가는부분이 있는데, Z buffer는 비선형이라는 점이다. 이것은, Z buffer메모리에 실제로 저장되는 값은 물체의 z좌표값과 관련되어있다는 이야기이다.


z_buffer_value = ( 1 << N ) * ( a + b / z )

    이때, N = z 정밀도의 bit수

a = zFar / ( zFar - zNear )

b = zFar * zNear / ( zNear - zFar )

z = 시점과 물체간의 거리


이때 z_buffer_value는 정수값을 가진다.

이 식이 의미하는 것은 Z ( 물론 Z의 정밀도 또한) z_buffer_value와 비선형 상관관계에 있다는 것을 의미한다. 쉽게말해, 시점에 가까울수록 더 높은 정밀도를 가지고, 시점에 먼 물체는 상대적으로 낮은 정밀도를 가진다.

이 특징은, 시점에 가까운 물체는 더욱 디테일하게 구현해야한다는 점에서 우용하다. 더욱 디테일한 물체에서는 더 정밀한 z값을 가져야 하기때문이다.

하지만, 그 부작용으로 시점에 가까운곳에서 쓸데없이 많은 z 정밀도를 가지게 된다. near clip plane 주변에서 비정상적으로 높은 정밀도의 z값을 저장하기 때문이다. near clip plane (zNear)를 카메라에 가까이 할수록 ( 0.0에 가까운 값을 지정할수록) zFar를 늘이는 것보다 메모리를 더욱 잡아먹게 된다.

그러므로 대부분의 경우에서, flimmering은 near clip plane을 시점에서 멀리하는것으로 해소 할 수 있는경우가 많다.


Z Calculator. Z 정밀도 계산기

영어원문 홈페이지 에 정밀도 계산기가 있다. 예를들어 넣은 값을 소개하자면,


Z buffer 비트수   =    16 bit                                Z 좌표값 100의 물체의 Z buffer 정밀도

zNear    =    0.000             →                                    100

 zFar     =    10000                                ( z좌표값차이 100의 물체 구분가능)

----------------------------------------------------------------------

Z buffer 비트수   =    16 bit                                Z 좌표값 100의 물체의 Z buffer 정밀도

zNear    =    10.00             →                            0.000059545

 zFar     =    10000                          ( z좌표값차이 0.000059545의 물체 구분가능)


보시다시피 zNear값을 0.0 에서 10.0으로 수정했을뿐인데도 100 거리의 물체의 z buffer 정밀도는 말도안되게 높아졌다.


Conclusion 결론

많은사람들이 z buffer가 제대로 움직이지 않을때, 다시 책을 뒤지고, 소스를 곱씹고 해도 도무지 해결안되는 경우가 있었을 것이다.


하지만 z buffer의 정밀도가 비선형(시점에 가까울수록 더 높은 정밀도를 가지고, 시점에 먼 물체는 상대적으로 낮은 정밀도)이고, zNear의 값을 0보다 아주 조금만 더 크게 조작하는 것 뿐만으로도 정밀도에 엄청난 변화가 있을거라는 것 잘 모르는 경우가 대부분일 것이다.


"초보 프로그래머들은 잘 모르고 zNear의 값을 0에 가까운 값으로 지정하는경우가 많지만, 이 글을 읽으신 여러분들은 이제 항상 zNear값을 당신의 눈이 인식할수 있을만큼까지만으로 설정하자"


그리고 옆에 z buffer가 안된다며 힘들어하는 친구가 있다면 5초만에 해결해 주도록 하자. 물론, 당신이 고급의 컴퓨터를가지고 있고 알게모르게 32비트 z buffer를 사용하고 있고, 작업하는 프로그램이 아주 간단한 문제라면 이 글은 의미가 없을지 모르겠다.