onsdag den 28. november 2007

Screenshots fra onsdagens fremvisning

Her er lige et par sceenshots fra vores terrain-motor:





torsdag den 8. november 2007

Terrain rendering

Vi har som vores selvvalgte emne valgt at lave en terrain-motor der skal understøtte følgende features:
  • Level Of Detail
  • Streaming a store terrain-heightmaps for nærmest uendelig store terræner.
Vi startede simpelt ved at lave en extension til OpenEngine som loader et heightmap fra en fil givet i constructoren og derved genererer et terrain over det og sender det til grafikkortet til senere rendering.

Den første test tegnede kun prikker for hver pixel i vores heightmap.

Vi har i skrivende stund mulighed for at oprette vilkårligt mange terrain-objekter med hver deres skalering og position:


Når vi loader vores heightmap laver vi en triangle strip som simpelthen kører fra venstre mod højre og tilbage igen ned igennem hele vores heigtmap.
Dette giver et slags zig-zag mønster hvis man ser det i wireframe, men kan ellers ikke ses. Vi synes dette var den simpleste metode for at lave en hurtig rendering af vores terræn. Man kan måske argumentere for og imod metoden, men den tegner ret hurtigt. Vores 2 heightmaps er hver 256x256 store, hvilket giver ialt 4*256² polygoner (262.144 polygoner) som den tegner i realtime på omkring 150 FPS.

Derefter var det relativt simpelt at tilføje en texture til terrainet.





Vi er dog igang med at finde en bedre metode til at udregne normalerne til polygonerne så det bliver mere behageligt at se på.

tirsdag den 9. oktober 2007

Uge 5

Der er ikke så meget at rapportere fra denne uge, vi fik fysikken til at virke
uden alt for store problemer.

Vi stødte dog på en træls ting, vi brugte ikke en boost::shared_ptr ordenligt.
Det var godt nok vores egen skyld at vi ikke læste dokumentationen ordenligt,
men det er også lidt et problem at bruge sådan en halv løsning; rigtig garbage
collection eller en mere eksplicit memory management ville nok være bedre end
en skrøbelig reference counting.

Tror ikke der er meget at sige om vores fysik implementation, tror vi har lavet
det på samme måde som de andre grupper. En kasse med 9 punkter og en masse
distance constraints imellem de punkter. Vi nåede ikke at tweake det helt så
det er stadig ret ustabilt.

tirsdag den 2. oktober 2007

Netværksmodul til OpenEngine

Ud over de opgaver vi skulle lave til denne uge, har vi også lavet et lille netværksmodul. Tanken bag dette er at hvis man skal få følelsen af at det er et spil vi sidder og arbejder på, så skal man også kunne konkurrere løbende, så man kan få en oplevelse af om de enkelte elementer man arbejder på, giver det ønskede resultat - rent spillemessigt. Dertil syntes vi det kunne være sjovt at dyste mod hinanden gruppevis, uafhængig af hvilken modifikationer vi har lavet på OpenEngine. Derfor er udgangspunktet for modulet også at man blot tildeler en Transformation node til modulet. Modulet vil så selv sende ændringer om denne Transformation node videre til serveren og derved alle andre spillere. For at bevare en cross-platform mulighed er SDL_net valgt som netværksbibliotek.

Til alle de andre grupper der ønsker at forsøge sig med vores netværksmodul, så er der en patch her.

BSP træer




Screenshots:
1: Wireframe udgave af den originale FutureTank
2: Wireframe udgave af FutureTank splittet op efter at have genereret BSP træ over den.
3: Gennemsigtig tank tegnet back to front (korrekt rækkefølge for gennemsigtighed)
4: Gennemsigtig tank tegnet front to back (forkert rækkefølge)

Generering af BSP-træet


Vores BSP generering udvælger stadig ikke helt den mest optimale face at splitte med først. Lige nu tager den bare og splitter med den første face i hvert FaceSet den finder. Dette er overhovedet ikke balanceret og genererer en hel del unødige splits, men det er til senere optimering med en langt bedre algoritme.

Rendering af BSP træet


Efter at vi har genereret vores BSP-træ kan vi så rendere modellen ved hjælp af den. Vi traverserer rekursivt ned igennem alle BSP-Nodes fra roden af træet, og besøger altid den BSPNode som er længst væk fra kameraet og derefter den anden rekursivt. Det giver en sortering fra "back to front" (screenshot 3). Hvis man besøger den BSPNode som er tættest på først vil man lave en "front to back" gennemgang og det vil resultere i screenshot 4.

