Який найкращий метод оновлення уніформи шейдера?


10

Який найбільш прийнятний спосіб оновлювати матриці шейдерів та чому?

Наприклад, на даний момент у мене є Shaderклас, який зберігає ручки до програми шейдерів та уніформи GLSL. Кожен раз, коли я переміщую камеру, мені потім доводиться передавати нову матрицю перегляду в шейдер, тоді кожен інший об'єкт світу я повинен передавати матрицю моделі в шейдер.

Це сильно обмежує мене, оскільки я нічого не можу зробити, не маючи доступу до цього об'єкта шейдерів.

Я думав створити ShaderManagerклас одиночки, який відповідає за проведення всіх активних шейдерів. Тоді я можу отримати доступ до цього з будь-якого місця, і світовий об’єкт не повинен знати про те, які шейдери є активними, лише про те, що потрібно повідомити ShaderManagerпотрібні матриці, але я не впевнений, що це найкращий спосіб, і, мабуть, є деякі проблеми, які виникне при використанні цього підходу.


Чому б не передати дані в шейдери, коли настає час візуалізації?
Нік Каплінгер

Це я маю намір, але як? Якщо один об'єкт створює шейдер, то як світові об’єкти мають знати про існування цього шейдера та передавати йому необхідні матриці?
Лерп

Відповіді:


11

Використовуйте рівномірні буфери (тобто постійні буфери) в лінгві D3D).

До тих пір, поки всі ваші шейдери домовляться про макет і точку прив’язки кожного такого буфера, то оновлення стає легким вітром. Моделі взагалі нічого не потрібно знати про шейдери. Їм потрібно лише оновити матрицю перегляду моделі в їх постійному буфері, і конвеєр візуалізації використовуватиме її автоматично.

Як мінімум, я стверджую, що у вас повинно бути два таких буфера. Перший повинен зберігати матрицю проекцій, матрицю камери, об'єднану матрицю проекції камери, інформацію про вікно перегляду, деталі фруструма та обертання матриці. Оновлювати цей буфер потрібно лише один раз на кожну сцену.

Потім дайте кожній моделі ще один буфер для зберігання її матриці перегляду моделі, нормальної матриці, обертів та властивостей матеріалу. Це оновлюється один раз для кожної моделі і може бути зроблено в іншому пропуску оновлення (якщо / коли це доречно). Інформацію про матеріал можна / слід перемістити в третій специфічний для буфера матеріал, якщо у вас є можливість ділитися матеріалами між кількома об'єктами.

У налаштуваннях затінення вперед має сенс помістити всі світильники в інший буфер, а також у відкладеному затіненні має сенс використовувати буфер на світло для пропускання світла (замість моделі / буфера, що використовується в пропуск геометрії).

Зауважте, що вам потрібна помірно оновлена ​​версія GL, щоб взагалі використовувати однакові буфери (3.1 або розширення; досить поширені сьогодні, за винятком старих, але ще в користуванні ноутбуків), і вам потрібна досить недавня версія, щоб бути вміти прив’язувати рівномірні буфери до конкретних місць зв’язування всередині коду шейдера (4.2; все ще нечасто, але покращується), інакше вам доведеться зробити більше роботи в коді на стороні процесора, щоб налаштувати речі (ваш код CPU повинен знати правильну прив'язку балів все одно, тож це швидше запах API, ніж серйозна проблема). На жаль, OpenGL | ES не додавав рівномірних буферів до 3.0, що все ще не підтримується на більшості популярних мобільних платформ.

Якщо буфери не є варіантом, вам знадобиться глобальне місце для зберігання покажчиків для активного шейдера. Ви можете використовувати glGetUniformLocationпісля завантаження шейдера, щоб знайти індекси для відомих імен (наприклад, ModelViewMatrixподібних), а потім зберегти ці індекси. Ваш візуалізатор може зіставити значення перерахунку, як MODEL_VIEWпередані SetUniformфункції обмотки, щоб заглянути в зв'язаний шейдер, знайти індекс і glUniformправильно зателефонувати . Це не особливо велика зміна використання коду клієнта з буферів, окрім необхідності встановлення кожної форми одноосібно, якщо ви все це добре завернули.

Див. Інтерфейсні блоки GLSL та уніфіковані об'єкти буфера .


Я знав, що це буде вбудованим способом. Дякую!
Лерп

4

Найпростіший спосіб зробити це - просто стандартизувати однакові імена між вашими шейдерами і просто надсилати всі дані прямо перед тим, як намалювати. Накладні витрати не божевільні, але ви можете їх оптимізувати пізніше, щоб не завжди надсилати менш оновлені форми.

Як я це роблю в своїй грі, це те, що у мене є абстрактний Materialклас. Матеріали виступають мостом між грою та шейдерами. У кожному Materialє Shaderі різні властивості, які можна встановити, включаючи текстури. Коли настає час намалювати предмет, його Materialзв'язати. BindМетод має GraphicsStateпараметр , який містить всі поточні графіки стану - матриці, світло і т.д. BindМетод пов'язує шейдер і текстуру і встановлюють все мундири, використовуючи всі , що має від GraphicsState.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.