onsdag, oktober 24, 2007

Godkendelse af Projekt!

SMCT
Skeleton Model Creation Toolkit, using python as modeling language

Gruppe 1: http://rolatorrally.blogspot.com/
Medlemmer: Jakob Balle Christensen, Mads Olesen, Kasper Vesth og Anders Bach Nielsen

Allerede i starten af kurset havde vi planer om at arbejde med ragdoll physics. Vi har dog været nødsaget til at tage en lidt anden tilgang til dette, da vi i forbindelse med de obligatoriske opgaver, fik til opgave at implementere et simpelt fysiksystem. Dette fysiksystem havde i bund og grund de egenskaber vi skulle bruge for at lave ragdoll fysik. Gruppens fokus er derfor skiftet fra selve fysikken, til det at oprette modeller, som fysiksystemet kan arbejde på. Vi tager stadig udgangspunkt i Rigid Bodies ĺitteraturen, selvom der er andre muligheder som Inverse Kinematics med flere.

En anden ide, som vi i gruppen har haft oppe nogle gange, var det at integrere et scripting sprog i OpenEngine implementationen. Her kunne vi implementere et domænespecifikt sprog eller bruge et eksisterende scripting sprog som Lua eller Python. Det ville afhænge af hvad vi ønsker at bruge dette scripting sprog til.

Målet med alt dette har stort set fra starten været at lave et sjovt spil, hvor man som en gammel mand eller dame på et plejehjem har fået fingrene i en top tunet rolator og kører ræs på plejehjemmet. Her vil vi bruge en ragdoll til at simulere den gamle person, der hænger efter sådan en rolator. Et andet brugsscenarie er de andre gamle mennesker der er på sådan et plejehjem, de kan jo blive ramt.
Her vil vi have statiske modeller som står rundt omkring på banen, og når de bliver ramt vil fysikken sørge for at de falder på en realistisk måde.

Vores valg er faldet på at kombinere de to ovenstående ideer for at lave vores spil. Vi ønsker at gøre processen med at oprette et skelet af partikler og constraints simpel. Her vil vi bruge scripting sproget Python til at lave en række klasser som kan beskrive forskellige elementer som partikler, constraints, kugleled og hængsler. Disse beskrivelser af fysikskeletter kan så omdannes til partikel- og constraint-information der kan gives til fysiksystemet i vores gameengine. Nedenfor vil vi give en mere specificeret liste over hvordan vi vil løse dette.
Vores projekt kommer derfor til at indeholde følgende dele:

1.Definere en klassemodel der beskriver skeletale modeller med knogler, led og hængsler. Denne klassemodel skal laves i python, hvor eventuelle hjælpefunktioner kan implementeres i C/C++ for at øge hastigheden.
2.Udvide vores model så vi kan gennemløbe den og hente samtlige partikler og constraints ud og give disse til vores fysiksystem. Denne del skal også laves i python. Der skal eventuelt laves callback functioner fra C/C++, så informationen let kan overføres fra python til vores gameengine.
3.Vi skal udvide vores gamefactory så den kan afvikle vores python model scripts og efterfølgende hente de beregnede værdier over i gameengines fysikengine.
4.Det skal være muligt at bygge de rigidbodies vi skal bruge ud fra information hentet fra en python beregnet model. Denne model skal i starten visualiseres som en ”stick man”.
5.Hvis en python model fil opdateres i filsystemet skal den reloades og den eksisterende model skiftes ud med den loadede.

Hvis vi imod alle formodninger bliver færdigr med alt dette, og stadig har tid til mere, er her en lille liste over mulige projekter vi kan arbejde videre med.

1.Mulighed for at finde forskellige dele af vores fysik model til bestemte geometri dele. For at dette skal kunne laves skal vores partikler have navne, så de kan sættes sammen med bestemte geometri dele.
2.Udvide python model script eller have externe config filer med beskrivelse af tilstanden af vores fysik system. Derved lægger vi alle konstanter ud i config filer i stedet for at have dem direkte i vores fysikmotor.
3.Vores GameFactory er som mange andres et stort roderi af foreskellig information og hver gang man ønsker at ændre en lille detalje skal hele projektet recompiles. Her kunne det være rart at lave en ny gamefactory klasse som kan læse et XML dokument der beskriver strukturen af scenegrafen, renderers, kameraer og meget mere. Dette kunne gøres ved at bruge en cross platform XML parser fra http://www.applied-mathematics.net/tools/xmlParser.html.


