Jak obchodzić się z materiałami w systemie Entity / Component

13

Moja implementacja E / C jest podstawowa, w której jednostki to tylko identyfikatory, komponenty to dane, a systemy działają na danych. W tej chwili mam problem z materiałami obiektowymi i renderowaniem w ogóle. Dla prostych objetcs mam a ModelComponent, powiązane z a RenderSystem, ModelComponentma identyfikatory bufora wierzchołków, których używa system renderujący. Prosty MaterialComponentprawdopodobnie miałby siłę koloru lub połysku itp., Ale chciałem, aby był wystarczająco elastyczny, aby umożliwić więcej niż jedno przejście renderowania i ogólne „efekty”, które nie są tak proste jak zwykła zmienna w MaterialComponent.

Próbując rozwiązać te problemy, wpadłem na dwa rozwiązania:

1 - Super-ogólny składnik materiałowy

Coś takiego:

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

a w systemie renderowania zapętlałem mundury i przekazywałam je do shadera. Przypuszczam, że byłoby to powolne, ale wystarczająco szybkie do moich celów.

2 - Kolejna warstwa abstrakcji, MaterialData

Mając klasę do owijania określonych materiałów, które mogą być dziedziczone przez dowolny specjalistyczny materiał, klasa podstawowa miałaby coś takiego, void set_shader_constants(ShaderData* d)ale implementacja zależy od każdej klasy i MaterialComponentmiałaby wskaźnik do obiektu MaterialData.

Nie jestem pewien, które podejście wolę, ale żadne z nich nie dotyczy tematu wielokrotnych przejść ani innych skomplikowanych technik renderowania.

Masz pomysł, jak to osiągnąć?

Łukasz B.
źródło

Odpowiedzi:

26

Materiały są koncepcją graficzną i należą do renderera. Mechanizm renderujący jest zbyt niskim poziomem architektury, aby można go było zbudować na systemie encji. Systemy jednostek powinny być przeznaczone dla obiektów gry wyższego poziomu. Nie wszystko musi być komponentem, a tak naprawdę generalnie złym pomysłem jest próba zmuszenia wszystkiego do jednego takiego paradygmatu. Tworzy rozwiązanie o najczęstszym mianowniku.

W związku z tym radzę przyjąć inne podejście:

  • Materiał jest tylko kolejnym rodzajem renderera.
  • Twój renderer ma typ, który reprezentuje „rzecz, którą należy narysować na ekranie”. Często są one nazywane „instancjami renderowania” lub „renderami”, a nawet „modelami”. Ten typ zawiera odniesienie do materiału, którego będzie używał podczas rysowania, i udostępnia publiczny interfejs API, który umożliwia konsumentowi renderera ustawienie tego materiału na dowolne, co jest pożądane.

Zasadniczo wymaga to wzięcia ModelComponentnazwy i zmiany jej nazwy Model, usunięcia zależności od warstwy encji / komponentu, a tym samym przeniesienia jej do niższej warstwy abstrakcji wraz z resztą renderera.

Następnie robisz to:

  • Na tej samej warstwie abstrakcji, co inne komponenty, masz jakiś „komponent aspektu”, który reprezentuje wizualną prezentację bytu. Ten komponent zawiera tylko odniesienie do jakiegoś renderowalnego elementu (jak opisano powyżej), który z kolei zawiera odniesienie do materiału. Składnik może zapewniać interfejs API do wyświetlania renderowania (umożliwiając w ten sposób klientom manipulowanie nim) lub może owijać interfejs API renderowania w celu kontrolowania ekspozycji. To zależy od Ciebie.

Rozwiązuje to problem współzależności komponentów, na który napotykasz, ponieważ modele i materiały są komponentami; byt powinien mieć albo aspekt, albo nie, i ten aspekt powinien być w stanie zakodować wszystko o prezentacji bytu, w tym materiał.

Zapewnia to również elastyczność w przyjmowaniu innych podejść do obiektu materialnego, co byłoby trudniejsze w przypadku tego obiektu jako komponentu z powodu braku parzystości z resztą abstrakcji systemu renderowania.

Problem polegający na dopuszczaniu bardziej złożonych efektów i wielokrotnych przebiegów można rozwiązać przede wszystkim w materiale, wystawiając funkcje na zapytania i ustawiając nazwane stałe modułu cieniującego ujawnione w pliku modułu cieniującego materiału. Jest to szczególnie prawdziwe, jeśli używasz plików efektów (w D3D), które obsługują wiele przejść i tym podobne. Nawet jeśli nie używasz plików efektów, możesz ujawnić ideę wielu przejść z materiału, każdy z odrębnymi modułami cieniującymi, i pozwolić interfejsowi API materiału udostępnić do tego celu manipulatory. Najprawdopodobniej integracja z interfejsem API renderowania byłaby łatwiejsza i czystsza, ponieważ materiał jest teraz na tym samym poziomie abstrakcji.


źródło
1
Dzięki za odpowiedź, ten problem trapił mnie od dłuższego czasu, ale tworzenie renderera bez ograniczeń E / C jest znacznie łatwiejsze.
Luke B.