Programowanie Gier -> Pracownia Michalisa

Pracownia: piątek, 10:15-12:00, sala 110.

Pracownia 110 to Windowsy, jeżeli ktoś woli pokazywać pod Linuxem (do czego Michalis zachęca :) ), to Michalis ma Linuxa w swoim pokoju (z dość starą kartą graficzną NVidii) i na laptopie (ze stosunkowo dobrą ATI; będę go przynosił do ii kiedy będzie termin oddawania zadań).

PomocSpisTreści

  1. Zasady
  2. Punktacja
  3. Zadanie 1
  4. Zadanie 2
  5. Zadanie 3
    1. Pierwszy etap: pomysł na grę, dźwięk
    2. Drugi etap: shadery
    3. Etap ostatni: końcowa gra !

Zasady

Punktacja

Punktacja:

Zadanie 1 (2D)

20%

Zadanie 2 (3D)

25%

Zadanie 3 (projekt końcowy, będzie podzielone na wiele "podzadań")

55%

Od 50% jest zaliczenie, przy czym za projekt końcowy trzeba uzyskać przynajmniej 30%.

Zadanie 1

W ramach "wprawki", zaimplementuj prostą grę z grafiką 2D. Podstawowe umiejętności które trzeba pokazać to posługiwanie się SDLem do grafiki 2D, ładowanie i wyświetlanie obrazków (można posłużyć się SDL_Image i rysować przez SDLa, ale można też użyć dowolnej innej biblioteki open-source do ładowania obrazków i rysować przez OpenGLa). Naturalnie trzeba też zaimplementować prostą logikę gry, to ma być coś grywalnego --- przynajmniej na kilka minut :)

Każdy sam wybiera jaką grę implementuje, myślę że to sprawi że rezultaty będą ciekawsze. Dobre pomysły to zaimplementowanie jakiejś bardzo, bardzo starej gry (DOSowej albo na automaty). Istnieje cała masa gier tego typu, zaimplementowanie ich przy użyciu nowoczesnych bibliotek jak SDL może być i łatwe i zabawne.

Konkretne pomysły można czerpać np. z "the crypt" na abandonii. Poza odmianami pacmana, tetrisa, SpaceInvaders etc. można tam znaleźć trochę mniej znanych "perełek", np. sopwith. Nie trzeba nawet grać w te gry, wystarczy popatrzeć na screenshoty aby nabrać inspiracji :)

Termin na wykonanie zadania: 27 marca.

Zadanie 2

