Pracuję nad rendererem od przodu do tyłu dla silnika 2D z wykorzystaniem projekcji ortograficznej. Chcę użyć bufora głębokości, aby uniknąć overdraw. Mam 16-bitowy bufor głębokości, aparat przy Z = 100 patrząc na Z = 0, zNear wynosi 1, a zFar wynosi 1000. Każdy renderowany duszek ustawia swoje współrzędne Z na coraz bardziej odległe wartości, umożliwiając testowi głębi pominięcie renderowania wszystko, co jest pod spodem.
Wiem jednak, że sposób, w jaki pozycje Z kończą się wartościami bufora Z, jest nieliniowy. Chcę skorzystać z pełnej rozdzielczości 16-bitowego bufora głębi, tzn. Zezwalając na 65536 unikalnych wartości. Tak więc dla każdego renderowanego duszka chcę zwiększyć pozycję Z do następnej pozycji, aby skorelować z następną unikalną wartością bufora głębokości.
Innymi słowy, chcę obrócić indeks rosnący (0, 1, 2, 3 ...) duszka, który jest wciągany do odpowiedniej pozycji Z dla każdego duszka, aby miał unikalną wartość bufora głębokości. Nie jestem pewien matematyki. Jakie są obliczenia, aby to zrobić?
Uwaga: Pracuję w WebGL (w zasadzie OpenGL ES 2) i muszę obsługiwać szeroki zakres sprzętu, więc chociaż rozszerzenia takie jak gl_FragDepth mogą to ułatwić, nie mogę go używać ze względu na kompatybilność.
źródło
Odpowiedzi:
Rzeczywiście, wartości przechowywane w buforze Z nie są liniowe względem rzeczywistych współrzędnych Z twoich obiektów, ale do ich wzajemności, aby dać większą rozdzielczość temu, co jest blisko oka, niż temu, co jest bliżej tylnej płaszczyzny.
To, co robisz, polega na mapowaniu
zNear
do0
izFar
do1
. DlazNear=1
izFar=2
powinno to wyglądać takSposób obliczenia tego jest określony przez:
Gdzie
... a wartość z_buffer_value jest liczbą całkowitą.
Powyższe równanie zostało przedstawione dzięki tej niesamowitej stronie , która wyjaśnia bufory Z w naprawdę dobry sposób.
Tak więc, w celu znalezienia niezbędnych
z
dla danegoz_buffer_value
, po prostu wyczyścićz
:źródło
z_buffer_value = k * (a + (b / z))
i po prostu przestawię rozwiązaniez
, otrzymam:z = b / ((z_buffer_value / k) - a)
- jak doszedłeś do innej ostatniej formuły?(v / k) - a => (v - k * a) / k
i zwijasz się do(k * b) / (v - (k * a))
. To ten sam wynik.Może powinieneś zmienić Twoje podejście do czegoś prostszego. Co bym zrobił; Zachowaj głębię Z, ale zachowaj listę tego, co renderujesz. Uporządkuj tę listę na podstawie wartości z Głębokość i renderuj obiekty w kolejności na liście.
Mam nadzieję, że to może pomóc. Ludzie zawsze mówią mi, żeby wszystko było proste.
źródło
Skoro masz już posortowaną listę rzeczy do renderowania (od przodu do tyłu), czy naprawdę musisz zwiększać indeks Z? Czy nie można użyć „mniejszej lub równej” dla „funkcji sprawdzającej”? W ten sposób sprawdziłby, czy określony piksel został już narysowany, czy nie.
źródło