Referencer:
1.Game Physics Engine Development, Ian Millington, Elsevier, 2007,
ISBN 978-0-12-369471-3
2.Physics for Game Developers, David M. Bourg, O'Reilly Media, 2001,
ISBN 978-0-59-60000-66
3.Python Cookbook 2Ed, A. Martelli et al., O'Reilly Media, 2005,
ISBN: 978-0-59-60079-73
4.Programming Python 3Ed, Mark Lutz, O'Reilly Media, 2006,
ISBN: 978-0-59-60092-50
5.Advanced Character Physics, Thomas Jakobsen, IO Interactive
6.NonConvex Rigid Bodies with Stacking, Eran Guendelman, Robert Bridson, Stanford University.
7.Dynamic Simulation of Articulated Rigid Bodies with Contact and Collision, Rachel Weinstein et al., Stanford University.

Svar for forelæser:

Python ragdolls

Det lyder som et rigtigt spændende projekt, og rimeligt konkret. Dvs. at man kan skrive et Python script til beskrivelse af fysikken i en ragdoll figur. I skal her overveje hvad det er man skal BRUGE Python til (altså hvorfor er det ikke XML man beskriver ragdoll figuren i - jeres punkt 3. ligger lidt op til en statisk forståelse). Jeg ser to brugsscenarier; at man skal bruge noget dynamik til at bygge en figur op med (fx en snor der er en gentagelse af enkelte dele), eller at Python eksekveringen er med til at bestemme den dynamiske opførslen af enkelte dele, hvis en bestemt type af kræfter bliver realiseret i en Python funktion.

Overvej hvordan I laver en pæn udvidelse (extension) af OpenEngine frameworket.

Og sidst men ikke mindst er jeg nødt til at sige, at selvom rolatorrally lyder sjovt, og kan virke som en rigtig god demonstration af de features i laver, så er det ikke gameplay i spillet i skal bruge jeres primære
kræfter på ;)

Jeres plan er godkendt.

torsdag, oktober 18, 2007

AI.. nu faktisk tilstede

Efter at have fået lavet styringen forholdsvis virkelighedstro, og have introduceret drag så man ikke bare bliver ved med at køre lige ud, gik vi igang med at lave vores AI. Allerede fra starten vidste vi at vi ville lave den som en waypointsAI, så vi startede med at finde nogen gode waypoints og gemme dem i et vectorarray. Da det så var gjort skulle vi til at implementere AI'ens opførsel.
Til at starte med forsøgte vi at regne ud hvad vinklen var mellem vores nuværende retning, og den retning vi gerne ville i, altså hen til det næste waypoint. Det vidste sig hurtigt at være utroligt bøvlet, og det endte da også med at vi måtte droppe den funktion. Efter noget tids tænkning og lidt spørgen omkring for inspiration, kom vi til at tænke på at vi jo reelt ikke var interesseret i hvad vinklen var. Vi er jo kun interesseret i et binært valg, nemlig, skal jeg dreje til venstre eller højre for at nå min idealbane. Der kom vi så i tanke om at Face-klassen har en glimrende funktion til det formål, nemlig ComparePointPlane(). Så det vi gjorde var at oprette et face der gik fra centerpunktet i vores rigidbox, til et punkt lige over centeret, og til sidst hen til vores næste waypoint. Så tog vi vores retningsvector, og kaldte face.ComparePointPlane(retning), og fandt ud af hvilken retning vi skulle dreje.
Det var forholdsvis hurtigt at implementere, og virker smukt :)!!

mandag, oktober 15, 2007

Fysik og spilbarhed

Vi er i den uheldige situation at vi forsøger at bygge et spil ovenpå et framework som lige nu ikke er specielt egnet til det; Det er oplagt at man, for at have en fungerende kunstig intelligens, må have en eller anden form for spil.
Vi har imidlertid gjort en række fremskridt. For det første fik vi fikset en seriøst irriterende bug; vores fysikmotor blev ved med at hælde kinetisk energi på vores Rigidbox uden at vi anvendte andet end tyngdekræften på den, og det kunne vi naturligvis ikke forstå. Selv med bouncyness og selvforstærkende fejl-faktorer burde vores fysik sikre et leaky energisystem, altså et system med konsekvent aftagende energi, frem for et tiltagende energisystem (den sidste type har det met at eksplodere). Til sidst fandt vi ud af, at der rigtignok var tale om energitilvækst; af uvisse årsager blev accelerationen på de enkelte partikler, i forbindelse med transformationen i vores fysikmotor, kummuleret i cycle efter cycle. Specielt tyngdekraften har på denne måde nået enorme højder. Da vores relaxation sker i samme rækkefølge i hver cycle forstærker det fejlene stille og roligt, og højner den kinetiske energi i systemet indtil det eksploderer. Med den bug fixet er tyngdekraften mere tilgivende, men ikke meget.

