Pytanie OpenGL - Jak uzyskać dostęp do wartości bufora głębokości? - Lub: gl_FragCoord.z ​​vs. Renderowanie głębi do tekstury


Chcę uzyskać dostęp do wartości bufora głębi w aktualnie przetwarzanym pikselu w module cieniującym pikseli.

Jak możemy osiągnąć ten cel? Zasadniczo wydaje się, że istnieją dwie opcje:

  1. Głębokość renderowania do tekstury. Jak możemy to zrobić i jaki jest kompromis?
  2. Użyj wartości podanej przez gl_FragCoord.z ​​- Ale: Czy to jest poprawna wartość?

9
2018-04-29 10:29


pochodzenie


gl_FragCoord.z jest wartością głębi aktualnie przetwarzanego fragmentu, a nie aktualną wartością w buforze głębi. Aby uzyskać teksturę głębi, utwórz teksturę z formatem głębi, wyślij do pliku FBO z teksturą głębi dołączoną do pliku GL_DEPTH_ATTACHMENT, a następnie połącz teksturę głębi do próbkowania w module cieniującym fragmentu. - Reto Koradi
@RetoKoradi, brzmi jak odpowiedź, dlaczego zrobiłeś komentarz? - JWWalker
@JWWalker: Ponieważ byłem w pośpiechu i zwykle staram się sformułować moje odpowiedzi nieco ostrożniej i bardziej szczegółowo. Zamienię to w odpowiedź. - Reto Koradi


Odpowiedzi:


W pytaniu 1: Nie można bezpośrednio odczytać z bufora głębi w module cieniowania fragmentów (chyba że istnieją nieznane rozszerzenia, których nie znam). Musisz renderować do obiektu bufora ramek (FBO). Typowe kroki:

  1. Twórz i wiąż z FBO. Wyszukaj połączenia typu glGenFramebuffers i glBindFramebuffer jeśli wcześniej nie korzystałeś z usług FBO.
  2. Utwórz teksturę lub bufor renderowania, który będzie używany jako bufor kolorów, i dołącz go do pliku GL_COLOR_ATTACHMENT0 punkt przyłączenia twojego FBO z glFramebufferTexture2D lub glFramebufferRenderbuffer. Jeśli zależy ci tylko na głębokości od tego przejścia renderowania, możesz pominąć to i renderować bez bufora kolorów.
  3. Utwórz teksturę głębi i dołącz ją do pliku GL_DEPTH_ATTACHMENT punkt przyłączenia do FBO.
  4. Wykonaj renderowanie, które tworzy głębokość, której chcesz użyć.
  5. Posługiwać się glBindFramebuffer aby powrócić do domyślnego bufora ramki.
  6. Powiąż teksturę głębi z próbnikiem używanym przez twój moduł cieniujący.
  7. Twój shader fragmentów może teraz pobierać próbki z tekstury głębi.

W pytaniu 2: gl_FragCoord.z jest wartością głębi fragmentu, na którym działa twój moduł cieniujący, nie bieżąca wartość bufora głębokości w miejscu fragmentu.


22
2018-04-29 17:55



Załóżmy, że renderuję do bufora ramki o tym samym rozmiarze co moje drugie przejście. Czy tekstura (depth_texture, vec2 (float (gl_FragCoord.x) / width, float (gl_FragCoord.y) / height)) .r index _prawdopodobnie prawą wartość tekstury i odczytać wartość głębokości poprzedniego przejścia? Widzę artefakty "dzwoniące" w pobliżu dużych nieciągłości w buforze głębi. - Alec Jacobson
Jak przekonwertować z powrotem wartość głębokości uzyskaną za pomocą texture() wzywać wnętrze shadera z powrotem do "prawdziwych" współrzędnych świata? Jeśli dobrze rozumiem, wartości głębokości są zaciśnięte na [0;1] - co za wartość pomnożyć zaciśniętą głębokość? - PinkTurtle
Głębokość można znaleźć za pomocą wartości bliskich i odległych ustawionych w macierzy projekcji. Po prostu pomnóż różnicę między bliską a daleką i dodaj zbliżoną wartość, aby uzyskać oryginalną wartość ((((daleko - blisko) * Głębokość) + blisko). - MasterPlanMan
Uwaga: Renderbuffer nie może być używany do próbkowania z późniejszymi etapami cieniowania. - Entalpi


gl_FragCoord.z jest wartością głębi okna-przestrzeni bieżącego fragmentu. Nie ma nic wspólnego z wartością przechowywaną w buforze głębi. Wartość może później być zapisane w buforze głębi, jeśli fragment nie jest discarded i przechodzi test szablon / głębokość.

Technicznie istnieją pewne optymalizacje sprzętowe, które wcześnie zapisują / testują głębię, ale na wszystkie intencje i cele gl_FragCoord.z nie jest wartością zapisaną w buforze głębi.

Jeśli nie renderujesz wielu przebiegów, nie możesz odczytać i zapisać do bufora głębi w module cieniowania fragmentów. Oznacza to, że nie można użyć tekstury głębi do odczytania głębi, a następnie odwrócić i napisać nową głębię. Przypomina to próbę implementacji mieszania w module cieniującym fragmentów, chyba że zrobisz coś egzotycznego ze sprzętem klasy DX11 i ładowaniem / przechowywaniem obrazu, to po prostu nie zadziała.

Jeśli potrzebujesz tylko głębokości finalnie narysowanej sceny dla czegoś w rodzaju odwzorowania cienia, możesz wykonać wstępne przejście tylko do głębokości, aby wypełnić bufor głębi. W drugim przejściu odczytałeś bufor głębi, ale nie zapisałeś do niego.


5
2018-04-29 18:01