Как использовать более 1-й текстуры в glsl-шейдере и glfw (C++)?

Я упражняюсь в работе с OpenGL, и передо мной стоит задача реализовать возможность добавлять множество различных текстур для разных объектов (в моём случае - сетки (mesh), состоящие из вершин). Я знаю о том, что можно использовать GL_TEXTURE0 + i, где i - число от 0 до 31. Но тут и возникает ограничение, из-за которого я могу использовать только 32 текстуры (а мне их нужно больше). Плюс у меня ещё реализован инстансинг, который тоже добавляет нюанс к написанию программы (я не могу из-за этого переключаться на нужные текстуры при помощи glActiveTexture перед рендером каждой отдельной сетки). Подскажите пожалуйста, как успешно реализовать то, что мне нужно?


Ответы (3 шт):

Автор решения: Никита Самоуков

Добро пожаловать в реалии графония. Тут придется постоянно переключать текстуры и шейдера.

Но тут и возникает ограничение, из-за которого я могу использовать только 32 текстуры

Максимум для одного запуска шейдера. А в опенжл можно запихивать сколько угодно.

Перерыл немало документаций, пробовал искать в исходниках нужные мне компоненты - не помогло.

Тут точно есть решение проблемы.

https://dev.epicgames.com/documentation/en-us/unreal-engine/downloading-unreal-engine-source-code

→ Ссылка
Автор решения: Timich

Я не до конца понимал возможностей конструкции "GL_TEXTURE0 + i". Несмотря на то, что максимальным существующим элементом является GL_TEXTURE31, последующие элементы можно вывести при помощи сложения маркеров GL_TEXTURE и целых чисел, а значит ограничения по количеству одновременно используемых текстур у данной реализации нету. А чтобы каждый объект имел уникальную текстуру, можно создать массив из sampler-ов (текстуры назначать через юниформы) и указывать индексы нужной текстуры.

→ Ссылка
Автор решения: user7860670

Когда множество мешей требует множества текстур, то для отрисовки каждого меша придется менять состояние конвеера, выставляя соответствующую объекту текстуру в используемый в шейдере текстурный блок (glActiveTexture). Как и любое изменение состояние конвеера, такие действия будут нести некоторый оверхед и снижать производительность.

Можно использовать в шейдере массив из sampler-ов, задействовав несколько текстурных блоков вместо одного и прикрепить разные текстуры к разным блокам вместо постоянного их переключения. Однако это плохой вариант. Во-первых количество текстурных блоков ограничено. Хотя на десктопах с актуальными графическими ускорителями их количество обычно значительно больше исторически имеющейся константы GL_TEXTURE31, но все равно ограничено величиной GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, которая может достигать пары сотен. А на мобильных устройствах ограничение может быть всего 8. Во-вторых расходовать бюджет текстурных блоков на разные текстуры для одного шейдера не рационально, вместо этого его следует расходовать на разные шейдеры, чтобы избегать дополнительного оверхеда при изменении состояния графического конвеера при переключении на другой шейдер (т.е. например первый шейдер использует блоки 1, 2, 3, второй шейдер блоки 4, 5, 6 и т.д).

Самый базовый подход заключается в сокращении требуемого количества текстур за счет объединения нескольких текстур в одну большую, то бишь создание текстурного атласа.

В силу имеющихся ограничений на габариты текстур, все текстуры могут не поместиться в одну большую. В этом случае можно сделать следующий шаг - переход к массиву текстур GL_TEXTURE_2D_ARRAY, в котором каждый слой будет представлять собой кусок текстурного атласа. По сути этот метод позволяет назначить одному текстурному блоку сразу несколько текстур.

А когда количество текстур становится настолько велико, что уже не может помещаться в память графического ускорителя, то в продвинутых графических API (таких как DirectStorage) для этого есть возможность использования виртуальных текстур с динамической подгрузкой, то бишь пополнение памяти графического ускорителя только кусками текстур, необходимыми для отрисовки в текущий момент.

→ Ссылка