Drugie zadanie to przećwiczenie podstawowych elementów gier 3D: formaty 3D, nawigacja, kolizje, frustum culling.

  1. Przede wszystkim, trzeba nauczyć się ładować modele 3D z plików. Do wyboru są:

    1. Collada. Zalecam wersję 1.4.1+ (niekompatybilne z 1.3, ale 1.3 jest stare i nie warto się nim zajmować). Collada jest kodowana w XML, w każdym języku programowania mamy bibliotekę do odczytu XML.

    2. X3D. Zalecam implementację kodowania X3D XML (najprostsze). Jeżeli ktoś naprawdę chce, może też zaimplementować VRML 2.0 — chociaż VRML 2.0 nie ma kodowania XML (trzeba będzie napisać własny lekser+parser) i jest podzbiorem X3D jeśli chodzi o możliwości (X3D to de facto "VRML 3.0"). Jedyna zaleta to że niektóre programy nie mają eksportu do X3D, ale mają do VRML 2.0, ale może być łatwiej znaleźć i używać wtedy konwerterów z VRML 2.0 do X3D XML.

      Podstawowa lektura to specykacja X3D (Architecture and base components) (razem ze specyfikacją kodowania XML), napisałem też stosunkowo łagodne wprowadzenie do VRML 1.0/2.0 dawno temu, może komuś się przyda.

    3. Wavefront OBJ.

      Napisałem dawno temu krótki opis formatu Wavefront OBJ z linkami, może będzie użyteczny.

    Nie ukrywam że zalecam X3D lub Colladę, są trudniejsze ale też pozwalają na bardziej zaawansowane sztuczki (chociażby shadery). Ale nie będzie to uwzględniane w ocenie zadania (bo, w zależności od tego jaką grę będziecie chcieli zrobić na końcu, być może Wavefront OBJ z ew. własnymi rozszerzeniami będzie zupełnie Ok). Jeżeli ktoś zna inne dobre formaty 3D, to można pytać Michalisa i ew. uzyskać pozwolenie :), ale podkreślam że zależy nam najbardziej na nowoczesnych formatach które pozwalają na wiele rzeczy do grafiki 3D w OpenGL, najlepiej żeby miały otwartą specyfikację (nie "domyśloną" jak 3DS), najlepiej żeby miały wersję tekstową (przy początkowych zabawach formatem 3D jest to naprawdę ułatwienie, a czas ładowania nie jest tak ważny), i żeby można było łatwo je rozszerzać (dodawać nowe pola/węzły etc. specyficzne dla naszego silnika). Takie starocie jak np. 3DS odpadają.

    Nie trzeba implementować wszystkiego co może się znaleźć w tych formatach (zwłaszcza w przypadku X3D byłby to overkill na kilka lat :) ). W ramach tego zadania interesuje nas tylko odczyt statycznego modelu 3D z:

    • Geometrią wyrażoną jako lista ściań, gdzie każda ściana to lista > 3 indeksów do tablicy wierzchołków. (Taką geometrię renderujemy przez VBO w OpenGLu w naturalny sposób.)

    • Materiałami (przynajmniej elementarne diffuse, specular). W ramach tego zadania potrzebujemy obsługi materiału per-object (gdzie "object" to jakaś większa część modelu 3D). Nie potrzebujemy obsługi bardziej skomplikowanych materiałów per-face albo per-vertex.

    • Teksturami. Trzeba odczytać i użyć nazwę pliku z teksturą (wystarczy nam jedna tekstura per-object, nic bardziej skomplikowanego), oraz mapowanie współrzędnych tekstury na nasz model. Trzeba przy okazji nauczyć się ładować tekstury OpenGLa jeżeli ktoś jeszcze nie umie (można wykorzystać dowolną bibliotekę open-source do odczytu obrazków, np. SDL_Image).

    • Wektorami normalnymi. Chcemy umieć odczytywać modele z różnym "smoothing" wektorów normalnych, czyli potencjalnie każdy indeks na inny wektor normalny. Opcjonalnie można też zaimplementować odczyt lub własne generowanie wektorów normalnych, per-face i/lub per-vertex i/lub per-vertex-index (w/g czegoś jak creaseAngle w X3D).

  2. Naturalnie, trzeba zaimplemtować renderowanie załadowanego modelu 3D poprzez OpenGL.

    Kod ładujący i wyświetlający modele powinien być elegacko zorganizowany, żeby móc łatwo załadować kilka modeli 3D i wyświetlać je na raz.

  3. Trzeba przetestować swój kod na różnych modelach 3D. Ściągniętych z sieci, a także zrobionych przez siebie. Chociaż nasz wykład jest nastawiony na programowanie, nie na tworzenie danych do gry, ale musimy posiadać elementarne zdolności tworzenia danych 3D. Trzeba nauczyć się jak tworzyć elementarne obiekty 3D w wybranym przez siebie programie do modelowania 3D (np. z free/open-source/software: blender, wings3d, art of illusion, z innych: 3ds Max jest zainstlowany na pracowniach ii (sala chyba 108), zresztą można ściągnąć wersję trial). Trzeba nauczyć się tworzyć proste modeliki w wybranym programie (podkreślam: proste! To nie jest wykład z modelowania, na początek wystarczy jeżeli umiecie zrobić coś co wygląda jak pudełeczko z czterema kółkami albo dwa pokoje połączone korytarzem, nałożyć na to kolor i teksturę, i już.) Przede wszystkim, trzeba przećwiczyć eksportowanie Waszych modeli do formatu 3D który umiecie załadować w swoim programie.

  4. Kiedy już będziemy mieli eleganckie modele 3D, trzeba zaimplementować nawigowanie z kolizjami po załadowanym levelu 3D. W ramach tego zadania level może być zupełnie statyczną sceną załadowaną z jednego pliku 3D.

    Gracz powinien móc poruszać się w przód/tył, obracać lewo/prawo, robić strafe (krok w bok) w lewo/prawo (mouse look nie trzeba implementować, chyba że ktoś chce).

    Kolizje z levelem mają być proste, gracz to zwykła sfera. (Nie trzeba implementować grawitacji, wchodzenia po schodach, wall-sliding... Wystarczą proste testy tak/nie na kolizję ze "swept sphere" albo "odcinek + sfera"). Kolizje muszą używać wybranej struktury drzewiastej.

  5. Na końcu, trzeba zaimplementować frustum culling. Wasz model powinien w naturalny sposób składać się z wielu obiektów/kształtów 3D, każdy z nich musi mieć swoje bounding box lub sphere (pozostawiam Wam do wyboru sferę lub box; ambitni mogą spróbować oba, chociaż dla frustum culling to naprawdę nie będzie miało zazwyczaj znaczenia). Podczas renderowania,podajemy do OpenGLa tylko te kształty które potencjalnie kolidują z frustum.

    Wasze frustum culling nie musi używać struktury drzewiastej. Na potrzeby tego zadania, wystarczy iterować w każdym display po wszystkich kształtach i sprawdzać dla każdego kształtu z osobna czy potencjalnie wpada we frustum. Szczegóły i linki do przykładów jak to zrobić były na wykładzie.

