Jaka jest najlepsza metoda aktualizacji mundurów shaderów?

10

Jaki jest najbardziej akceptowany sposób aktualizowania matryc modułu cieniującego i dlaczego?

Na przykład w tej chwili mam Shaderklasę, która przechowuje uchwyty do programu cieniującego GLSL i mundurów. Za każdym razem, gdy poruszam kamerą, muszę przekazać nową macierz widoku do modułu cieniującego, a następnie każdy inny obiekt świata muszę przekazać jej macierz modelu do modułu cieniującego.

To poważnie mnie ogranicza, ponieważ nie mogę nic zrobić bez dostępu do tego obiektu modułu cieniującego.

Myślałem o stworzeniu ShaderManagerklasy singleton, która byłaby odpowiedzialna za utrzymanie wszystkich aktywnych shaderów. Mogę wtedy uzyskać do niego dostęp z dowolnego miejsca, a obiekt świata nie musiałby wiedzieć o tym, które shadery są aktywne, po prostu musi poinformować ShaderManagero pożądanych macierzach, ale nie jestem pewien, czy jest to najlepszy sposób i prawdopodobnie istnieją pewne problemy, które powstanie z tego podejścia.

Lerp
źródło
Dlaczego nie przesłać danych do shaderów, gdy nadejdzie czas renderowania?
Nick Caplinger,
Tak zamierzam, ale jak? Jeśli jeden obiekt tworzy moduł cieniujący, to w jaki sposób obiekty świata mają wiedzieć o istnieniu tego modułu cieniującego i przekazać mu niezbędne matryce?
Lerp

Odpowiedzi:

11

Używaj jednolitych buforów (tj. Stałych buforów w języku D3D).

Tak długo, jak wszyscy twoi shadery zgadzają się co do układu i punktu wiązania każdego takiego bufora, aktualizacja staje się bardzo prosta. Modele wcale nie muszą nic wiedzieć o shaderach. Muszą tylko zaktualizować matrycę widoku modelu w swoim stałym buforze, a potok renderujący użyje go automatycznie.

Przynajmniej twierdziłbym, że powinieneś mieć dwa takie bufory. Pierwszy powinien przechowywać macierz projekcji, matrycę kamery, połączoną matrycę projekcji z kamery, informacje o rzutni, szczegóły frustrum i odwrotności matrycy. Musisz zaktualizować ten bufor tylko raz na scenę.

Następnie daj każdemu modelowi kolejny bufor do przechowywania jego matrycy widoku modelu, macierzy normalnej, odwrotności i właściwości materiału. Jest on aktualizowany jeden raz dla każdego modelu i można to zrobić za pomocą innej aktualizacji (jeśli / w razie potrzeby). Informacje o materiale można / należy przenieść do trzeciego bufora specyficznego dla materiału, jeśli masz możliwość współużytkowania materiałów między wieloma obiektami.

W ustawieniu cieniowania do przodu sensowne jest umieszczenie wszystkich świateł w innym buforze, a w przypadku cieniowania odroczonego warto również zastosować bufor światła dla przejścia światła (zamiast bufora modelu / materiału używanego w przejście geometrii).

Pamiętaj, że potrzebujesz umiarkowanie aktualnej wersji GL, aby w ogóle używać jednolitych buforów (3.1 lub rozszerzenia; dość powszechna dzisiaj, z wyjątkiem niektórych starszych, ale wciąż używanych laptopów) i potrzebujesz dość nowej wersji, aby być możliwość powiązania jednolitych buforów z określonymi lokalizacjami powiązań z kodu modułu cieniującego (4.2; wciąż niezbyt często, ale coraz lepiej), w przeciwnym razie musisz wykonać więcej pracy w kodzie po stronie procesora, aby skonfigurować ustawienia (kod procesora musi znać odpowiednie powiązanie wskazuje, więc to raczej zapach API niż poważny problem). OpenGL | ES nie dodał jednolitych buforów do 3.0, co niestety nie jest obsługiwane na większości popularnych platform mobilnych.

Jeśli bufory nie są opcją, będziesz potrzebować globalnego miejsca do przechowywania lokalizacji indeksu dla aktywnego modułu cieniującego. Możesz użyć glGetUniformLocationpo załadowaniu shadera, aby znaleźć indeksy dla dobrze znanych nazw (podobnych ModelViewMatrixlub podobnych), a następnie zapisać te indeksy. Twój rendering może mapować wartości wyliczeniowe, takie jak MODEL_VIEWprzekazane do SetUniformfunkcji otoki, aby spojrzeć na związany moduł cieniujący, znaleźć indeks i wywołać glUniformpoprawnie. Nie jest to szczególnie duża zmiana w użyciu kodu klienta z buforów innych niż konieczność ustawiania każdego munduru indywidualnie, jeśli wszystko dobrze się zapakuje.

Zobacz bloki interfejsu GLSL i jednolite obiekty buforowe .

Sean Middleditch
źródło
Wiedziałem, że będzie to wbudowany sposób. Dzięki!
Lerp
4

Najprostszym sposobem na to jest po prostu ujednolicenie jednolitych nazw między modułami cieniującymi i przesłanie wszystkich danych bezpośrednio przed rysowaniem. Narzut nie jest szalony, ale możesz go później zoptymalizować, aby nie zawsze wysyłał mniej zaktualizowane mundury.

Sposób, w jaki to robię w mojej grze jest taki, że mam abstrakcyjną Materialklasę. Materiały działają jak pomost między grą a shaderami. Każda Materialma Shaderróżne właściwości, które można ustawić, w tym tekstury. Kiedy narysujesz obiekt, Materialjest on związany. BindMetoda ma GraphicsStateparametr, który zawiera wszystkie aktualny stan Graphics - macierze, oświetlenie, itp Bindwiążę metoda cieniującego i tekstur i ustawia wszystkie mundury, używając cokolwiek to wymaga od GraphicsState.

Robert Rouhani
źródło