Vi fandt ud af at Resource Manageren var buggy da den ikke kunne finde ud af at hente resourcer fra BSP træer så det resulterede i en helt hvid model (ingen texture). Et fix ville være at tilføje den funktionalitet til Resource Manageren men da den efter sigende skulle være mere buggy end som så, da har vi valgt en midlertidig løsning hvor vi i hvert af bladene på BSP træet har en GeometryNode indeholdende et enkelt Face da Resource Manageren godt kan finde ud af at hente resourcer ud fra GeometryNodes.

Quad Tree

Det lykkeds os at implementere Quad-Træet, men det skete over to omgange. Første omgang kiggede tildelte vi rekursivt hvert face til kun én ny Quad. Selvom dette teoretisk burde give fejl ved manglede faces, oplevede vi et utrolig effektivt og flot resultat. Der var ingen fejl og spotte og frustrummet skar rigtig pænt på afstanden. Den anden løsning blev dog senere implementeret, da der som sagt teoretisk vil være fejl samt vi fik oplyst fysikken senere skal benytte Quad-Træet til mere effektiv kollektion. Her blev hver face der var på grænsen imellem to eller flere Quads splittet op og fordelt ud imellem de forskellige Quads. I starten gav dette et voldsomt problem ved bygningen af træet, da vores count i QuadNode var sat til 100. Dette var simpelthen for dybt at gå ned i træet og antallet af faces steg eksplosivt. Vi erfarede en stigning i ram forbruget på op til 1 GB før end vi manuelt lukkede programmet igen. Ved at efterfølgende ændre denne værdi til 200 blev resultatet fint igen. Dog er effektiviteten ikke så god som før og beskæringen i distancen er ikke helt så pæn.

Den efterfølgende performance af brugen af et Quad-Træ var overvejden. Antallet af faces der blev tilføjet til systemet dræbte den effekt man fik ud af det før og hvis man står et sted i banen hvor at man kan se ca. det hele(altså med en høj distance), så er performance lavere end før.

tirsdag den 25. september 2007

Uge 3: Shaders og Transformation nodes

Parallax shaderen




Parallax-shaderen faktisk den shader der tog kortest tid at skrive.
Vi har ikke så mange kommentarer til den, vi brugte bare approksimations-metoden.

Oily shaderen




Denne shader gav os store hovedpiner da vi ikke kunne få det til at se rigtigt ud.
Først og fremmest fandt vi ud af at man ikke kunne loade en 1D texture så vi måtte loade ColorRamp.tga som en 2D texture og så læse fra den via 2D koordinater.

Derefter kunne vi ikke få oliefarverne til at få den "thin-film" effekt som vi ønskede: farverne gentog sig mange gange og så ikke realistisk ud. Vi fandt fejlen (forkert udregning).

Den sidste men sværeste fejl var da vi ville have Cetatta'ens egen texture neden under Oily-effekten. Ingen metoder så ud til at virke ordentligt (evigt roterende textures eller textures der sad statisk fast uanset hvor kameraet pegede hen).
Fejlen lå dog ikke i pixel shaderen, men i vertex shareden.

I pixel shaderen indlæser vi texture farver med koden:

color = texture2D(diffuseTex, gl_TexCoord[0].xy);

Grunden til at det ikke virkede helt var at vi manglede at definere gl_TexCoord[0].
Det rettede vi ved at tilføje linien:

gl_TexCoord[0] = gl_MultiTexCoord0;

i vores vertex shader.


Spørgsmål 3


Hvis man ville udvide med support for DirectX skal man udvide Renderer
interfacet kraftigt eller man skal lave to af alt ting. Fra dennes uges
opgaver
ville man skulle have to visitTransformationNode en som bruger
glPush/PopMatrix
og en der gør tilsvarende med DirectX API'en. visitGeometryNode bruger også
nogle kald direkte til OpenGL(glVertex3f, glTexCoord2f osv).

Det ville nok ikke være en lille opdatering at udvide med DirectX, men heller
ikke umuligt. Det hele er dog nemmere hvis man antager det altid er OpenGL, så
slipper man også for at have HLSL udgaver af sine shaders f.eks.

Desuden kører OpenGL fint på alle platforme, DirectX kører kun på Windows.

tirsdag den 18. september 2007

Uge 2: Fremskridt

Object (.OBJ) loading


Vores tank på et procedurally generated skatbræk ;-)

Koden var ret lige til, vi brugte sscanf lige som i OBJResource::LoadMaterialFile med en masse if, else if.
Vi valgte at ignorere alle linjer uden {v, vt, vn, f, mtllib, usemtl} i starten, i
stedet for at smide exceptions. Der var ikke rigtig nogen grund til ikke at prøve at
loade selv om man støder på noget ukendt.