Na całe zadanie dajemy sobie 4 tygodnie od ostatnich zajęć, czyli do 24 kwietnia. Termin ostateczny: 8 maja.

Ponieważ jednak zadanie jest dłuższe, chcę żeby wszyscy pokazali mi że za dwa tygodnie (10 kwietnia) mają wykonany co najmniej podstawowy odczyt i renderowanie wybranego formatu 3D. 10 kwietnia mamy wprawdzie wolne, ale nie zależy mi na jakimś wielkim sprawdzaniu, więc nie potrzebujemy do tego pracowni --- po prostu pokażcie mi demo po wykładzie w czwartek 9 kwietnia, albo nawet przyślijcie screenshoty emailem (bo kod wrzucicie do svn).

Zadanie 3

Zadanie 3 to po prostu projekt końcowy. Elementarne założenia:

  1. Ma to być grywalna gra, nie tylko engine.
  2. Chcę ocenić Wasze zdolności programistyczne, więc gra musi mieć coś 3D i wykorzystywać sporo rzeczy omawianych na wykładzie. Jednocześnie, nie chcę oceniać Waszych umiejętności posługiwania się programami do tworzenia grafiki 2D lub 3D, więc nie wymagam żeby gra miała 30 leveli i 10 potworków. Dla niektórych gier, wystarczy nawet 1 level i 1 potworek, jeżeli będą wystarczająco skomplikowane i sprawią że gra będzie ciekawa. Oczywiście dla niektórych gier w ogóle nie będzie pojęcia level/potworek...

Rzeczy co do których daję Wam zupełnie wolną rękę:

  1. Gatunek i klimat gry wybieracie sami (edukacyjny survival horror na bazie pasjansa?). Można zrobić strzelankę, można zrobić przygodówkę, strategię, cokolwiek Wam przyjdzie do głowy. W ramach inspiracji, można przejrzeć np. http://en.wikipedia.org/wiki/Video_game_genres. Tylko podkreślam: to nie jest zadanie z projektowania światów 3D, ani pisania dobrych scenariuszy do gier. Wymyślcie coś krótkiego, co zdołacie skończyć w te półtora miesiąca do końca wykładu. Jeżeli wymyślicie coś epickiego, to śmiało: ale zamiast robić "Moją Wielką Grę", zróbcie tylko pierwszy level / rozdział / etc. Waszej wymarzonej gry.

  2. Sieciowość: ten element programowania gier nie został omówiony na wykładzie tak jak na to zasługuje, zwyczajnie nie ma to czasu, mamy na ii całe przedmioty temu poświęcone, a i tak każdy rodzaj gry ma swoją specyfikę. Odradzam porywanie się na grę sieciową czasu rzeczywistego. (Gra podzielona na tury, z ograniczoną ilością graczy, z założeniem szybkiej sieci lokalnej, gdzie gracze ufają sobie i nie stosują cheatów --- to może nie być takie straszne do zaimplementowania.) Jeżeli chcecie zrobić rozgrywkę "człowiek vs człowiek", pomyślcie np. nad prostszymi rozwiązaniami, jak "split-screen". Ostatecznie, decyzja czy (i jak) zrobić grę sieciową jest Wasza --- ale pamiętajcie że roboty i tak jest dużo, więc nie porywajcie się na to chyba że rzeczywiście bez tego Wasza gra nie ma sensu.