Envidere har vi fundet, at kræfterne vi påviker partiklerne med ikke har udgangspunkt inde fra den transformationsmatrix hvor modellen bliver tegnet; de bliver derimod sat på ude i rummet hvor terænnet bliver tegnet. Vi kunne ikke overskue at modificere motoren så de ville have udgangspunkt i modellens system, men det forklarer hvorfor vi har haft problemer med at anvende partiklerne til at styre med.
Kombineret med at vi translater vores kamera før vi rotterer det (en fejl vi vil rette i morgen) gør at vores spil lige nu er ret uholdbart, men der er håb forude. At kalde rotate på kameraet før vi kalder translate vil være trivielt, og at nu hvor vi ved hvordan vi transformerer partiklerne har vi været i stand til at udvikle nogle metoder til at komme videre.
For det første anvender vi nu accelereret translation til at flyve vores tank rundt. For det andet har vi udviklet en funktion som nustiller tankens retning og kraftpåvirkning, hvilket betyder vi kan genoprette efter et crash. For det tredje kan vi, nu da vi ved hvordan motoren virker, bygge en AI styret tank som kan følge et antal waypoints. Således er løsningen af opgaven inden for rækkevidde, omend styringen bestemt vil være noget for sig.

torsdag, oktober 11, 2007

4 timers fysik mere....

Hvis man skal lære noget af hvad vi har lavet, så er det at man skal stole på og lytte til dem som faktisk har implementeret det som virker! Sorry, jesper ;-) Men det må du da give os ret i.

Nå, for at gøre en lang historie kort, så efter at vi havde fået noget hjælp fra instruktorene på at løse kollisions detection så skulle vi lige bruge et hint mere, men kunne vi ikke finde OE gutterne. Derfor gik vi til Jesper og det var så her.. hehe .. det hele begyndte at blive underligt.

Den model som vi skulle have implementeret var at tjekke hver constraint og finde alle de faces som sådan en constraint den intersecter og så efterfølgende flytte punkterne hvis et af punkterne lå bag efter noget geometry.

Det som vi først fik implementeret efter at have snakket med jesper var at kun kigge på partiklerne og så finde det face som ligger tættest på denne partikel og så se om vi ligger bagved. Dette virkede ikke specielt godt og vi fik brugt det meste af en dag på dette... Men til gengæld fik vi lavet 2 metoder på OE frameworked som var til stor hjælp. Det var IsInsode på en Box og ProjectToPlane og DistanceToPoint på et Face givet et punkt. Man kan håbe af det kommer med i en patch senere :)

Nå, 2 version af vores kollisions test var så at bruge både oldpos og pos af vores partikler til at se om vi var kommet igennem et face. Derved kunne vi jo se om vi var kommet igennem noget siden vores sidste position... Dette skulle jo gerne virke, der er dog det special case når oldpos og pos ligger under geometrien, så vil de bare falde og derved trække resten af modellen med ned.

Denne anden version var så her vi var nået og stadig havde en underlig opførsel. Men fordi vi tjekkede om linien mellem oldpos og pos intersectede med et stykke geometry brugte den allerede lavede metode Intersection på face som ikke kunne give noget svar hvis vi var tættere på end EPSILON... så havde vi ofte ikke nogen intersection selvom vi lå lige på geometrien... Denne fejl tog heller ikke særlig lang tid at finde....

Vi lavede rigtig mange test med om vi kunne constrain os selv på et plan med en normal der pegede lige om og ganske rigtigt så kunne vi sagtens det. Der lå vi rigtig pænt og kunne navigere. Men det kunne vi ikke på geometri faces.... pga ovenstående regnefejl med EPSILON. :-/

Nedenfor ses 2 screenshots af at vores model er constraint af den level nedenunder. Det viser også at vores collision detection virker... men der er huller... det ville kunne ses hvis vi havde en video af det.... det må vi få lavet...



6 timers fysik...

Onsdag efter forelæsningen var det planen lige at lave vores fysik færdig... men det er åbenbart ikke noget man bare lige gør!

Vi fik nogle hints fra instruktorene om at vi skulle se på alle vores constraints og for hver af dem gennemløbe vores QuadBSPtræ for at finde det face som denne linie skærer. Dette fik vi implementeret og vores model var også nogle gange ovenpå banen, men kunne finde på at falde igennem banen!!

Vi snakkede med Jesper og han sagde at vi bare skulle kigge på hver partikel, og hvis partiklen var en en bestemt quad, skulle vi kalde videre til dens børn. Når vi så fandt BSP træet, skulle vi finde det faceset som lå tættest på vores punkt. Derefter skulle vi så projectere vores punkt op på dette plan.

