Budujemy silnik: filozofia

15.12.2008 23:59 in grafika 3D, cg, OpenGL, programowanie, silnik

Na forum gamedev.pl znalazłem następujący wpis:

Naszły mnie wątpliwości co do sensu silnikow graficznych jako dużych, zaawansowanych projektów. Wiec, chodzi o to, że w dobie fixed-pipeline wygląd gry, efekty jakie w niej występowały, zależaly tylko i wyłącznie od programistów. Oni to, pisali w całości w kodzie wszystko to co mialo zostać wyrenderowane. Silnik wydawał się sensowną częścią gry, zawierał w sobie cały kod wszystkich fajnych rzeczy do których narysowania był zdolny i życie wydawało się proste. Jednak pojawiły się shadery, effect'y i wszystko co kiedyś musieli zawierać programiści w engine, tworzą map designerzy czy modelerzy.

Stąd moje pytanie - czy wartość silnika nie zmalała przez przypadek, jako następstwo programowalnych GPU, do frameworka którego rola sprowadza się do szybkiego renderowania tych wszystkich shaderow?

Wiele wody w wirtualnych rzekach upłynęło od czasu napisania tego posta, ale postaram się tutaj odpowiedzieć na to pytanie.

Otóż nie, rola silnika nie zmalała z powodu odejścia od fixed-pipeline. Powiem więcej: dopiero teraz jego rola stała się dominująca! Pomijam tap pisania software'owych rendererów, z których każdy miał siłą rzeczy inne możliwości (ale kiepskie możliwości sprzętu skutkowały kiepskimi -- tak czy inaczej -- efektami). W czasach świetności fixed pipeline każdy silnik stanowił bowiem z grubsza nakładkę na zwykły OpenGL-owy potok (jeżeli nie lubisz OGL, zamieniaj wszystkie jego wystąpienia na DX). Możliwości były wszakże mocno ograniczone. Jeżeli mgła, to raczej standardowa (plus jej konfiguracja). Światła? OK, ale poza podaniem kilku kolorów i pozycji światła nie dało się zbytnio zcustomizować.

Teraz mamy potężne narzędzie: shadery. Ale czy shader jest równoważny końcowej grafice? W prostych zastosowaniach (demonstracja efektu graficznego) generalnie tak. Ale w przypadku większych projektów (gier) użyty shader to tylko mały krok na drodze do wielkości. Dlaczego?

Po pierwsze, każdy shader jest -- mimo wszystko -- dosyć podobny. W dużym uproszczeniu możemy powiedzieć, że to takie NdotL z dodatkami. ;) Oczywiście te ,,dodatki'' to istota zagadnienia, ale sami przyznacie, że ,,zwykły'' (,,prosty'') shader do każdego silnika/renderera będzie podobny?

Po drugie, shader to nie tylko kod. To również (a może nawet przede wszystkim) pewne dane wejściowe. To my musimy zatroszczyć się o przekazanie odpowiednich macierzy, pozycji kamery i światła czy innych niezbędnych do obliczeń elementów. Zaimportowanie do silnika shadera wymagającego obliczeń w przestrzeni stycznej (tangentów) nie jest trywialne, jeżeli nie przewidzieliśmy takiej możliwości przy budowie modeli. Podobnie, ciężko nam będzie skorzystać z cubemapy (zwłaszcza dynamicznej), jeżeli nasza architektura tego nie uwzględniła.

Po trzecie, liczba kombinacji faz renderowania jest przeogromna. Każdy obiekt może być renderowany:

  • różnym rodzajem materiału: prostym, metalicznym (mapowanie środowiskowe), przezroczystym (lustra), ...
  • dla różnych świateł: kierunkowe, punktowe, spotlighty
  • uwzględniając zacienienie lub nie (plus różne techniki SM/SV)
  • z innym przetwarzaniem wierzchołków: prostym, z animacją na kościach, z displacement mappingiem, ...
  • w innym kontekście: wypełnianie Z bufora, rysowanie geometrii, rysowanie map cieni, rysowanie odbić, cubemap, testowanie przesłaniania

Jak widać, ilość tych kombinacji jest nietrywialna od ogarnięcia ze strony silnika. A do tego trzeba ów silnik napisać tak, by nasza gra działała z przyzwoitą wydajnością. To niełatwe zadanie, ale kto powiedział, że bycie programistą silnika jest proste? ;)

Temat budowy silnika będzie kontynuowany. Następna notka: organizacja shaderów (mam nadzieję, że wkrótce).

Comments:

  1. Reg

    Reg:

    Zgadzam się z Tobą. Ja dodatkowo uważam, że silnik powinien być biblioteką na tyle wysokiego poziomu, żeby ukrywać szczegóły takie jak shadery i dawać dostęp do czegoś bardziej abstrakcyjnego, takiego jak materiały. Jako idealny przypadek możnaby sobie wyobrazić taki silnik, w którym ten sam kod użytkownika mógłby renderować grafikę na GeForce 9600, Xbox 360, PS3, ale też na GeForce 2 MX i na telefonie komórkowym, odpowiednio tłumacząc żądane parametry materiału na shader (lub ustawienia Fixed Pipeline), dostosowane do możliwości platformy.

    21.12.2008 13:11:15

Leave comment: