2D 렌더링에 깊이 버퍼의 전체 해상도 사용


9

직교 투영을 사용하여 2D 엔진의 전후방 렌더러를 작업 중입니다. 오버 드로우를 피하기 위해 깊이 버퍼를 사용하고 싶습니다. 16 비트 심도 버퍼, Z = 100의 Z = 0, zNear는 1, zFar는 1000 인 카메라가 있습니다. 렌더링 된 각 스프라이트는 Z 좌표를 점점 멀어지는 값으로 설정하여 심도 테스트에서 렌더링을 건너 뛸 수 있습니다. 밑에있는 모든 것.

그러나 Z 위치가 Z 버퍼 값으로 끝나는 방식이 비선형 적이라는 것을 알고 있습니다. 16 비트 깊이 버퍼의 전체 해상도, 즉 65536 고유 값을 사용하고 싶습니다. 따라서 렌더링 된 모든 스프라이트에 대해 다음 고유 깊이 버퍼 값과 상관시키기 위해 Z 위치를 다음 위치로 증가시키고 싶습니다.

즉, 각 스프라이트에 대해 고유 한 깊이 버퍼 값을 갖도록 스프라이트의 증분 인덱스 (0, 1, 2, 3 ...)를 적절한 Z 위치로 끌어 내고 싶습니다. 나는 이것 뒤에 수학을 확신하지 못한다. 이를위한 계산은 무엇입니까?

참고 WebGL (기본적으로 OpenGL ES 2)에서 작업하고 있으며 광범위한 하드웨어를 지원해야하므로 gl_FragDepth와 같은 확장 기능이 더 쉬울 수 있지만 호환성을 위해 사용할 수는 없습니다.


z 버퍼를 사용하면 알파 투명도 / 블렌딩을 언급하지 않고 z 버퍼 쓰기, 계산 및 비교 대 텍스처 복사를 다시 추가 한 후 성능이 많이 향상된다고 상상할 수 없습니다. 화가
Matt Esch

@MattEsch : 모든 계산은 GPU에서 엄청나게 빠른 속도로 수행되므로 그렇게하는 것이 합리적입니다.
Panda Pajama

@MattEsch : FWIW 이것은 전용 GPU 메모리 대신 시스템 메모리를 사용하는 Intel 통합 GPU를 대상으로합니다. 이로 인해 스프라이트를 너무 많이 끌어 오면 속도가 매우 느리고 채우기 속도 제한에 도달하기 쉽습니다. 인텔은이 문제를 해결하는 방법으로이 방법을 권장했습니다. 아마도 깊이 테스트 구현은 최적화가 잘되어 있고 많은 충전 속도를 절약 할 수 있습니다. 그래도 아직 프로파일 링되지 않았습니다!
AshleysBrain

@PandaPajama 블록 복사 메모리는 실제로 매우 빠르므로 표면에 텍스처를 블리 팅하는 경우 실제로 매우 빠릅니다. 첫 번째 주요 오버 헤드는 우선 GPU에 데이터를 가져 오는 것입니다. Ashley가 지적했듯이 통합 GPU에서 더 비쌀 수 있습니다. 많은 3D 게임조차도 (뼈 애니메이션과 같이) CPU에서 사소한 양의 작업을 수행한다는 것을 알았습니다. 먼저 매트릭스 계산을 수행하는 데 필요한 데이터를 업로드하는 것이 너무 비싸기 때문입니다.
Matt Esch

@MattEsch : 블리 팅만으로 할 수있는 일이 너무 많습니다. 회전, 스케일링 및 변형이 생각 나지만 픽셀 / 버텍스 셰이더가 있기 때문에 하드웨어로 할 수있는 것의 한계는 블리 팅으로 할 수있는 것보다 훨씬 높습니다.
Panda Pajama

답변:


5

실제로 z- 버퍼에 저장된 값은 물체의 실제 z 좌표에 선형이 아니고 역수에 가깝기 때문에 백플레인에 가까운 것보다 눈에 가까운 것에 더 많은 해상도를 제공합니다.

당신이 할 것은 당신이 당신의지도이다 zNear0당신은 zFar1. 에 대해 다음 zNear=1zFar=2같아야합니다.

Z 버퍼

이를 계산하는 방법은 다음에 의해 정의됩니다.

z_buffer_value = k * (a + (b / z))

어디

 k = (1 << N), maximum value the Z buffer can store
 N = number of bits of Z precision
 a = zFar / ( zFar - zNear )
 b = zFar * zNear / ( zNear - zFar )
 z = distance from the eye to the object

... z_buffer_value는 정수입니다.

위의 방정식은 이 멋진 페이지 에 의해 제공됩니다. 이 훌륭한 페이지 는 z 버퍼를 정말 잘 설명합니다.

따라서 z주어진에 필요한 것을 찾으 z_buffer_value려면 z다음을 지우십시오 .

z = (k * b) / (z_buffer_value - (k * a))

답변 해주셔서 감사합니다! 그래도 최종 공식을 얻는 방법이 약간 혼란 스럽습니다. 내가 가지고가는 경우에 z_buffer_value = k * (a + (b / z))단순히 위해 해결하기 위해 재 배열 z, 그럼 내가 얻을 : z = b / ((z_buffer_value / k) - a)- 당신은 어떻게 다른 마지막 공식에 도착 했습니까?
AshleysBrain

@AshleysBrain : 분모를 취하고로 (v / k) - a => (v - k * a) / k축소합니다 (k * b) / (v - (k * a)). 같은 결과입니다.
Panda Pajama

아, 알겠습니다 답변 주셔서 감사합니다, 그것은 잘 작동하고 있습니다!
AshleysBrain 11

0

어쩌면 당신은 접근 방식을 더 간단한 것으로 바꿔야 할 것입니다. 내가 할 것; Z 깊이는 유지하지만 렌더링 대상 목록은 유지하십시오. z 깊이 값을 기준으로 해당 목록을 정렬하고 목록 순서대로 오브젝트를 렌더링하십시오.

이것이 도움이되기를 바랍니다. 사람들은 항상 일을 단순하게 유지하라고 말합니다.


1
미안하지만별로 도움이되지 않습니다. 나는 이미 그렇게하고있다. 질문은 Z 위치를 선택하는 것에 관한 것입니다.
AshleysBrain

0

렌더링 할 항목 목록 (앞에서 뒤로)이 이미 있으므로 Z 인덱스를 증가시켜야합니까? "체크 기능"에 "작거나 같음"을 사용할 수 없습니까? 이런 식으로 실제로 특정 픽셀이 이미 그려 졌는지 확인합니다.


모든 것이 항상 동일한 Z 인덱스를 가지므로 깊이 테스트를 통과하기 때문에 "낮음 또는 같음"은 여전히 ​​모든 항목을 덮어 씁니다.
AshleysBrain
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.