Wymagania:

  1. Gra ma mieć elementy 3D zrobione w OpenGLu. Piszę "elementy", bo nie trzeba robić typowej kamery 3D w stylu FPS (z oczu gracza albo zza pleców postaci). Można kombinowac, ograniczyć kamerę np. do widoku z góry na świat, z perspektywą albo ortogonalną (ale, żeby nie było zbyt łatwo, nie można zupełnie oszukiwać i robić 99% gry w 2D...).
  2. Naturalnie, elementy 3D muszą być ruchome. Swoboda ruchu gracza i innych elementów nie może być "tile-based", gdzie kolizje robimy przez proste testy ze stałą tablicą 2D albo 3D. Świat musi być możliwie dynamiczny. Wiem że to brzmi trochę mało precyzyjnie, ale trudno napisać coś precyzyjnego jednocześnie dając Wam dużą swobodę na wymyślenie własnej gry.
  3. Trzeba mieć jakąś metodę badania kolizji. Z graczem, i/lub pomiędzy elemantami świata --- cokolwiek będzie odpowiednie. Nie narzucam konkretnej techniki, ale musi być szybka i odpowiednia do danej gry. Napisałem że "swiat musi być dynamiczny" w poprzednim punkcie właśnie po to aby zmusić Was do jakiejś mniej trywialnej metody sprawdzania kolizji.
  4. Trzeba mieć jakś metodę obcinania dużej sceny dla OpenGLa. Może to być frustum culling zrobione w ramach zad2, może być coś innego (portale? hardware occlusion query?).
  5. Gra musi mieć dźwięk. Nie narzucam używania OpenAL, ale trzeba użyć czegoś open-source. Dźwięk musi być co najmniej stereo, co najmniej uwzględniający odległość od źródła dźwięku. Najlepiej żeby po prostu był to dźwięk w przestrzzeni 3D. Musi być możliwość załadowania dłuższych dźwięków (ścieżka z muzyką, albo tekst mówiony).
  6. Trzeba użyć przynajmniej dwóch z trzech nie-trywialnych technik renderowania:
    • bump mapping
    • lustra przez cube environment mapping, albo inne zastosowania render-to-texture (niekoniecznie do cube environment mapping, może być np. do renderowania portali (jak w Portal) / widoku z kamer (jak w Duke Nukem 3D))
    • cienie przez shadow maps albo shadow volumes albo volumetric lightmapping
  7. Trzeba użyć shaderów GLSL albo Cg.
  8. Trzeba wykorzystać albo zewnętrzny engine fizyki, albo zintegrować się z zewnętrznym językiem skryptowym.

Na razie to tyle.

Pierwszy etap: pomysł na grę, dźwięk

  1. Wymyśl jaką grę chcesz robić. Ustal dokładnie jakich danych będziesz potrzebował (jakie/ile modeli 3D, jakie grafiki?). Ustal jak zrobisz podstawowe punkty z wymagań --- jak dynamiczny jest świat, jak zrobić na nim dobrze wykrywanie kolizji? Jak zrobić cienie? Czy bardziej przyda Ci się engine fizyki, czy porządny język skryptowy? Etc. Wreszcie: ile z kodu źródłowego zadania 2 wykorzystasz?
    • Zapisz to pokrótce w pliku tekstowym. Nie zależy mi na żadnym oficjalnym raporcie, nie starajcie się formatować żadnego pięknego dokumentu. Najzupełniej wystarczy zwykły plik tekstowy, krótki ale treściwy. Ma to być precyzyjny opis, odpowiadać na wszystkie pytania powyżej, wyjaśniać jak spełnicie wymagania projektu, opisywać gatunek/klimat gry, etc.

      Po czym koniecznie skonsultuj się z Michalisem czy jest Ok, czy coś dodać, czy za łatwe etc.

  2. W ramach rozrywki, zaimplementuj dźwięk. Nie musi to jeszcze być zaimplementowane jako część Waszej gry. Nie musi to też być zaimplementowane jako dodatek do kodu z zadania 2. Po prostu --- pokażcie że umiecie wykorzystać jakąś bibliotekę open-source do robienia dźwięku.

Termin: 22 maja.

Drugi etap: shadery

Dopisz do swojego kodu ładującego i wyświetlającego modele 3D możliwość używania shaderów. Omawialiśmy GLSL na wykładzie, i myślę że zintegrowanie z GLSL będzie prostsze (skoro i tak jesteśmy nastawieni tylko na OpenGL), ale jeżeli ktoś chce --- można alternatywnie użyć Cg.

Nie chcę na tym etapie zmuszać Was do pisania większych shaderów, chodzi tylko o to żeby była możliwość załadowania shaderów i nałożenia ich na Wasze obiekty 3D, można testować z trywialnymi shaderami z wykładu.

Precyzyjnie wymagania/rekomendacje:

Na przykład dla Wavefront OBJ można dodać obsługę linijek zaczynających się od tokenów "vertshader", "fragshader":