Det eneste problem vi stødte på er at de index man læser efter et f ikke starter
fra 0, men fra 1.

Vi fandt én reference som vi synets var god nok. I hvert fald den vi lavede det ud fra.

Kritik


Man kan ikke bruge Vertex Arrays eller Vertex Buffer Objects da de kræver
at man har sine værdier liggende med fast mellemrum(man kan kun angive en start og en
stride der siger hvor langt der er til starten af næste).
Det krav duer ikke sammen med at en Face da:

  1. Face er for det første heap allokeret, så et FaceSet har dem ikke liggende i et
    sammenhængende stykke.

  2. Hvis man gik i gennem det ekstra besvær med at få allokeret en bunke Faces efter
    hinanden, ville man stadig have et problem da de er lavet som 3 punkter, 3 normaler,
    3 texture coordinater osv.
    De ville være nødt til at være 1 punkt, 1 normal, ..., 1 punkt, 1 normal, ...



Man kunne ændre Face og FaceSet, eller tilføje en OptimizedGeoNode der ikke bruger
dem, hvis man virkelig gerne vil bruge en mere optimal måde, men vi rodede os ikke ud i
det. En anden måde at optimere det på er med Display Lists. Det skulle være
muligt, men dog ikke uden at enten ændre GeometryNode til at vide hvilken list der
passer til dens FaceSet, eller ved at cache i RenderingView.cpp på pointeren til
FaceSet. Så må man bare håbe de ikke bliver opdateret in-place

Joystick support


Da i vores gruppe har adgang til et joystick (det er nu nærmere en gamepad i playstation stil der har fået transplanteret halen...), så er det jo lidt en must have at kunne køre bilen med dette. Vi har derfor implementeret joystick understøttelse i Enginen.

Implementation er i samme stil som både keyboard og mouse, vi har defineret et interface (IJoystick) til enginens devices afdeling, samt et par nyttige structs.
Af structs har vi defineret:

JoystickState som indeholder joysticket tilstand, dvs. hvilke knapper der er trykket ned, og hvor på akserne de forskellige styrepinde står.

JoystickAxisEventArg der som navnet antyder indeholder data der benyttes i akse, dvs. id'et på aksen der har udløst begivenheden, samt tilstanden af alle andre akser.

JoystickButtonEventArg der ganske ligesom den foregående er til en begivenhed, indeholder id'et på knappen der udløste begivenheden, samt alle knap tilstande.

Da det må forventes at der kan sættes flere joysticks til, så skal disse også kunne håndteres, alle strukturerer indeholder derfor et id på joystick som strukturen tilhører. Joystick id starter fra og med 0 for første enhed, og til og med n-1 for n'te tilkoblede enhed.

Struct'sne er som følger:

struct JoystickState {
int JoystickID;
int NumberOfButtons;
int ButtonState;
int NumberOfAxis;
std::vector AxisStates;
};


struct JoystickButtonEventArg {
int JoystickID;
int NumberOfButtons;
int ButtonState;
int button; //button that triggered the event;
};


struct JoystickAxisEventArg {
int JoystickID;
int Axis;
std::vector AxisStates;
};


selve interfacet specificerer 3 metoder, en til at hente hele tilstanden på et givent joystick, en til undersøge om en knap er trykket ned (Vi overvejer at markere den som deprecated), og tilsidst en til at finde ud af hvor mange joysticks computeren besidder.

Metoderne er deklareret som følgende:
JoystickState GetJoystickState(int id);
bool IsPressed(JoystickButton b, int id);
int GetNumberOfJoysticks();


Slutteligt specificerer interfacet 3 event, Knap op, knap ned, og sidst men absolut ikke mindst, en til når en styrekæp flyttes. Alle events er statiske ligesom i IMouse og IKeyboard for en mere konsekvent stil.

Event'sne er som følger:
static Event joystickButtonDownEvent;
static Event joystickButtonUpEvent;
static Event joystickAxisMovementEvent;


Interfacet er ikke komplet, i kampens hede har vi opdaget at der også er noget der hedder hats og balls i en joystick sammenhæng, og vi ved virkelig hvad det er :) Derudover kunne det så også have über nice med Force Feedback understøttelse.

Selve implementationen er sket modulet SDLInput, som der så ellers ikke er så synderligt meget ophidsende omkring.

Når modulet initialiseres åbnes alle joysticks, deres tilstand aflæses, og gemmes.
Deres tilstand opdateres så vha. af de events vi får fra SDL.

