Сколько ВАО и ВБО
Насколько я понимаю: ВАО представляет собой определенное государство. Если я связываю VAO, добавляю несколько VBO и буферов элементов для указателей и прочего, я могу сохранить определенное состояние объекта (ов), который я хочу нарисовать, активировать и легко нарисовать позже в будущем, когда я хочу визуализировать материал. Правильно?
Таким образом, VBO содержит фактические данные, а VAO - это просто "объект-обертка", который содержит указатели на все буферы, которые я для него определил?
Изменение VAO является дорогостоящим (как и изменение VBO?!). В настоящее время я загружаю в Meshes и объединяю их с моделями. Каждая модель использует свой собственный VAO и имеет VBO (с вершинами) и элементный буфер с их индексами.
Теперь, насколько я понимаю, это чушь собачья, поскольку каждый объект в моем мире (у которого есть модель) использует свой собственный VAO. Не проблема для ~30 объектов в моем мире, но я хочу сделать это правильно, и в будущем могут появиться сотни или тысячи объектов, и тогда производительность значительно снизится.
Итак, многие объекты "одинаковы" по своим моделям. Я имею в виду, если, например, у вас есть определенный тип дерева в мире, вы, вероятно, используете одну и ту же модель несколько раз, просто в разных местах.
Теперь, как бы я пошел по этому поводу? Должен ли я вручную отслеживать свои VAO, такие как: (псевдокод следующий!)
treesVAOId = 1;
rabbitsVAOId = 2;
и затем, если я загружу модель, просто проверьте, был ли идентификатор уже связан (как?) и добавьте туда другой набор VBO (или даже добавьте к нужному VBO? если да, то как?)
Я думаю о большой игре здесь. Давайте предположим, что в игре тысячи персонажей. Конечно, не все они воспроизводятся одновременно, но я не могу создать VAO и VBO для каждого из них, могу ли я?
Я чувствую, что отсутствует большая часть... например, создание экземпляров и использование (более или менее) одних и тех же данных снова для разных целей эффективно.
Это один шаг, который мне не хватает, как по-настоящему оптимизировать использование VAO и VBO в реальном мире.
2 ответа
То, что вы описали здесь, называется менеджером ресурсов или, по крайней мере, частью менеджера ресурсов. Описание ресурсов во внешнем файле является хорошей практикой, поэтому вам необходим файл ресурсов, в котором все ваши сетки описаны каким-либо образом (рассмотрите возможность использования XML или JSON).
Иерархия классов
Вот возможный подход к иерархии классов:
Каждый VAO представляет сетку, определяя ее координаты вершин, координаты текстуры, нормали, цвета вершин и так далее. Я думаю, что нет причин использовать один и тот же VBO в нескольких VAO, пока у вас не появится особый случай визуализации. Итак, давайте предположим, что вы используете каждый набор данных только один раз, то есть классы, которые используют VAO, не должны ничего знать о базовых VBO, и нет необходимости писать оболочку класса для VBO.
Набор сеток (может содержать только одну сетку) представляет модель. Минимальный класс модели должен включать дескриптор (ы) VAO(ов) и информацию о преобразованиях геометрии (вращать, переводить, что вы хотите). Почему не строго одна сетка на модель? Иногда вам может потребоваться применить одно преобразование к группе сеток, которая в свою очередь имеет свое собственное модельно-локальное преобразование. Например, такая композиция может использоваться для своего рода скелетной анимации или просто для рендеринга персонажа с произвольным оружием, взятым из библиотеки возможного оружия. Более того, вы можете группировать такие модели вместе, получая более сложные модели с одним и тем же интерфейсом, так что вы получите сходство графа сцены. В любом случае, это хорошая идея использовать составной шаблон для модельного класса.
Сцена должна включать коллекции моделей, источников света, силовых полей и так далее.
Менеджер ресурсов
Но откуда сцена (или подобный игровой объект) получит свои модели? Менеджер ресурсов должен ответить на этот вопрос. Сделайте каждую модель определенной своего рода уникальным идентификатором. В простейшем случае путь в реальной или виртуальной файловой системе может рассматриваться как идентификатор, но он не очень гибкий. На мой взгляд, лучше определить все сетки в вашем файле ресурсов, используя выразительные понятные человеку имена и привязать каждое имя к набору данных (все типы координат, цветов и т. Д.) И атрибутов. Весь ваш код не должен использовать модели напрямую, но он должен использовать дескрипторы, предоставленные вам менеджером ресурсов. Очевидно, что менеджер ресурсов должен сохранять состояние во время выполнения программы и между вызовами из разных мест. Он предназначен для отслеживания того, какие сетки уже хранятся в памяти, и хранит идентификаторы VAO всех сохраненных сеток. Рассмотрите возможность использования одноэлементного шаблона для менеджера ресурсов.
Пример:
ModelHandle footman = resMan->getModel("footman.model");
//.....
footman->setLocation(x,y,z);
footman->draw();
Здесь вызов getModel("footman.model") начинает конструирование модели, вызывающей такие вызовы, как
MeshHandle resMan->getMesh("footman1.mesh");
чтобы получить все сетки. А также getMesh
делает ли работа причиной всего этого объяснения. Он проверяет, была ли загружена такая сетка ранее, и если да, он просто возвращает дескриптор VAO, содержащей эту сетку. В противном случае он создает новый объект VAO, загружает в него запрошенные данные и возвращает дескриптор вновь создаваемого объекта. Все последующие запросы этого объекта не будут вызывать новое выделение VAO.
Конечно, описанная организация графа сцены является лишь приблизительным приближением к тому, как он должен выглядеть. Например, он не делает различий между узлом модели и абстрактного графа сцены, но разработка и точная настройка такой иерархии для вашего движка зависит от вас.
Окончательный интерфейс к классу менеджера ресурсов - еще одна тема для обсуждения и разработки. Некоторые вопросы и идеи:
- Будете ли вы использовать синглтон или по какой-то причине решите использовать глобальную переменную?
- Если вы решите использовать синглтон, может быть, вы хотите иметь некоторые другие частные не-синглтон-менеджеры ресурсов для какого-то ограниченного набора ресурсов? Затем рассмотрите возможность разработки синглтона как класса шаблона для упаковки, чтобы сделать возможным такой код:
ResourceHandle h1 = Singleton<ResourceMan>::instance->getResource("foo");
ResourceMan myPrivateManager;
ResourceHandle h2 = myPrivateManager.getResource("bar");
- Будете ли вы управлять всеми типами ресурсов с помощью одного комплексного менеджера или использовать специальный класс менеджера для каждого типа ресурсов? Второй подход лучше. Развивая идею второго подхода, поручите вашему компилятору написать код для вас! Используйте класс менеджера ресурсов шаблона с небольшим подмножеством специализированного метода. Просто специализируйте один метод создания ресурса для каждого типа ресурса и оставьте все остальные коды управления ресурсами нетронутыми!
- Продумайте ресурс ресурса. Когда конкретный ВАО должен быть уничтожен? Рассмотрите возможность использования счетчика ссылок и / или заимствованных ссылок.
- Кэширование? Удалить данные из памяти хоста сразу после загрузки их на устройство (видеокарту) или оставить на некоторое время? На сколько долго?
- Как насчет потоковой передачи? Это не должен быть домен менеджера ресурсов, но поддержка потоковой передачи может повлиять на него.
- Функция glIsVertexArray и ее аналоги могут быть полезны.
Сортировка
VAO - не единственный ресурс, который вам нужно изменить при рендеринге сцены. Вам также необходимо изменить текстуры, шейдеры и даже кадровые буферы. Обычный способ уменьшить количество изменений состояния состоит в сортировке отображаемых объектов по некоторому свойству.
Например, очень вероятно, что вы визуализируете данный меш только с одним шейдером. Поэтому сначала вы можете отсортировать все сетки по шейдерам, чтобы минимизировать количество изменений шейдеров. Затем для каждого шейдера (т. Е. В списке сеток для данного шейдера) вы можете отсортировать сетки по VAO, чтобы уменьшить количество изменений VAO до выполнимых. минимум. Сортировать по текстуре? Это зависит от вашего приложения, если вам нужно отсортировать объект по текстуре и где это сделать.
Заключение
Подводя итог, если вы пишете игровой движок, вам все равно понадобится менеджер ресурсов. Если вы напишите "быстрое и грязное" частичное решение для VAO, то вы столкнетесь с точно такими же вопросами и проблемами при обработке текстур, дополнительных кадровых буферов и многих других объектов, поэтому лучше один раз реализовать хороший менеджер ресурсов.
Полезные статьи для начала:
Очень полезная книга:
Смена ВАО не так уж и дорога. Точные цифры явно сильно зависят от оборудования и платформы. Но просто чтобы дать вам общее представление, я измерил количество переключателей VAO / секунду в миллионах на ноутбуках несколько лет назад. Предположим, что ваша машина может переключать VAO 6 миллионов раз в секунду. Если вы хотите достичь 60 кадров в секунду с такой скоростью, вы можете переключать VAO 100000 раз за кадр.
Теперь, конечно, вы не хотите использовать все свое процессорное время для переключения VAO. Ваше приложение будет иметь множество других состояний, которые нужно изменить, вам придется обрабатывать собственную логику приложения, и в идеале вы не хотите, чтобы общая загрузка процессора была как можно ниже. Так что я бы не хотел приближаться к числу выше. Тем не менее, переключение VAO 1000 раз за кадр не должно быть проблемой на компьютере / устройстве с достаточно высокой производительностью.
Это действительно сопоставимо с другими изменениями состояния, которые вы обычно делаете между вызовами отрисовки. Вы всегда хотите свести их к минимуму (а также количество вызовов отрисовки). Но что касается изменений состояния, связывание другой VAO обычно является относительно дешевым.
Если у вас есть объекты с одинаковой геометрией, например, деревья в вашем примере, вам определенно не нужно иметь несколько копий одних и тех же данных. Это просто здравый смысл, и даже не имеет ничего общего с графикой. Истощение памяти, конечно, нежелательно. И даже если вы не в отчаянном кризисе памяти, наличие нескольких копий одних и тех же данных может все же снизить производительность, поскольку, вероятно, снизит частоту обращений в кэш.
Как разработать свою игру, чтобы она работала лучше всего, является довольно широким вопросом для этого формата. Ну, и я никогда не писал серьезную игру, так что я не обладаю идеальной квалификацией, чтобы давать вам советы. Мой первый инстинкт должен был бы иметь группу классов, которые определяют различные формы. Например, вы могли бы иметь TreeShape
который владеет геометрией (VAO и VBO) для дерева. То же самое для каждого персонажа. Затем, если ваша сцена содержит кучу деревьев, у вас есть Tree
класс, который описывает конкретные деревья, где экземпляры могут просто содержать информацию о положении / размере дерева, но все они имеют ссылку на один и тот же TreeShape
, Таким образом, все деревья используют один и тот же VAO/VBO, используя один и тот же TreeShape
и каждый конкретный Tree
содержит только информацию, которая на самом деле отличается для каждого экземпляра дерева.