Dertil implementerede vi en extra metode på Box som hedder IsInside(Vector<3, float> p) og på Face som hedder ProjectPointToPlane(Vector<3, float> p).

Problemet er bare nu at når vi rammer noget som vi vil kollidere med så springer vores model i luften.... og vi ved ikke hvorfor...!

onsdag, oktober 10, 2007

Så fik vi flyttet vores followcamera...

På nedenstående billed kan det ses at vi endelig fik flyttet vores followcamera så vi ser bilen bagfra og derved har vi fået korrekt styring på bilen. Vi mangler dog stadig at detectere kollision med banen... men det kommer!



Det at lave position af vores followcamera var ret let og tak til Ian for lidt hints.

cam = new FollowCamera(*frustum);
cam->SetPosition(Vector<3,float>(-100,50,0));
cam->LookAt(0,0,0);

Vores andet problem med at vores geometry ikke lå indenfor vores fysik bounding box. Her skulle vores offset bare være center af bounding boxen og som skal vedligeholdes hele tiden.

tirsdag, oktober 09, 2007

RigidBox noget af vejen...

I denne uge skulle vi implementare fysikken i vores spil, hertil fik vi udleveret en RigidBox klasse som vi skulle implementere. Vi fik hurtigt loaded SmallLevel og lavet en simpel bane så vores hybrid quad og bsp træ ikke tager så lang tid at lave.

Vi fik relativt hurtigt implementeret Verlet ud fra artiklen (med en mindre fejl). I den forbindelse lavede vi en inner class i RigidBox som hedder Constraint som modellerer et constraint mellem 2 partikler. Her i gemmer vi de pointers til de 2 punkter og deres ideal afstand. Derved kan man lave en simpel metode SatisfyMe på hvert enkelt constraint. Koden til det ses nedenfor.


class Constraint {

private:
float length;
Vector<3, float>& p1;
Vector<3, float>& p2;

public:

Constraint(Vector<3, float>& point1, Vector<3, float>& point2) : p1(point1), p2(point2) {
this->length = p1.Distance(p2);
};

float getLength() {
return length;
};

Vector<3, float>& getP1() {
return this->p1;
};

Vector<3, float>& getP2() {
return this->p2;
};

void SatisfyMe() {
Vector<3, float> delta = p1 - p2;
float deltalength = p1.Distance(p2);
float diff = (deltalength - length) / deltalength;
p1 = p1 - delta * 0.5 * diff;
p2 = p2 + delta * 0.5 * diff;

};

};



Vi implementerede også på baggrund af Frustum den måde at tegne vores constraints. Nedenfor ses vores første eksperiment med dette.



Her ses det at vores model ligger ovenpå centrum af vores rigidbox, derfor var vi nød til at indføre et offset så vi kan translatere den ned så modellen ligger korrekt indenfor denne boks. Men desværre er der ikke alle modeller der er ens....



Dette kan vi ikke lige svare på, men har valg en model FutureTank hvor denne relation passer.

Vi er desværre ikke blevet færdig med ugens opgave med at få alle dele af fysikken til at virke. Vi har en gravity som trækker nedaf og dette virker. Vi kan også påvirke de enkelte partikler med en kraft og derved sætte objektet i bevægelse. Vi har ikke nogen form for kollisions detection med banen endnu..

Nedenfor ses et sjov billed af vores bil som roterer frit gennem rummet og er .. tja.. lidt ude af kontrol ;-)

torsdag, oktober 04, 2007

Quad/BSP hybrid

Så har vi implementeret vores Quadtree/BSPtree hybrid. Vi har ikke testet den da vi ikke har noget at bruge den på endnu men den compiler og sprænger ikke i luften nå vi bruger bruger den i vores spil. Hybriden er bruger vores Quadtree og BSPtree builders fra sidste uge og er lavet således:


QuadNode* QuadBSPHybridBuilder::Build(ISceneNode& node) {
QuadNode* qn = qtb.Build(node);
qn->Accept(*this);
return qn;
}

void QuadBSPHybridBuilder::VisitQuadNode(QuadNode* node) {

GeometryNode* gn = node->GetLeafs();
if (gn != NULL) {
BSPNode* bn = btb.Build(*gn);
node->RemoveNode(gn);
node->AddNode(bn);
} else {
node->VisitSubNodes(*this);
}
}


Og hvis der er nogen der skriver af så får I SMÆK! ;-)~~~

Frustum culling in action