o Obiekt1
vertshader nazwa_pliku_z_vertex_shader.vs
fragshader nazwa_pliku_z_fragment_shaderem.fs
....
o Obiekt2
vertshader nazwa_pliku_z_vertex_shader_2.vs
fragshader nazwa_pliku_z_fragment_shaderem_2.fs
....

(Nie, to nie jest żadne oficjalne rozszerzenie Wavefront OBJ, wymyśliłem to przed chwilą.) Można zrobić shadery dla każdego obiektu ("o") albo grupy ("g") Wavefronta, co Wam będzie wygodniej.

Kto obsługuje Colladę, może odczytywać shadery podążając za specyfikacją Collady, ale pozwalam też na chwilę zignorować standard i rozszerzyć XML Colladę tak jak Wam będzie wygodnie to zaimplementować.

Acha, i jeszcze jedno wymaganie:

Acha, można użyć funkcji OpenGLa 2.0 albo rozszerzeń ARB do shaderów (ARB_shader_objects, ARB_vertex_shader, ARB_fragment_shader, ARB_shading_language_100). Które będzie Wam wygodniej (albo: które Wasz OpenGL implementuje).

Czyli w skrócie, trzeba zaimplementować to co opisałem w sekcji API OpenGLa do shaderów na wykładzie.

Termin: za tydzień, czyli 29 maja.

Etap ostatni: końcowa gra !

(Poniżej skrót maila:)

Czas na skończenie projektu macie do 28 czerwca. Tak, to już w czasie sesji. Nie, nie ustaliliśmy jeszcze kiedy będzie egzamin, ale wiemy już na pewno że do oceny końcowej (z wykładu) 50% punktów będzie branych z egzaminu (łatwego!, jak obiecywaliśmy) a 50% z projektu końcowego (który jest na tym przedmiocie najważniejszy, tak jak ostrzegaliśmy od początku :) ).

Nie będę już narzucał Wam kolejnych tygodniowych zadań, ponieważ rozwój każdej gry powinien już biec swoim torem. Każdy z Was wie najlepiej w jakiej kolejności musi dodawać kolejne elementy gry żeby pracowało się Wam wygodnie, szybko, i żeby powstała gra i grywalna i stabilna.

Osoby które pracowały mają już gotowe techniczne podstawy (engine do wyświetlania 3D z shaderami, kolizjami i dźwiękiem). Z dużych rzeczy technicznych pozostało Wam zrobić ładne efekty graficzne (bump mapping i/lub cienie i/lub lustra etc.) i zintegrować się z fizyką albo językiem skryptowym. I, co najważniejsze, oczywiście zaimplementować całą grę którą zaplanowaliście. Sami decydujecie od teraz w jakiej kolejności to wszystko zrobicie.

Jedna moja rada (a na ile użyteczna, zdecyduje każdy sam patrząc na swój kod i cele gry): zanim zajmiecie się polerowaniem silnika, spróbujcie zrobić "szkicową" wersję "alpha" Waszej gry przy użyciu takiego silnika 3D jakie macie dzisiaj. Zasugeruję nawet więcej: spróbujcie zrobić to w tydzień, serio. Mówiąc wprost, po prostu spróbujcie sklecić Waszą grę na szybko, byle jak, używając silnika takiego jaki macie. Potem wszystko przerobicie --- ale w ciągu tygodnia robienia takiego "szkicu" gry zorientujecie się jak szybko to idzie, co konkretnie jest potrzebne do gry, gdzie Wasz silnik wymaga poprawy, etc. Pamiętajcie że wymagania techniczne (ta długa lista na początku zadania) to jedno, a drugim wymaganiem jest cały czas "chcemy zrobić grywalną grę".

Acha, i jeszcze jedno: chociaż nie ma konkretnego zadania na najbliższe piątki, zapraszam a nawet wymagam pojawiania się na pracowni w czerwcu. Przychodźcie i pokazujcie mi co tydzień Wasze postępy.

(Skrót informacji z maila 19 czerwca:)

Michalis ma miękkie serce i zgodził się żeby ostateczny (ale to naprawdę kompletnie-bezwzględnie-nieodwołalnie ostateczny) termin oddawania projektów był 10 lipca. Co nie zmienia faktu że 28 czerwca (oficjalny termin) trzeba pokazać przynajmniej szkielet gry (czytaj: coś co spełnia chociaż część założeń projektu, i ma coś więcej niż tylko wymagania na "etap drugi - shadery").