Specielt er akserne, hvor der er sat en grænse på ca. 10% fra 0 (akse centrum) før en begivenhed udløses, +- 10% er derfor et dødt område. Dette er indført da flue ellers ville kunne køre bilen i grøften :)

Joysticks kan benyttes på ca. samme måde som keyboard og mouse vha. events.




Race car movement


For at teste en lidt mere avanceret kamera-kontrol ville vi lave en forløber til det vi kommer til at bruge senere hen, nemlig et modul der kan simulere det at køre i en bil.

Vi simulerer en racerbils bevægelser ved at have en "Velocity", "Direction" og "Position" vector.
En racerbil behøver ikke nødvendigvis bevæge i den retning den peger da den kan skride ud i sving m.m. derfor holder vi Velocity og Direction adskildte variabler.

Vi arbejder løbende på at gøre bevægelsen mere realistisk og efterligne en rigtig bil mere og mere.

Vi er klar over at der kommer konkret teori om dette senere, men vi bruger dette til at teste forskellige ting.

Målet med vores RaceCar modul er senere at koble det på FutureTank modellen så man kan styre den rundt på banen.

Vi kan både styre bilen med tastaturet og med joystick.
Tastaturet begrænser input til at være "konstant" som f.eks. at trykke "pil op" vil resultere i at give fuld gas, mens det er muligt at kun gasse lidt op når man bruger joysticket.

I vores implementation har vi gjort plads til det ved at gøre alle input variable til floats der går fra -1 til 1.

Ved brug af tastatur vil en variabel som f.eks. accelerationFactor blive sat til 1 (fuld acceleration) hvor joysticket kan have en hvilken som helst acceleration efter ønske.

tirsdag den 11. september 2007

Uge 1: starten

Overordnet


Vi fik løst opgaven og implementeret IKeyboard og IMouse, selvom
de ikke er helt færdige. Man kan ikke holde en knap nede og få flere
events(Som hvis man holder w nede for at gå frem i et skydespil)

Vi implementede kamera kontrol som et seperat modul, der lytter på
IKeyboard::onKeyUp/Down og IMouse::mouse*Event. En ting vi gjorde
anderledes i forhold til eksemplerne er at vi droppede Handler delen
af event systemet.

class QuitEventHandler {
public:
void HandleQuit(KeyboardEventArg arg) {
if (arg.sym == KEY_ESCAPE)
IGameEngine::Instance().Stop();
}
};

bool GameFactory::SetupEngine(IGameEngine& engine) {
QuitEventHandler* quit_h = new QuitEventHandler();
Listener<QuitEventHandler, KeyboardEventArg>* quit_l
= new Listener<QuitEventHandler, KeyboardEventArg> (*quit_h, &QuitEventHandler::HandleQuit);
IKeyboard::keyUpEvent.Add(quit_l);
return true;
}


Kan håndteres lige så nemt med en HandleQuit metode direkte i GameFactory
og så new Listener<GameFactory, KeyboardEventArg> (*this, &GameFactory::HandleQuit)

Den teknik giver mening når man laver engangs-ting, men det er ikke reusable.

Tools


Vi bruger allesammen Linux, men vores valg af editor er mindre ensformigt.
Kate, KWrite, gedit og vim bliver alle brugt.

De værktøjer der er blevet valgt for os, synets vi godt om.


  • Darcs er et godt system og vi har også sat det op til at dele kode i gruppen

  • CMake er uendeligt meget bedre end selv at rode med Makefiles i Linux
    og projekt-filer på windows

  • SDL er ret lige til og helt klart et godt valg til crossplatform ting



Det er selvfølgeligt også rart at alle værktøjerne er open source.
Vi ville nok selv have valgt de samme ting.

OpenEngine



Frameworket virker fornuftigt, vi skulle dog lige bruge et kort stykke tid til
at sætte os ind i koden men nu ser den ud til at være fleksibel.

Dokumentationen på openengine.dk var også til hjælp. Godt organiseret og
detaljeret nok.

Boost bliver allerede brugt i frameworket, så hvorfor ikke udvide det til
event systemet.
Med Boost::Signals og Boost::Bind får man samme system gratis.

Koden til IKeyboard::keyUpEvent kunne simplificeres til det følgende
hvis HandleQuit metoden flyttes ind i GameFactory:

boost::signal<void (KeyboardEventArg)> keyUpEvent;
keyUpEvent.connect(boost::bind(&GameFactory::HandleQuit, *this, _1));

søndag den 9. september 2007

Første indlæg i vores GameDev "Blag"

Vores gruppe består af:
  • Anders Riggelsen (20063138)
  • Anders Halager (20063252)
  • Anders Johnsen (20063634)
  • Troels Hansen (20062372)