Her ses det rigtig tydeligt at vores scene bliver culled ud fra vores quadtree. Det kan så også ses at vores frustum er for lille.... men det er en helt anden historie :)

tirsdag, oktober 02, 2007

Back to front rendering

I stedet for at beholde vores spanning faceset i BSP knuden har vi valgt at udvide knuden med en geometry knude som indeholder dette faceset. Dette er for at kunne udnytte visitorpatterenet til at renderen geometrien.

Vi har også implementeret back-to-front rendering. Dette har vi brugt til at få renderet korekt transparency. Her er koden og et screenshot:


glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_DST_ALPHA);
glDisable(GL_DEPTH_TEST);
int i = node->ComparePoint(viewport.GetViewingVolume()->GetPosition());
if (i > 0) {
if (node->GetBack() != NULL) node->GetBack()->Accept(*this);
node->GetSpanGeo()->Accept(*this);
if (node->GetFront() != NULL) node->GetFront()->Accept(*this);
} else {
if (node->GetFront() != NULL) node->GetFront()->Accept(*this);
node->GetSpanGeo()->Accept(*this);
if (node->GetBack() != NULL) node->GetBack()->Accept(*this);
}
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);




På billedet ovenfor ses effekten af ovenstående kode. Kigges der grundigt efter ses der at nogle flader ikke er transparente??? Dette har vi ikke kunne forklare, men et let fix er at fjerne linien fra koden... eller bare udkommentere den hvis man er sådan en type ;-)


glDisable(GL_BLEND);


Herved opnåes følgende resultat:



Som det så kan ses har vi nu transparency og det hele ser pænt ud. Men hvorfor det er nødvendigt at fjerne den disable linie .. det må guderne vide.

I denne uge at vi arbejdet meget med SceneGrafen og dens struktur og jo mere man arbejder med den jo "pænere" bliver den. Men den lider af at være meget generel og ved at bruge et visitor pattern til gennemløb bliver abstractionen niveuaet endnu højere så derved skabes en stejl indlærings kurve. Men vi mener selv at have mere styr på tingene ud og lært at man ikke må klistre Geometri noder under hinanden og på andre måder gøre ting som OE folkene ikke havde tænkt fra starten ;-)

Vi glæder os til næste uge.....

Frustum Culling...

Så har vi fået implementeret frustum culling og det var jo alt for let. Vi ændrede vores VisitQuadNode til at være:

if (viewport.GetViewingVolume()->IsVisible(node->GetBoundingBox())) {
node->VisitSubNodes(*this);
}




På billedet ses det jo tydeligt at vores frustum indeholder hele den synlige del af vores bane og at der i kanten bliver klippet dele væk. Og pfaff siger .. tak for kaffe...! :O)

Working BSP node and builder....

Så skete det og Haleluja... Vores BSPNode kunne finde de "rigtige" deviders og derved lave en pæn deling. Her på screenshottet ses vores Sahara model i et QuadTræ og vores FutureTank i et BSPTræe renderet i et SplitScreen view.... puh der er mange Buzzzzz words ;-)

Længe leve split screen...

For at teste at vores frustum er korrekt har vi nu lavet split screen... så her er det og længe leve split screen!



Så videre med culling...

mandag, oktober 01, 2007

Lille udvidelse på QuadNode

I vores implementation af QuadNode var der 2 parametre count og hsize. Vi har indført en ny depth som bestemmer hvor dybt recursionen skal gå og derved højden af QuadTræet.



Dette billed er bare et screenshot med en depth på 16 i QuadTræet og samtlige modeller i Sahara001 modellen. Vi ville så bruge DotVisitor til at lave en graf over dette træ, men eftersom at dot filen fyldte 1,2 Mb og SVG filen kom til at fylde 19 Mb satte vi graf højden ned til 8 og fjernede noget af geometrien fra vores scene!

Da dot ikke kan lave billeder som firefox kan vise direkte, ligger der her 2 links til henholds en SVG version og en JPG version.
Så skulle der være en implementation af QuadNode's som kan bruges til noget. Her er et billed af Sahara001 modellen (dele af den) loaded ind i et QuadTree.



Vi har ikke lavet culling endnu og har derfor heller ikke verificeret at de forskellige quads faktisk gør som de skal og ligger i de rigtige hjørner :) Men det skal nok komme..

Som en lille reflektion på OE frameworked så går det meget ud på at få de samme ide'er som OE folkene havde da de lavede dem. Der er nogle ting som virker indlysende men i praksis ikke virker. Som f.eks. at loade facesets i andet end GeometryNodes eller det at have 2 GeometryNodes efter hinanden det gør sjove ting ved shader loaderen!

Men videre med næste opgave....