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)