Jaki jest najbardziej akceptowany sposób aktualizowania matryc modułu cieniującego i dlaczego?
Na przykład w tej chwili mam Shader
klasę, 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 ShaderManager
klasy 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ć ShaderManager
o 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.
Odpowiedzi:
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ć
glGetUniformLocation
po załadowaniu shadera, aby znaleźć indeksy dla dobrze znanych nazw (podobnychModelViewMatrix
lub podobnych), a następnie zapisać te indeksy. Twój rendering może mapować wartości wyliczeniowe, takie jakMODEL_VIEW
przekazane doSetUniform
funkcji otoki, aby spojrzeć na związany moduł cieniujący, znaleźć indeks i wywołaćglUniform
poprawnie. 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 .
źródło
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ą
Material
klasę. Materiały działają jak pomost między grą a shaderami. KażdaMaterial
maShader
różne właściwości, które można ustawić, w tym tekstury. Kiedy narysujesz obiekt,Material
jest on związany.Bind
Metoda maGraphicsState
parametr, który zawiera wszystkie aktualny stan Graphics - macierze, oświetlenie, itpBind
wiążę metoda cieniującego i tekstur i ustawia wszystkie mundury, używając cokolwiek to wymaga odGraphicsState
.źródło