2015-02-09
Föreläsningens syfte Syfte: Ge kännedom om ett antal tekniker som kan vara användbara i en FPGA-baserad dator som ska generera ut mer eller mindre avancerad datorgrafik Metod: Historiska nedslag hos ett antal olika TV-spelskonsoller från 8 och 16-bitars eran.
Tidig datorgrafik CRT (Cathode Ray Tube) där avlänkningsmagneter i X och Y-led styrs av D/A-omvandlare kopplad till processorn (Eller om man så vill, ett oscilloskop kopplat i X-Y läge) Användes av: Vetenskaplig visualisering på tidiga datorer, gamla arkadspel, Vectrex Uråldrigt exempel (elektronrörsbaserat!): SAGE http://youtu.be/iccl4inqcfo?t=52s Historiskt exempel Vectrex: http://youtu.be/xlson0x4_j4?t=4m6s Modernt exempel: Beams Of Light by TRSI - https://www.youtube.com/watch?v=lvdwxkzvyc0
VGA-signalen Tre analoga signaler (Röd, Grön, Blå) Två synkpulser (vertikal och horisontell) (DDC2: En I 2 C-buss som används för att detektera vilken typ av skärm som är ansluten.)
Grafik med extremt enkel hårdvara En I/O-port är kopplad direkt till grafikutgången Kräver att du skriver klockcykelexakt kod för att mata ut exakt rätt data vid exakt rätt klockcykel. (Detta underlättas lite om du har en timer i hårdvaran så att inte exakt all kod måste vara skriven på detta sätt genom att du exempelvis kan göra annat under vblank.) Exempel: Craft av Linus Åkesson: https://www.youtube.com/watch?v=vpz5byixifm
Variant på CPU-kopplad VGA-utgång En mikrokodad processor har normalt tre faser: Hämtfas, adressfas och utförandefas. Ändra så att fyra faser används: Grafikfas, hämtfas, adressfas, utförandefas CPU-hårdvaran kan (delvis) återanvändas till att skicka ut grafikdata. Fördelen är att vi inte får problem med att synkronisera tillgång till grafikminne mellan CPU och GPU. Mikrokoden skrivs förslagsvis så att alla faser tar lika lång tid...
Grafik på Atari 2600 Första populära TV-spelet Extremt enkel grafikhårdvara: Hårdvara för att rita en boll (1,2,4 eller 8 pixlar bred) Hårdvara för att rita två missiler (1,2,4 eller 8 pixlar bred) Hårdvara för att rita två spelare (8 pixlar breda, konfigurerbart utseende(!)) Hårdvara för att rita bakgrunden (20 bitars minne, räcker till en halv(!) rad). (Plus en bit som säger om raden ska speglas eller dupliceras på andra halvan av raden.) För att få ut någon vettig grafik måste alla dessa register uppdateras för varje rad som ritas ut!
Lärdomar: Atari 2600 Även med extremt enkel grafikhårdvara kan ganska avancerad grafik skapas (förutsatt att du är beredd på att det är ganska drygt att programmera spelet) Tips: Atari 2600 har inbyggd detektion av kollision mellan alla typer av objekt samt mellan bakgrund och objekt. Detta underlättar mycket om ni ska skriva spel i assembler! Exempel på grafik som kan skapas utifrån detta: https://www.youtube.com/watch?v=ucrylobga0g - 75 Atari 2600 games https://www.youtube.com/watch?v=xm1cbbepcdk - Liquid Candy/Noice (Atari VCS/2600 demo)
Förslag på system: CPU + GPU anpassad till just ditt spel Förslag på hårdvarusystem: CPU + en GPU anpassad till precis det spel du vill göra. Två komparatorer per hårdkodat objekt jämför koordinaten som ritas ut med koordinaten som ritas ut. Förslag på lämpliga spel: Pong, Spacewar
Bitmap-grafik Värdet för varje pixel sparas individuellt i minnet Enklast: 1 bit i minnet motsvarar om pixeln är svart eller vit. Nexys 3-kortet ni ska använda har 8 utsignaler för färginformation till VGA-skärmen. Dvs, ni kan använda upp till 8 bitar per pixel (Röd: 3 bitar, Grön: 3 bitar, Blå: 2 bitar)
Tips och tricks för bitmap-grafik Tips: Palett: Använd exempelvis 4 bitar per pixel. Låt dessa indexera ett palettminne på 16x8 bitar för att avgöra vilken färg som ska matas ut till skärmen Trick: Genom att ändra på paletten kan du göra vissa typer av animationer
Tips och tricks för bitmap-grafik Tips: Dubbelbuffring Duplicera grafikminnet. Detta gör att ni kan rita i en del av grafikminnet utan att förstöra den del av skärmminnet som skickas till VGA-skärmenför tillfället. Kräver att CPU:n kan få reda på när GPU:n kommit ner till vblank så att den kan ändra vilken del av grafikminnet som ska visas upp. Notering: Vill du göra riktig 3D-grafik (såsom Quake) behöver du bitmap-grafik.
Användning av bitmap-grafik Alla datorer och spelkonsoller använder bitmap-grafik idag. Bitmap-baserade spel kräver: Stort bildminne, snabbt bildminne, snabb uppdatering av bildminnet via antingen specialiserad hårdvara eller en snabb CPU Notera att det dröjde länge innan spelkonsoller och datorer som lämpade sig för mer avancerade spel började använda bitmap-grafik Historisk tillbakablick: Framgångsrik dator med bitmap-grafik: Amiga (den första(?) prisvärda datorn med specialiserad hårdvara för att accelerera bitmap-grafik).
Bitmap-grafik på Nexys-3 Problem 1: FPGA:n på Nexys 3 har för lite minne för vettig bitmap-grafik (FPGA:n har cirka 580 kbit minne, vill du använda 640x480 pixlars upplösning räcker det inte ens till en bit per pixel om du vill använda dubbelbuffring...) Lösningsförslag 1: Använd externt minne för att öka mängden minne (Problem: Externa minnet har dåligt med bandbredd om man inte krånglar till det.)
Bitmap-grafik på Nexys-3 Problem 2: Det är svårt att hinna med att uppdatera grafikminnet ifrån en enkel CPU Lösningsförslag 2: Visa bara upp 320x200 pixlar Lösningsförslag 3: Använd bara bitmap-grafik på några delar av skärmen (förslagsvis de som sällan ändras) (Lösningsförslag 4: Snabba upp hantering av bitmap-grafik genom en speciell hårdvara för att kopiera rektangulära delar av skärmen från en del av grafikminnet till en annan (blitter)) Lösningsförslag 5: Använd inte bitmap-grafik överhuvudtaget
Förslag på bitmap-baserade spel Vill ni använda er av bitmap-baserad grafik? Tips: Välj en typ av spel där ni inte behöver uppdatera hela skärmen hela tiden Exempel: Worms, Qix
Tile/tecken-baserad grafik Skärmen består av (exempelvis) 8x8 eller 16x16 pixlar stora tiles (alternativt tecken) vars utseende bestäms av ett tile-minne (tecken-minne). Ett annat minne bestämmer vilken typ av tile som ska finnas på ett visst ställe på skärmen. Fördel: Mycket mindre minne behövs typiskt för att skapa en spelplan Exempel: Editorn Tiled - https://www.youtube.com/watch?v=cjsyrjvqjv0
Räkneexempel: 8x8 tiles (svartvitt) En tile är 8x8 pixel och vi vill ha 256 olika tiles Med upplösningen 640x480 får vi plats med 80x60 tiles (kräver 4800 bytes lagringsutrymme) Minnesutrymme för tile-utseende: 8x8x256 bitar = 2048 bytes Jämför detta med ett bitmap-baserat minne som kräver 640x480 bitar = 38400 bytes
Exempel: 8x8 tiles (8 bitar per pixel) Spelplan kräver fortfarande bara 4800 bytes Tile-minnet kräver 16384 bytes Jämför med bitmap: 640x480 = 307200 bytes
Spel som lämpar sig för enkel tile-grafik Spel där spelplanen lämpar sig för att delas in i tiles och där vyn ej behöver ändras Förslag på spel: Snake, Tetris, Sokoban, Bejeweled, Roguelikes
Tips och tricks till tile-grafik Många typer av spel kräver en spelplan som du kan scrolla runt på Tips: Bygg din grafikenhet så att den klarar att hantera en spelplan som är större än vad din skärm är. Trick: Se till så att du kan scrolla en sådan spelplan i steg om en pixel Trick: Om du kan skriva i ditt tile-minne så kan du få till en del roliga effekter genom att uppdatera utseendet på en (eller flera tiles) varje gång skärmen ritas upp.
Sprite-baserad grafik Nackdel med tile-baserad grafik: Om du vill ha objekt som rör sig på spelplanen måste dessa röra sig i steg om (exempelvis) 8x8 pixels Lösning: Sprites En sprite är ett objekt som ligger ovanpå spelplanen och kan flyttas i steg om en pixel. (Notering: Muspekaren är en sprite.) Utseendet för en sprites lagras (lämpligtvis) i ett separat minne. Exempel: I ett BlockRAM i Spartan-6 får du plats med en sprite som är 64*32 pixlar stor med 9 bitar per pixel. (Där en bit avgör om pixeln ska synas eller vara genomskinlig.)
Tips och tricks för sprites Tips: Du kan låta ett par konfigurationsbitar användas för att styra om spriten ska roteras 90, 180 eller 270 grader samt låta en annan bit avgöra om den ska speglas i X eller Y-led. (Detta trick kan även användas för tiles för övrigt.) Tips: Glöm inte bort att du kan låta hårdvaran kolla om en sprite har kolliderat med spelplanen eller andra sprites Tips: Om även dina sprites använder en palett av något slag kan du ändra i paletten för att skapa flera olika typer av fiender utan att du behöver använda mer minne. (Exempel: Blå bil: Kör långsamt rakt fram. Röd bil: Kör snabbt och försöker preja spelaren.)
Tips på spel: Tiles + Sprites Typiska spel på exempelvis NES eller C64 passar till denna typ av hårdvara (men många spel kräver för mycket programmeringsarbete) Exempel på spel som är rimliga att skapa i denna kurs: Shoot-em-ups, bilspel (där du ser kartan uppifrån), Breakout, Enkelt tower defense-spel.
Extra-slides Här följer några slides som ej presenterades på föreläsningen men som ändå kan vara av intresse för den som vill göra lite mer avancerad grafik i sina spel
Tips och tricks: Tiles + Sprites Rasterinterrupt: Låt processorn få reda på att vi precis ritat ut en viss rad på VGA-skärmen genom att GPU:n genererar ett interrupt vid lämplig tidpunkt. Varför vill vi veta det? Om du precis visat en sprite, ändra koordinaten för spriten så att den hamnar nedanför aktuell rad den kommer att ritas ut igen! Bra om du behöver fler objekt för än du har stöd för i hårdvaran (typiskt 8) Tips: Återanvänd samma hårdvarusprite till att visa flera skott som flyger uppåt eller nedåt på skärmen i ett typiskt shoot-em-up. NES har visst hårdvarustöd för att göra detta automatiskt. Programmeraren ser 64 sprites men bara 8 kan samtidigt visas på en viss rad. (Om mer än 8 sprites behöver visas på samma rad kommer dessa att flimra frenetiskt.)
Tips och tricks: Tiles + Sprites Ändra i paletten för att ändra färger mitt på skärmen. (Användes ofta för att skapa till exempel en tonad himmelsbakgrund i äldre spel.) Ställ om vilken del av tile-minnet som ska visas upp. Används exempelvis för att skapa split-screen effekter. Exempel: Övre delen av skärmen innehåller statusinformation (poäng, antal liv, hälsa, etc), resten innehåller den vanliga spelplanen. Du kan skapa intressanta effekter genom att scrolla varje rad litegrann i horisontal-led. Vissa plattformar (Exempel: Amiga, Super NES) hade en speciell co-processor som enbart hade till uppgift att uppdatera olika grafikregister för varje rad som visas på skärmen. Exempel 1: Vatteneffekt https://www.youtube.com/watch?v=1_nqd77cdgi Exempel 2: Parallax-scroll https://www.youtube.com/watch?v=4vn9h7n-z_e (notera hur olika delar av bakgrunden scrollar olika fort)
Avancerad tile/sprite-grafik Tile och sprite-baserad grafik användes på klassiska 8-bitars datorer och spelkonsoller Klassiska 16-bitars spelkonsoller (Super NES, Megadrive, etc) var också baserade på tiles och sprites men med fler finesser Framförallt: Flera lager med tile-grafik! (I vissa fall även med effekter såsom halvgenomskinlighet.) Möjliggör parallax-scrollning med överlappande lager. Exempel 1: Sonic till Megadrive https://www.youtube.com/watch?v=evarjhxsfl4 (notera att vissa effekter antagligen skapas genom att animera tiles (vattenfallen)) Exempel 2: Agony till Amiga https://www.youtube.com/watch?v=a839o59bt4s (strikt talat inte tile-baserat)
Pseudo-3d effekter för bilspel Parallax-scroll som nämndes på förra sliden är en typ av pseudo-3d effekt I ett bilspel kan du få fram en viss perspektivkänsla genom att scrolla varje rad på skärmen individuellt i horisontalled. Exempel: Pole Position: https://www.youtube.com/watch?v=_gzwsijqtky Bra länk med mer information: http://www.extentofthejam.com/pseudo/
Pseudo-3d effekter: Mode 7 i Super Nintendo Super NES hade hårdvara som lät en utföra en transformation på skärmens X och Y-koordinater innan grafik från tile-minnet lästes ut. Enligt wikipedia: ( ) ( ) x x a b 0 x0 y = x y y c d y 0 (1) 0 1 (Där x och y är de nya koordinaterna i tilemap och x och y är de ursprungliga skärmkoordinaterna.) Skalning, skjuvning, rotation Exempel: Pilotwings: https://www.youtube.com/watch?v=7yx2b4ux0by
Pseudo-3d effekter: Mode 7 i Super Nintendo Super NES hade en speciell DMA-enhet för att uppdatera transformationsmatrisen för varje rad. Kan användas för att (bland annat) skapa perspektiveffekter Exempel: F-Zero https://www.youtube.com/watch?v=1xltukuczl4 (Notera hur sprites används för att visa objekt som inte tillhör bakgrunden) Tips: Om ni vill göra något i stil med detta: Använd en full 4x4 transformationsmatris istället för att behöva räkna fram en ny transformationsmatrisen för varje rad. Exempel (tunneleffekten i Super Castlevania 4 (3:30)): http://youtu.be/8e3lhy2irmi?t=3m30s
Uppslagstabell för koordinater Skärmkoordinater skickas in i en uppslagstabell och resultatet därifrån används för att hitta rätt tile. Möjliga effekter (Tunnel, wormhole, mode 7-liknande effekter, etc.) Exempel: http://www.youtube.com/watch?v=oea0idazcte
Slutliga tips Tips: Om ni inte känner er överdrivet artistiska men ändå vill ha estetiskt tilltalande grafik: Ladda hem 2D-grafik från opengameart.com Bygg en enkel GPU först och se till att få ert projekt att fungera innan ni börjar lägga till avancerade finesser som egentligen inte behövs för att få godkänt på kursen.