Как работать с материалами в системе Entity / Component

13

Моя реализация E / C является базовой, где сущности - это просто идентификаторы, компоненты - данные, а системы работают с данными. Сейчас у меня проблемы с материалами объекта и рендерингом в целом. Для простых объектов у меня есть a ModelComponent, связанный с a RenderSystem, ModelComponentимеет идентификаторы буфера вершин, которые использует система рендеринга. Простое MaterialComponent, вероятно, будет иметь цветовую или зеркальную прочность и т. Д., Но я хотел, чтобы оно было достаточно гибким, чтобы можно было использовать более одного прохода рендеринга и общие «эффекты», которые не так просты, как простая переменная в MaterialComponent.

Пытаясь решить эти проблемы, я придумал два решения:

1 - Супер-универсальный компонент материала

Что-то вроде этого:

struct Material : public Component
{
    ShaderData* shader;
    std::vector<std::pair<std::string, boost::any>> uniforms;
    [...]
};

и в системе рендеринга я бы зацикливал и передавал униформу в шейдер. Я полагаю, это будет медленно, но достаточно быстро для моих целей.

2 - еще один уровень абстракции, MaterialData

Имея класс для переноса определенных материалов, который может быть унаследован любым специализированным материалом, базовый класс будет иметь что-то вроде, void set_shader_constants(ShaderData* d)но реализация зависит от каждого класса, и у него MaterialComponentбудет указатель на объект MaterialData.

Я не уверен, какой подход я бы предпочел, но ни один из них не затрагивает тему нескольких проходов или других сложных методов рендеринга.

Есть идеи, как этого добиться?

Люк Б.
источник

Ответы:

26

Материалы являются графической концепцией и принадлежат вашему рендереру. Рендерер - это слишком низкоуровневая часть архитектуры, чтобы быть построенной поверх системы сущностей. Системы сущностей должны быть для игровых объектов более высокого уровня. Не все должно быть компонентом, и, вообще-то, вообще плохая идея пытаться объединить все в одну такую ​​парадигму. Это создает решение с наименьшим общим знаменателем.

Следовательно, я бы посоветовал вам использовать другой подход:

  • Материал - это просто другой тип вашего рендерера.
  • Ваш рендерер имеет тип, который представляет «вещь, которую нужно нарисовать на экране». Часто они называются «экземплярами рендеринга» или «визуализируемыми» или даже «моделями». Этот тип имеет ссылку на материал, который он будет использовать при рисовании, и предоставляет общедоступный API, позволяющий потребителю средства визуализации устанавливать для этого материала все, что требуется.

По сути, это требует от вас взять ModelComponentи переименовать его Model, удалив зависимость от слоя сущности / компонента и, таким образом, переместить его на более низкий уровень абстракции, наряду с остальной частью вашего средства визуализации.

Затем вы делаете это:

  • На том же уровне абстракции, что и другие ваши компоненты, у вас есть некий «аспектный компонент», который представляет визуальное представление сущности. Этот компонент просто содержит ссылку на некоторый рендеринг (как описано выше), который в свою очередь содержит ссылку на материал. Компонент может предоставлять API для предоставления рендеринга (таким образом, позволяя клиентам манипулировать им) или может оборачивать API рендеринга для управления экспозицией. Это зависит от вас.

Это решает проблему взаимозависимости компонентов, поскольку модели и материалы являются компонентами; у объекта должен быть аспект или нет, и этот аспект должен иметь возможность кодировать все, что касается представления объекта, включая материал.

Это также дает вам гибкость в использовании других подходов с материальным объектом, которые было бы сложнее сделать с этим объектом как компонентом из-за отсутствия паритета с остальной частью абстракции системы рендеринга.

Ваша проблема с разрешением более сложных эффектов и многократных проходов - это проблема, которая может быть решена в основном в материале, предоставляя функции для запроса и устанавливая именованные константы шейдера, предоставляемые файлом шейдера материала. Это особенно верно, если вы используете файлы эффектов (в D3D), которые поддерживают несколько проходов и тому подобное. Даже если вы не используете файлы эффектов, вы можете раскрыть идею нескольких проходов из материала, каждый из которых имеет свои собственные шейдеры, и позволить API материала предоставить манипуляторы для этого. Скорее всего, было бы проще и понятнее интегрироваться в API рендеринга, поскольку материал теперь находится на том же уровне абстракции.


источник
1
Спасибо за ваш ответ, эта проблема мучила меня довольно долго, но создание рендера без ограничений E / C намного проще.
Люк Б.