Фон:
Я проектирую простую систему трехмерного рендеринга для архитектуры типов систем сущностей с использованием C ++ и OpenGL. Система состоит из рендера и графа сцены. Когда я закончу первую итерацию рендера, я смогу распределить граф сцены в архитектуру ECS. На данный момент это так или иначе заполнитель. Если возможно, мои цели для рендера:
- Простота . Это для исследовательского проекта, и я хочу иметь возможность легко изменять и расширять мои системы (отсюда и подход ECS).
- Производительность . В моей сцене может быть много маленьких моделей, а также большие объемы с большой геометрией. Недопустимо получать объекты из контекста OGL и геометрии буфера каждый кадр рендеринга. Я стремлюсь к локальности данных, чтобы избежать промахов кэша.
- Гибкость . Он должен уметь отображать спрайты, модели и объемы (вокселы).
- Отделен . Граф сцены может быть преобразован в основную архитектуру ECS после того, как я напишу свой рендер.
- Modular . Было бы неплохо иметь возможность поменять местами разные рендеры без изменения графика сцены.
- Ссылочная прозрачность , означающая, что в любой момент времени я могу назначить ей любую действительную сцену, и она всегда будет отображать одно и то же изображение для этой сцены. В частности, эта цель не является обязательной. Я подумал, что это поможет упростить сериализацию сцен (мне нужно будет уметь сохранять и загружать сцены) и дать мне возможность переключаться между различными сценами во время выполнения для целей тестирования / экспериментов.
Проблема и идеи:
Я предложил несколько разных подходов, чтобы попробовать, но я борюсь с тем, как кэшировать ресурсы OGL (VAO, VBO, шейдеры и т. Д.) Для каждого узла рендеринга. Ниже приведены различные концепции кеширования, которые я уже придумал:
- Централизованный кеш, Каждый узел сцены имеет идентификатор, а средство визуализации имеет кэш, который отображает идентификаторы для визуализации узлов. Каждый узел рендеринга содержит VAO и VBO, связанные с геометрией. Промах кэша получает ресурсы и сопоставляет геометрию с узлом рендеринга в кэше. Когда геометрия изменяется, устанавливается грязный флаг. Если средство рендеринга видит флаг грязной геометрии во время итерации по узлам сцены, он создает буфер данных, используя узел рендеринга. Когда узел сцены удаляется, событие транслируется, и средство визуализации удаляет связанный узел визуализации из кэша при освобождении ресурсов. Кроме того, узел помечается для удаления, а средство визуализации отвечает за его удаление. Я думаю, что этот подход наиболее близко достигает цели 6, а также рассматривает 4 и 5. 2 страдает от дополнительной сложности и потери локальности данных при поиске карт вместо доступа к массиву.
- Распределенный кеш . Аналогично выше, за исключением того, что каждый узел сцены имеет узел рендеринга. Это обходит поиск карты. Для адресации данных узлы рендеринга могут быть сохранены в рендерере. Тогда узлы сцены могут вместо этого иметь указатели для визуализации узлов, а средство визуализации устанавливает указатель на промах кэша. Я думаю, что этот вид имитирует подход, основанный на компонентах, поэтому он будет соответствовать остальной архитектуре. Проблема здесь в том, что теперь узлы сцены содержат данные, специфичные для реализации рендерера. Если я изменю способ рендеринга вещей в рендерере (например, рендеринг спрайтов против томов), мне нужно изменить узел рендеринга или добавить больше «компонентов» в узел сцены (что также означает изменение графа сцены). С другой стороны, это кажется самым простым способом запустить и запустить мой рендер с первой итерацией.
- Распределенные метаданные . Компонент метаданных кэша рендерера хранится в каждом узле сцены. Эти данные не зависят от реализации, а содержат идентификатор, тип и любые другие соответствующие данные, необходимые для кэша. Затем поиск в кэше может быть выполнен непосредственно в массиве с использованием идентификатора, и тип может указывать, какой тип рендеринга использовать (например, спрайты против томов).
- Посетитель + распределенное отображение . Рендерер - это посетитель, а узлы сцены - это элементы в шаблоне посетителя. Каждый узел сцены содержит ключ кэша (например, метаданные, но только идентификатор), которым манипулирует только средство визуализации. Идентификатор может использоваться для массива вместо общего поиска карты. Рендерер может позволить узлу сцены отправлять другую функцию рендеринга в зависимости от типа узла сцены, и идентификатор может использоваться любым кешем. Идентификатор по умолчанию или идентификатор вне диапазона будет указывать на отсутствие кэша.
Как бы вы решили эту проблему? Или у тебя есть предложения? Спасибо за чтение моей стены текста!
Ответы:
Перечитав ваш вопрос, я чувствую, что вы слишком усложняете проблему. Вот почему:
На самом деле существует только два типа системы рендеринга: Вперед и Отложено, ни один из которых не зависит от графа сцены.
Единственные проблемы с производительностью, которые вы действительно должны получить с любой системой рендеринга, должны быть связаны с большим количеством поли, неэффективным шейдером и клиентским кодом.
Промахи в кеше действительно снижают производительность, но они не совсем те монстры, о которых можно подумать. 80% ваших улучшений производительности будет от более эффективного алгоритма. Не делайте ошибку предварительной оптимизации вашего кода.
Это говорит:
Если вы используете доморощенный сценограф, тогда вы уже должны использовать интерфейс "Renderer" (или базовый класс) для разработки визуализации части кода вашего сценографа. Хорошим подходом к этому является использование шаблона посетителя с использованием двойной диспетчеризации, поскольку вы вполне можете использовать многие типы узлов графа, такие как цвет, текстура, сетка, преобразование и т. Д. Таким образом, во время цикла рендеринга все, что нужно сделать для рендеринга, это сначала пройдитесь по древовидной структуре сцены, передавая себя в качестве аргумента. Таким образом, рендерер - это просто набор шейдеров и, возможно, кадровый буфер или два. Результатом этого является то, что код поиска / удаления больше не нужен для системы рендеринга, а только сам граф сцены.
Конечно, есть и другие способы решения проблем, с которыми вы сталкиваетесь, но я не хочу давать слишком многословный ответ. Итак, мой лучший совет - сначала поработать над чем-то простым, затем расширить его, чтобы найти его слабые стороны, а затем поэкспериментировать с другими подходами и посмотреть, в чем их сильные / слабые стороны.
Тогда вы сможете принять обоснованное решение.
источник