tirsdag, december 18, 2007

Extension: SimplePhysicsSystem

Extension name:

SimplePhysicsSystem

Location:

~abachn/oe/extensions/SimplePhysicsSystem/

Purpose:

This is a simple physics engine written in C++. It contains a number of PhysicsSystems that again contains particles and constrains. The PhysicsEngine uses Verlet integration to calculate the particle positions over time. This is taken from the FixedTimeStepPhysics extension.
Each PhysicsSystem can have a range of modifiers like gravity and can collide with surfaces that in not part of the world graphics.

Dependencies:


Implementation details:

fredag, december 14, 2007

Nu også figurer med placering :-O

Vi har nu gjort det muligt at placere vores ting andre steder end i 0.0. Man kan nu placere dem hvor man har lyst i rummet, og samtidig kan man også dreje dem som man har lyst til. I sig selv en meget god lille opdatering, men for at det ikke skal være løgn er det nu også muligt at vælge en hvilken som helst port, i en hvilken som helst figur, og så fastsætte et sted og en vinkel som den skal tegnes i. Det vil gøre det muligt for os at sige at et hoved skal være i positionen (0, 30, 0) så den altså bliver sat et godt stykke over jorden, og det gør os faktisk også indirekte i stand til at bestemme hvilken del af kroppen vores figur skal tegnes ud fra.
Umiddelbart en lille opdatering, men faktisk en ret væsentlig del af projektet :)

tirsdag, december 11, 2007

Visualizer, nu også med mulighed for placering

Ja, som der så smukt står i overskriften, har vi nu gjort det muligt at bestemme hvor i visualiseringen, det man tegner skal tegnes. Dette blev opnået ved at lave et nyt objekt, der i modsætning til vores andre objekter, havde partikler med placeringer. Inde i vores distributor, sørger vi så for at gemme disse partikler i deres egen liste, så de ikke bliver berørt af eksplosionen, men stadig bliver brugt til at udregne constraints med. Og efter hvert gennemløb af distribute-algoritmen bliver deres position så sat til det de oprindeligt var igen. dette sikrer os at figuren altid vender som vi gerne vil have det, og gør det lettere at visualizere store figurer. Man sørger bare for at attache vores nye object der hedder Placer, meget passende, til det objekt man nu engang vil have til at være på et særligt sted, og placeren sætter sig så med centrum i 0.0 og resten af figuren bliver tegnet ovenpå det :)

mandag, december 10, 2007

randomniseret distributor

nu er vores distributor-algoritme blevet randomniseret ved hjælp af en modulus-funktion.. sørger for at vi ikke kommer ud for nogen problemer, med nogen constraints der ikke virker efter nogen af de tidligere er blevet kørt, og derved bliver det meget mere stabilt og sikkert :)

søndag, december 09, 2007

Præcision af et afstandsbaseret system

Som mange gange nævnt er vores led konstrueret alene ved hælp af partikler og afstande.
Det har før givet anledning til megen dokumentation af effektivisering, men nu er vi nået til et punkt, hvor vi bliver nødt til at overveje præcision, når verlet-integration anvendes.

Lad os tage et konkret eksempel:


To partikler (de blå) har en constraint imellem sig (den grønne linje), som er 2x lang. Vi ønsker nu at placere en partikel midt imellem dem (den gules placering), og det virker oplagt, at så skal den røde bare have afstanden x til hver af de to partikler, og så er den i vinkel.
Sådan er det imidlertid ikke når man arbejder med verlet integration. Man kan ikke være sikker på at partiklernes placering hele tiden er korrekt, blot, at de vil forsøge at placere sig korrekt. Jo flere integration steps man tager i sekundet, desto mere præcis er vil partiklernes placering være, men den vil i reglen aldrig være perfekt.
Når en konstruktion som den ovenstående indgår i en struktur kommer denne præcision til at spille ind.
Der sker nemlig det, at de blå partikler vil søge at placere sig korrekt, og derfor vil stå og slå lidt.
Det gør ikke noget for dem - de har mange andre partikler at støtte sig til, så deres placering opnår ved relativt få iterationer af verlet integration en god ca. placering.
Den røde partikel, derimod, har kun 2 partikler at læne sig op ad. Og hvad værre er, en relativt lille procentvis afvigelse i x giver en stor procentvis afvigelse i forhold til hvor tæt den er på idealplaceringen. Lad os kigge på nogen kommatal:
Hvis x er 1.0 lang, så kunne den for eksempel få værdien 1.001. så er den grønne afstand 2.002. Hvis de blå partikler så ryster lidt, så afstanden ændrer sig til 2.004, og x derfor ændrer værdi til 1.002, så er det ok - for de blå partikler er der tale om 0.002/2 = 0,1% forskel, og det er ikke til at se. Men får den røde partikel, som før var i afstanden (1.001^2 - 1.000^2) = 0.002 fra sin idealplacering, så er den nu (1.002^2 - 1.000^2) = 0.004 - altså en 100% større fejlmargin.
Men betyder det virkelig noget? når tallene er så små?
Ja, det gør det, og det har vi nogle screenshots af allerede. Det betyder faktisk så meget, at der pludselig opstår tydelige afstande, hvor der ikke burde være nogen. Efter mange tests viser det sig, at hvis længderne er præcise med blot 4-5 decimaler i forhold til idealet, så er der ikke noget problem, selv med en følsom midterpartikel - men det krævede så,
med en stor, verbos algoritme, mere end 1000 verlet integrations før denne præcision var opnået.

Da der er påvirkninger i forbindelse med hver eneste integration, kan vi ikke umiddelbart arbejde ud fra at denne form for ro nogensinde vil opstå i openengine.
Det er et problem, for det tvinger os til at overveje konstruktioner som undgår bestemte teknikker til partikelplacering, og generelt kan vi ikke længere bruge, at et lavt antal constraints giver et sundt resultat hvis bare man sætter antallet af integrationer i vejret. Vi bliver nu, simpelthen, nødt til at forholde os til konstruktionstypem, og dennes stabilitet. Noget kan eksempelvis løses ved hjælp at lidt løsere constraints, andet ved hjælp af en mere doven integration, og noget tredje kan være aktivt at udsulte systemet for energi så det falder til ro lettere.

Da tidspresset så småt begynder at kunne mærkes, og vi ikke har et miljø oppe og køre hvor vi kan teste os til _et_ resultat som passer med openengine, kan vi gøre det at vi programmerer både ideale optimerede konstruktioner med den ene hånd, og samtidig programmere robuste konstruktioner, som så er tungere men mere pålidelige med den anden.
Såfremt vi sikrer at ledene anvender løse koblinger kan vi anvende fleksibiliteten i vores system til at lave både livrem og seler, og så senere skifte efter forgodtbefindende =]
(præcis ligesom vi, i parantes bemærket, kan lave fuldt kompatible skeletter med ens opførsel, der kan anvende constraints til forward kinematics hvis vi skulle have lyst til det)

lørdag, december 08, 2007

Visualisering

Når man skal opbygge led som dem vi vil lave, er det utroligt praktisk at have en visuel repræsentering af dem. Og til det formål har vi været så heldige at der findes et tool til at visualisere python, nemlig vpython. I sig selv er det ikke voldsomt svært at vise sin kode ved hjælp af vpython, men vi løber dog hurtigt ind i et problem, da det eneste vi har at tegne vores figurer efter, er partikler uden nogen position i rummet og så nogen constraints der binder disse partikler sammen. Dette gør at vi er nødt til at skrive en algoritme der tildeler partiklerne positioner.

Vores algoritme, ellers vores distributor, får givet en liste af partikler, og en liste af constraints.
Det første vi gør er at tildele alle partiklerne nogen tilfældige positioner i rummet, og herefter sætter vi antallet af gange vi vil køre vores eksplosionsalgoritme. Vi laver så en while-løkke, hvor vi i hvert skridt først regner gennemsnitspositionen ud. Herefter exploderer vi vores partikler væk fra det punkt. Med andre ord kan partiklerne ikke lide hinanden. Nu har vi fået partiklerne til ikke bare at ligge i en tilfældig klump omkring (0,0,0), men det er stadig ikke godt nok. Derfor er vi nødt til også at have fat i vores constraintlist. Alle vores constraints har attributer der gemmer på de to partikler de er forbundet til, og vi regner nu vectoren mellem de to partikler ud. Vi regner så længden på alle constraintvectorerne ud, og gemmer dem i en liste. Denne længde bruger vi så til at regne ud om de to partikler constrainten binder sammen er for tæt på hinanden eller for langt væk, ved hjælp af constraintens minimum- og maximum-længde. Er partiklerne for tæt på hinanden, bliver de skubbet lidt væk fra hinanden, og omvendt hvis de er for langt væk fra hinanden.
De sidste skridt hvor vi tilpasser constraintsne bliver kørt en del flere gange end selve eksplosionen, og det er fordi det er her vi tilpasser figuren.
Nu har partiklerne så fået tildelt deres positioner, og det er tid til at tegne dem. I vpython foregår det så smart som at man, i en helt almindelig pythonfil, skriver ”from visual import *”. Når det er gjort har vi tilgang til alle de funktioner vi skal bruge. Vi laver så en funktion der hedder draw, der først kører vores distributionsalgoritme, og herefter tegner partiklerne og constraintsne. Partiklerne bliver tegner som bolde, eller spheres for at blive i fagsproget, og constraints som rods, eller rør.
En af de smarte ting ved den her visualiseringsmetode, er at det også er den vi gør brug af når vi importerer vores python i c++, og derved i openengine, så ikke nok med at den gør vores designarbejde utroligt meget nemmere, så er den også med til at sikre os, at vi kan repræsentere det vi har lavet, og det er alt andet lige en hel del sjovere at se på en visualisering af vores skelet, end bare på nogen stumper kode. Til at starte med giver den os dog ikke det helt ønskede resultat, så vi er nødt til at kunne fortælle den hvilken orientering et givent led skal have, men vi får det tegnet og det ser smukt ud selvom retningen ikke altid er den ønskede. Nedenfor ses vores hængselsled tegnet ved hjælp af vpython.



onsdag, december 05, 2007

Project: CreatePythonModels

Project name:

CreatePythonModels

Location:

http://www.daimi.au.dk/~abachn/oe/projects/CreatePythonModels/

Purpose:

A project that uses the python bindings via PythonModels to create and display models scripted in python. The models are via !PythonModels loaded into a physics system.

Dependencies:


Implementation details:

In the GameFactory of this project we have create one instance of the PythonModels class. This exports the nessesary classes and functions to python and we can run scripts from this project that expect to find the classes defined by the extension.
We have created a Module that in added to the engine that monitors a list of files. It one of these files are updated, the entire model is recalculated.

Extension: PythonModels

Extension name:

PythonModels

Location:

http://www.daimi.au.dk/~abachn/oe/extensions/PythonModels/

Purpose:

Creating an extension based on the PythonBindings extension that loads some real python files into the interpreter and exports some C++ functions and classes to python. This extensions makes it possible to use the exported python model to create models written in python scripts and have them exported to a physics system. To visualize the model its possible to get a RenderNode form the !SimplePhysicsSystem.

Dependencies:


Implementation details:

onsdag, november 28, 2007

Præsentation

Det var så vores "8 minuts of fame"... og det gik da også nogenlunde!

Vores slides kan findes på http://www.daimi.au.dk/~abachn/oe/gamedev-uge48.pdf.

Vores extension hvor vores tidlige python model ligger, samt embedding af python ind i OE frameworked kan findes på http://www.daimi.au.dk/~abachn/oe/extensions/PythonModels/. Vores projekt der bruger denne extension kan findes på http://www.daimi.au.dk/~abachn/oe/projects/CreatePythonModels/.

onsdag, november 21, 2007

Udvidelser af Core OE: Resource Manager

Efter en snak med Ian og de andre OE gutterer vi begyndt at lave lidt om på ResourceManageren i selve OpenEngine, da den har nogle uhensigtmessige design valg.

Kort nævnt er det:

Der er kun et plugin pr file extension. Der er desværre ikke muligt at bruge et plugin på flere forskellige file extensions.

Pt har ResourceManageren kun en data path. Her kunne det være rart at have en form for PATH variabel som bestod af flere muligheder for søge stier.

[UPDATE] 28.11.07

We have updated both the IResourcePlugin class and the ResourceManager class to get the above results right.

The IResourcePlugin class/interface was extended with a list of the extensions this plugin knows how to handle. The idea is that when creating a new plugin you add the extensions that this plugin should handle. A plugin can be asked if it AcceptsExtension.

This is used in the ResourceManager to replace the map to just list. Given a file we just look through all plugins and ask if this plugin AcceptsExtension of the given file. So first task completed.

Next we needed to have a path system. We can AppendPath and PrependPath. The ResouceManager just keeps a list of these path elements. The important part is the function FindFileInPath that given a filename looks in the paths list and uses boost::filesystem::exists to determine if that filename exists somewhere. It returns the empty string if not found and the absolute/relative fullpath of the file.

tirsdag, november 20, 2007

Entydigt system bestående af punkter og afstande

Vi foretager mange designvalg, hele tiden, for at få et gennemskueligt og velfungerende system stablet på benene.

I den forbindelse er vi stødt på et problem med vores porte, som kræver at vi foretager et umiddelbart valg. Lad os først dokumentere problemet:

Et væsentligt langsigtet mål med vores system er at vores knogler/led/skeletobjekter er entydigt bestemt internt - Det på trods af at de kun består af afstande og punkter. Men, hele skelettet skulle også gerne være entydigt bestemt. Det skulle vores porte, i reglen, sørge for. Det har de også gjort hidtil, men det er nu gået op for os, at det ikke altid er tilfældet.

Sådan er det imidlertid ikke på nuværende tidspunkt. Helt basalt set er vores porte ikke orienteret korrekt. Vi låser, som det er nu, to objekter sammen ved at svejse deres porte sammen – det har den heldige effekt, at man kan orientere objektet man sætter på i 4 retninger, så man kan foretage en tilnærmelsesvis drejning i et led og ikke behøver skrue på de omkringliggende knogle-objekter meget.
Samtidig, og vigtigst, sikrer vi rigtig 3-dimensional placerings-afhængighed, idet portene nu er 1 og samme, og dermed har dens position indflydelse på partiklerne i begge objekter.

Problemet er, at objekterne ikke kan finde ud af hvilken side af den nye port netop deres partikler skal være på:



Det ene objekt, skoen, er opbygget af indbyrdes afstand, og er entydigt. Det andet objekt, læggen, er også opbygget af inbyrdes afstande og er entydigt.
Det at svejse portene sammen er ikke nok – der skal på én eller anden måde tilføjes endnu en constraint for at det holder. Vores opgave, rent programmeringsmæssigt, er at automatisere samlingen bedst muligt. Ideelt set skal brugeren af objekterne ikke kende til hverken skoens eller læggens opbygning; og han skal absolut ikke ind og beregne afstanden mellem to punkter i det nye objekt for selv manuelt at tilføje en constraint, det ville være ødelæggende for vores mix-and-match mål med bibliotektet.

Desværre betyder det her en generel udvidelse af vores arbejde:

1.
Vores porte ændres så de er 3dimentionale ved at tilføre én ny partikel, og kun en del af portene svejses, hvilket vil indbygge orientering i portene. Det betyder imidlertid at man, i designet af objekter, skal forbinde sig stramt til en væsentligt mere kompleks port: Hvis hele objektet er hæftet ved en 3dimensional port, kan man, i svejsningen, automatisk sætte en constraint på mellem de 2 partikler i portene som ikke er i plan sammen. De er nødt til, for at sikre at man kan rottere et led som nu, at være en slags små pyramidetoppe.

- Det er en puritansk løsning, som desværre gør hvert eneste led mere komplekst, og som gør at skrivningen af nye basisled, knogler, og større strukturer bliver mere kompleks. På plus-siden er den overkommelig: Der skal kun én ny fast constraint imellem den nye partikel i den ny porttype og vores hidtige knogler og led. Resten af konstruktionen ligger i den ny porttype. Det er smatidig heller ikke en uoverkommelig opgave at splejse de ny porttyper sammen, og vi kan, efter splejsnigen, glemme alt om porte og objekter og derfra kun arbejde med en liste af partikler og en liste af constraints.

2.
Vi løser problemet når vi sætter koordinater på: gennemsnittet af koodinaterne i det ene objekt skal ligge på den ene side af det plan porten udgør, gennemsnittet af koordinaterne for det andet objekt skal ligge på den anden side.

- Det er en rigtig snusket løsning som fritager os for ansvaret her ved at skubbe det fremad til instancieringen af koordinater. Vi skal bare sikre, som invariant, at vores objekter altid, i gennemsnitskoordinater, befinder sig på den ”rigtige” side af porten, og det gør ikke noget at nogen af partiklerne raver forkert. Det er lunkent, for hvis foden, i den tegnede analogi, bliver slået hårdt på runtime kommer den pludselig til at krænge op i læggen, og det er vi helt sikkert ikke interesserede i. Endelig kræver det, at vi, når vi producerer koordinater stadig bibevarer mulighed for at traversere legemet som objekter med porte.

3.
Vi gør det samme som ovenover, min vi udvidder openengine til også at forstå konceptet porte og skeletobjekter, og vi foretager hele beregningen på runtime. Så har vi oversat hele modellen til c++ og vi bruger kun python fordi det er ”et rart sprog”. Vi smadrer i øvrigt alt hvad der har med performance og gøre.

- kritiske kommentarer og grimme ord overlades til læserens fantasi.

4.
Vi udpeger en føle-partikel som har riggid-forbindelse til hver port i hvert objekt, og giver variabler med for porten og føle-partiklen frem til koordinatisering/runtime. Når porte svejses arves følepartikler fra de to forældre-porte. Vi foretager lejlighedsvis, men først i forbindelse med koordinatisering/runtime, en point-plane-comparison til begge følepunkter tilkoblet en svejset port. Er de på samme side smides det ene følepunkt over på den anden side.

- Hvis ikke denne løsning fremføres helt op til runtime har den samme svaghed med inadkrængende objekter som løsningen ovenover, men den vil være relativt billig at checke på runtime i forhold til.

5. Alle punkter i alle objekter holder sig på deres side af portene. Det giver problemer i forhold til punkt 4, se illustrationen nedenunder, hvor en stor rigidbody har en port med partikler på begge sider. Her skal objekterne bibevares helt frem til det tidspunkt hvor checket køres.


Som det kan ses accepteres en del af partikler ikke (de gule).


- Ærgelig løsning, som kræver bibevarelse af mange variable for at adressere objekterne individuelt langt hen i processen.

6. Ligesom i punkt 4 anvendes følepartikler, men denne gang defineres på slum for hver følepartikel en constraint, hvori portstørrelsen indgår som faktor. Det gælder så generelt, at partiklen som minimum er ½ portstørrelse væk fra porten, og at dens constraint til enhver anden følepartikel maximum rager ½ portstørrelse ind over dennes. Afstandene er angivet i afstande vinkelret på planet porten udgør. Derudover må det gælde, at alle portens 4 partikler have kortere afstand til følepartiklen, end dens minimumsafstand til den anden følepartikel. Når portene splejses sørger partiklerne for automatisk at oprette disse minimums-constraints.

- Svær at dokumentere forståeligt, og designet af basisled problematiseres noget. Følepartiklen skal vælges til at være centralt placeret i forhold til sin tilhørende port, men så længe den befinder sig ”oven over” porten så går det. Hvis ikke constraintsne overholdes nøje risikerer man inkompatible led/knogler.

_______________

Gruppen hælder for øjeblikket mod model 1, og vi ønsker at beslutte os for en løsning inden fredag, men det er forhåbentligt den sidste større problemstilling i vores modelleringsarbejde =]

Skelletbibliotek og krav til led, knogler med videre

En af de problemstillinger vi løbende har forhold os til er at objekter som består af afstande og punkter kan opfylde afstandskravet i en række forskellige orienteringer. Det indgår i designet af hvert eneste af vores led og hver eneste af vores knogler, som endeligt successkriterium, at afstandskravene opfyldes hvis og kun hvis ledene har præcist den form vi ønsker.

Der kan opstå problemer med tvetydigheder i forhold til dette mål - lad os forholde os til vores generelle drejeled som eksempel.
Hvis vores generelle drejeled een gang har taget en omgang for meget forbliver det i den drejede tilstand og er stadig funktionsdygtigt - på samme måde som metallåget på mange flasker kan drejes for tæt til og så "hopper" gevindet en omgang op og bliver løsere igen. 

Men vores led kan i nogen situationer, i modsætning til metallåget, være i stykker: hvis en 3d model af en underarm er bundet fast til partiklernes koordinater, er modellen nu blevet snoet en gang, og fysikmodellen siger stadig, at armen er lige så funktionsdygtig som før.

Det er imidlertid kun et problem som opstår, hvis en partikel udsættes for så stor kraft at ledet går i stykker i første omgang, i løbet af een af fysikmotorens verlet-integration iterationer. Her har vi valgt at stå af, i første omgang, for et naturligt svar vil være at lave en model som har et mindre perfidt led så constrainten bliver sværere at overtræde. Det gælder her generelt, at der skal enormt meget mere kraft til at overrumple et drejeled med 180 graders drejespan, end et led med 359 graders drejespan. Alternative svar er at sætte antallet af fysik-iterationer per sekund op, at bygge og anvende en version af drejeledet med hjælpepartikler, eller at lave et runtime tjek på at partiklerne i drejeledet ikke bliver udsat for en for stor udefrakommende resulterende kraft. Med andre ord må det, pt, være brugeren af vores systems ansvar at sikre, at han ikke ødelægger det ved at begå vold mod et led som han selv har bestemt skal være svagt.

Til gengæld kan vi garantere mere for de mere specifikke led vi laver - vores eget underarms-drejeled, for eksempel, er designet med et span på netop omkring de 180 grader.

Men vores system er altså ikke fejlfrit, hvis ikke det bliver anvendt med omtanke, og det siger vi faktisk god for. Det er et generelt bibliotek til at modellere skeletter og led med, og skulle man ønske at implementere led der kan vrides i stykker i 3d med nøje specificerede krafter må man selv udbygge biblioteket med markeringer af partikler der indgår i svage led eller lignende.
Ligeledes gælder det samme hvis man ønsker for alt i verden at undgå overvridning, fordi man har en særlig voldsom fysikmotor.

Og skulle det vise sig at det generelle bibliotek har problemer med at fungere tilfredsstillende i openengine må vi blot lave en openengine udvidelse :-)

mandag, november 19, 2007

Testing python, ruby and lua bindings...

Vi har oprettet en extension og et projekt der tilsammen tester de 3 forskellige bindings klasser. Der er her gjort mest ud af Python bindings testene da det er dem som vi selv skal arbejde videre med.

Vores test extension kan findes på:

http://www.daimi.au.dk/~abachn/oe/extensions/BindingsTest/

Denne extension bruger PythonBindings, RubyBindings, LuaBindings og ScriptBindings. Kig her på bloggen omkring hvordan du får fat i dem.

Vores test project kan findes på:

http://www.daimi.au.dk/~abachn/oe/projects/EmbedBindingsTest/

Disse tests er ikke vores endelig projekt, men er mere proof of concept på at det vi har gang i kan lade sig gøre. Derfor vil disse ogsåvære fyldt med forskellige eksperimenter som kan være mere eller mindre brugbare!

Embedding python in C++

Så er det lykkedes at definere en C++ klasse, exportere den til Python. Oprette en liste af objecter af denne klasse i python og kalde en exportet function fra C++ hvor denne liste gives med. Denne function i C++ modtager nu listen og gennemløber denne for at udskrive elementer i denne.

C++ klassen:

class Point3D {
public:
double x, y, z;
Point3D(double cx, double cy, double cz) : x(cx), y(cy), z(cz) {};
};


C++ callback functionen

void printListPoint(object const& ob) {
stl_input_iterator begin(ob), end;
std::list il(begin, end);
for (std::list::iterator itr = il.begin(); itr != il.end() ; itr++) {
std::cout << (*itr).x << std::endl;
}
}


Export af functionen fra C++ til Python

BOOST_PYTHON_MODULE(hello)
{
def("printPointList", &printListPoint);

class_("Point3D", init())
.def_readonly("x", &OpenEngine::Scripting::PythonTest::Point3D::x)
.def_readonly("y", &OpenEngine::Scripting::PythonTest::Point3D::y)
.def_readonly("z", &OpenEngine::Scripting::PythonTest::Point3D::z)
;
}


Python coden der bliver kaldt:

import hello

p1 = hello.Point3D(1.1, 2.2, 3.3)
p2 = hello.Point3D(2.1, 6.2, 7.3)
p3 = hello.Point3D(3.1, 7.2, 8.3)
p4 = hello.Point3D(4.1, 8.2, 9.3)

pl = [p1, p2, p3, p4]

hello.printPointList(pl)


Output fra dette script!!

1.1
2.1
3.1
4.1


Som det kan ses så har vi oprettet nogle objecter i python, som vi så har sendt tilbage til C++, så vi der kan arbede videre med dem!

Næste skridt... i C++ lave instancer af nogle nogle python definerede klasser!!

Extension: LuaBindings

Extension name:

LuaBindings

Location:

http://www.daimi.au.dk/~abachn/oe/extensions/LuaBindings/

Purpose:

Create a abstract base class for integrating Lua into OpenEngine. This class should be used as a super class for your more specific extension that wants to execute lua scripts.

Dependencies:


Implementation details:

We have used the standard lua C API to implement the lua integration in OpenEngine. This abstract class gives the ability to run scripts or run entire lua files. Before each run a Pre() method is called and a Post() method os called after the script has run. These can be overwritten in a subclass, but are here given the default behavior of nothing. A default environment is setup before each run. Subclasses have to specify a Init() method when subclassing from this class. This Init method is used to export functions from C++ to lua.

Extension: RubyBindings

Extension name:

RubyBindings

Location:

http://www.daimi.au.dk/~abachn/oe/extensions/RubyBindings/

Purpose:

Create a abstract base class for integrating Ruby into OpenEngine. This class should be used as a super class for your more specific extension that wants to execute ruby scripts.

Dependencies:


Implementation details:

We have used standard ruby C API to implement the ruby integration in OpenEngine. This abstract class gives the ability to run scripts og run entire ruby files. Before each run a Pre() method is called and a Post() method os called after the script has run. These can be overwritten in a subclass, but are here given the default behavior of nothing. A default environment is setup before each run. Subclasses have to specify a Init() method when subclassing from this class. This Init method is used to export classes and methods from C++ to ruby.

onsdag, november 14, 2007

Extension: ScriptBindings

Extension name:

ScriptBindings

Location:

http://www.daimi.au.dk/~abachn/oe/extensions/ScriptBindings/

Purpose:

Common super class to all scripting languages we want to embed into OpenEngine.

Dependencies:

  • None


Implementation details:

This is a simple abstract class that defined some virtual methods which can be overridden in subclasses to give a more meaningfull behavior.

Toptunet drejeled

Vores drejeled har nu nået 4. iteration. Men før vi kaster os ud i beskrivelsen af den vil vi lige kort nævne iteration nummer 2 og 3:

Som det kan ses var anden iteration en stor konstruktion.

Det har sine årsager, men lad os starte med at sige, at vi redegør for de første led, ikke fordi de er gode, men fordi de illustrerer hvor store fejl man kan begå når man forsøger at modellere geometrisk funktionalitet i software.

2. Iteration:
Ideen er taget fra vores kugleled, hvor der sidder constraints fra alle partikler til alle partikler, og hvor minimums-afstandene mellem de to pyramidebunde kan forøges til det tidspunkt hvor de passer med, at ledet er helt strakt ud hvis det ikke er twistet - men det kan i den konstruktion give sig en del hvis man twister partiklerne i bunden af den ene pyramide 45 grader omkring midteraksen på figuren, hvorfor modellen er mangelfuld. Ydermere kan man ikke sætte grænser for rotationsgraden, så den dur ikke rigtig; Iteration 2 baserer sig på at forøge antallet af partikler som har minimumsafstande, altså i stedet for to pyramider hvor partiklerne i bundene ikke må komme for tæt på hinanden er her to figurer som er en approximation over flade kegler. På tegningen er et antal af gule minimumsafstande angivet. Men kegler passer ikke ind i vores system med porte, så derfor er der spændt porte ovenpå og nedenunder konstruktionen, og midterpartikler er nødvendige adskillige steder for at afstive strukturen.

Alt i alt er dette led håbløst indviklet, og ignorerer geometriske regler til fordel for et viderearbejde med noget, som er tried and true.

3. Iteration :

Her har vi genvundet fatningen lidt:
Dette led består af 4 pyramider, og portene er markeret med blåt. Det bærende princip er, at vi ønsker at kunne rottere 2 figurer som er placeret oven i hinanden i forhold til hinanden:
Det at fysiske led ikke kan have overlappende dele, betyder ikke, at vi behøver arbejde med den begrænsning. Vi kan tvært imod udnytte, at vi har mere fleksibilitet til rådighed. Vi kiggede derfor lidt på det, og indså, at vi kunne placere partikler på en cirkel ved at angive afstande til to punkter. Herfra var ideen at konstruere to centralt placerede overlappende firkanter, der altså havde partikler som kun bevægede sig på cirkelbuen, og så lave constraints på dem. Det er de to kongruente figurer, en sort og en grøn, som hver har 8 kanter.
De bliver hver låst fast på en port ved hjælp af lidt constraints.

4. Iteration

Men det viste sig, at det kan optimeres yderligere:


Her har vi udnyttelse af summen af ting fra de andre led: vi spender to porte direkte på 2 partikler med faste constraints. Det giver 2 dobbelt-pyramide konstruktioner, som bedst beskrives ved, at hver port laver to pyramider, som hver møder en af den anden ports to pyramider i spidsen. De er fint defineret i forhold til hinanden, og er ubevægelige i forhold til de to faste constraints, så såfrem man gør sit arbejde ordenligt er der ikke problemer. Den grønne constraint er tegnet på for at illustrere, at justerer man på max-størrelsen af den, så kan man justere drejbarheden af den ene pyramide i forhold til den anden.

5. Iteration

Men kan det gøres endnu bedre? her må svaret være ja - det kan det. "Man behøver kun at definere 3 afstande fra 3 punkter på en rigid-body til "noget andet" for at forholdet er bestemt": Det er en regel vi nu har fået praktisk erfaring for at bruge. Så det gælder altså for hver af de 4 dobbeltpyramider, at der kan undværes en constraint op til spidsen. Men vores fysikmodel anvender verletintegration, hvilket gør at man ikke kan stole helt så meget på, at afstanden mellem partiklen og pyramidetoppene er bibeholdt i korrekt det sted hvor constrainten (som ideelt set allerede er opfyldt) er sat på. 
Men man kan imidlertid foretage flere verletintegrationer hvis man kun arbejder med 25 constraints, end hvis man arbejder med 29. 
Og precisionen øges også med antallet af iterationer - så her er der tale om en afvejning.
Under alle omstændigheder er der kun tale om en lille optimering, så den vil vi ikke dokumentere yderligere.

tirsdag, november 13, 2007

Vores led

Lad os tage fat på beskrivelsen af de første led:

Tidligere har vi beskrevet et drejeled, fordi det umiddelbar var det mest komplekse led vi stod overfor. Hvorvidt vi får det implementeret i koden vil tiden vise, for det er ikke nær så essentielt som de andre led: Vi har studeret menneskelige led og knogler i materiale vi har skaffet, og det viser sig at drejeledet primært er nødvendigt for at modellere menneskers underarm. De andre ledtyper - hængselled og kugleled - er derimod anvendt overalt i kroppen.

Så derfor vil vi her fokusere på det design vi har lavet af kugleled og hængselled

Det kugleled vi har planlagt ser ca. således ud:



Dette led består af to kongruente pyramider, som er sat sammen ved spidsen. De to pyramider kan rottere frit i forhold til hinanden i vores mest basale model, så længe de ikke rotterer ind over hinanden. De er lavet ved hjælp af faste afstande partiklerne imellem, hvorfor der ikke er behov for diagonal-constraints i bunden. Det er illustreret på tegningen med de røde streger, der er constraints med en minimumsafstand som er ca. det samme som afstanden mellem to partikler i en af pyramidernes bund. Men her slutter det ikke - udover de tegnede constraints er det faktisk nødvendigt med samme minimumsconstraints fra alle partikler i den ene pyramidebund til alle partikler i den anden pyramidebund. Det er fordi pyramiderne selvfølgelig også kan "twistes" i forhold til hinanden. Vi vil forsøge at tilføje en tegning hvor alle constraints er sat på senere.

Hvis man ønsker at begrænse ledets twist-evne kan det forsøgsvis gøres ved at lave maksafstande på de røde constraints - men de skal beregnes nøje, og vi har endnu ikke undersøgt præcist hvordan det vil ha indflydelse på ledets bøjeegenskaber, og det bliver højest sandsynligt noget som bliver sat på når vi har mulighed for at visualisere det på skærmen.

Det næste led vi har arbejdet med er et universelt hængselled. Universelt, fordi vi ønsker at kunne begrænse hvilke vinkler det kan bøje sig indenfor.

Det ser således ud:

Det består af to prismer med lige stor højde og ligedannede trakenter som grund-areal.
Det er væsentligt at bemærke, at der på alle firkantede overflader i figuren er der behov for diagonaler.
Trekanterne i "bunden" (på tegningen ses de fra siden) skal forestille at være trekanter hvor alle vinkler er 60 grader. Endvidere gælder det for alle constraints som ikke er diagonaler i prismerne, at de har samme længde, og at denne længde vil blive givet med til ledet i dens constructor.
Den røde trekantsfigur som er tegnet på markerer en rød constraint og en rød vinkel. Det er fordi vi er i stand til at beregne længden af den røde constraint, der er en min/max constraint, som begrænser hvor meget leddet kan bevæge sig. Som standard vil man sige, at trekanterne ikke må gå ind over hinanden.
Vi kan, ved hjælp af sinusrelationen, den røde vinkel, og de røde kateter som støder op imod vinklen beregne hvor stor constrainten skal være for at låse leddet i en given vinkel. Envidere kan vi  anvende samme relation til at angive minimumslængde og maksimumslængde for constrainten, for på den måde at begrænse ledets bevægelsesevne. Det gør at vi kan modellere et knæled, der jo ikke kan bøjes fremad, for eksempel. At gøre det samme for den sorte vinkel og den sorte constraint gør blot at vi kan præcisere det yderligere.

Vi har også designet et udviddet drejeled, som vi vil snakke om senere, når vi har fået tegnet og dokumenteret det lidt bedre.

Design af skeletsystem, porte

Vi er nu nået til at arbejde med en konkret pythonimplementering af vores led, men først vil vi gerne snakke lidt om hvordan vores design flasker sig.

I den forbindelse har vi lavet en masse designarbejde, hvoraf jeg vil forsøge at gøre rede for noget af det her.

I pyhton er vores vigtigste mål, at producere et bibliotek med led og skeletdele, der kan sættes sammen på kryds og tværs af hinanden. Det gør vi objektorientere. Det vil sige, at hver skeletdel består af skeletdele eller er defineret ved hjælp af et basis.

Det eneste openengine er i stand til at forstå, er i øjeblikket partikler og constraints, så vores pythonobjekter skal nødvendigvis bestå af disse dele for at openengine kan forholde sig til dem. Med andre ord er vores basis: partikler og constraints.

For at producere et bibliotek med led og skeletdele må vi starte et sted, og da vi på sigt er interesseret i at vores bibliotek skal anvendes til ragdollfunktionalitet er det med ledene vi starter.
Men for overhovedet at producere led må vi være klar over hvordan vi har tænkt os, de forskellige skeletdele skal sættes sammen.

Vi har valgt at anvende en port-abstraktion. En port er i vores model 4 partikler der har constraints til hinanden. Hvis man er bekendt med geometrisk triangulering ved man, at et punkt defineret ved een afstand til et fast punkt kan ligge hvor som helst på en kugleskal, et punkt defineret ved afstande til 2 punkter gør at punktet kan ligge hvorsomhelst på en cirkelkant, hvorimod et punkt defineret ved afstande til 3 punkter nødvendigvis må ligge på eet bestemt sted.

For at integrere to systemer fast i forhold til hinanden i vores system, der kun har partikler og afstande, må de to systemer nødvendigvis være fælles om 4 punkter, der er defineret med afstande i forhold til hinaden. Fordi vi ønsker at vores led skal vende rigtigt i forhold til hinanden og kun klistrer sammen på bestemte steder er porte den bedste abstraktion vi har adgang til. Porte har, derudover, en universel form, således at vi kan optimere ved at kombinere to porte der er sat sammmen til 4 punkter uden at skulle forholde os til form, men kan nøjes med at kigge på størrelse. Vores porte ser ca. sådan her ud:


Så det gælder altså, at alle vores led og senere også vores knogler kommer til at anvende porte.

Vi har ikke besluttet om vores porte også skal have een universel størrelse endnu, men det kan godt være det viser sig at være lettest. Vi har endnu ikke forholdt os præcist til, hvordan vi ønsker at kunne skallere vores skeletter og lignende, men det gælder utvetrydigt, at hvis alle afstande i alle contraints bliver ganget med samme konstant vil systemet skalere, så det er kun relevant hvis vi ønsker forskelle i portstørrelse inden for samme figur. Indtil videre går vi ikke ud fra at vi har en universel størrelse, kun en universel form.

lørdag, november 10, 2007

løsning på drejeled

Et drejeled is er et meget begrænset led, som er i stand til ar dreje de opmodliggende knogler i forhold til hinanden. Vi arbejder for øjeblikket med en fysikmodel, der kun tilader partikler og constraints som afgrænser afstandene mellem partikler. Ved hjælp af modellen er vi kommet på 2 løsninger:

- A freespinning 1 point-joint with minimum-distance restrictions between points on either end of the joining point.

a 40 degrees box-skewing 4 vs. 4 points

Første mulighed giver leddet en evne til at rottere rundt og rundt på samme måde som et bilhjul, men de to ender af leddet er ikke nødvendigvis parallelle, så det har karakter af at være et kugleled. Det kan afhjælpes gevaldigt ved at tilføje flere partikler i den ene side af leddet, men vi ønsker at vi kan bygge skeletter ved hjælp af et universelt forbindelsesled, bestående af 4 partikler, så der skal sættes en yderligere forbindelsesstruktur ind.

Anden mulighed er den vi aktivt har arbejdet med:

Her er ideen, på den enkelte figur, at de hele streger er på forsiden og de stiplede er på bagsiden. De brune streger har en minimumslængde som er ca. 60% sammentrukket, og de er på billedet udstrukket i deres maksimumslængde. De røde siplede og de grønne hele udgør samme constraint: De har på billedet deres minimumslængde, og ingen maksimumlængde. Endelig har de blå stivere en konstant længde, og det har de sorte firkanter i hver ende også. Figuren hvor firkanterne er sat oven på hinanden er der, for at illustrere hvordan man kan opnå mere drejbarhed end ca. 40 grader.
Det enkelte leds funktion er, at i takt med at de brune bliver kortere, så vil figuren blive kortere, men på grund af de blå stivere bliver den nødt til at dreje, så den øverste ende drejer med uret. De grønne stivere er primært med for at sikre, at toppen ikke kan dreje imod uret.

Det er lidt svært at forklare hvordan det virker med ord, så hvis man har mulighed for at sætte sig med en terning eller lignende, og tegne de enkelte constraints, så vil det måske lette lidt på forståelsen.

Vi har ikke implementeret nogen af ideerne endnu, men i sidste ende vil det komme an på hvilken type drejeled man ønsker, og hvilke resurser man har til rådighed i forbindelse med beregninger.

tirsdag, november 06, 2007

Extension: PythonBindings

Extension name:

PythonBindings

Location:

http://www.daimi.au.dk/~abachn/oe/extensions/PythonBindings/

Purpose:

Create a abstract base class for integrating Python into OpenEngine. This class should be used as a super class for your more specific extension that wants to execute python scripts.

Dependencies:


Implementation details:

We have used Boost Python to implement the python integration in OpenEngine. This abstract class gives the ability to run scripts og run entire python files. Before each run a Pre() method is called and a Post() method os called after the script has run. These can be overwritten in a subclass, but are here given the default behavior of nothing. A default environment is setup before each run. Subclasses have to specify a Init() method when subclassing from this class. This Init method is used to export classes and methods from C++ to python.

mandag, november 05, 2007

Så er der plan!



Her har vi så vores relativt løse plan. Den er ikke helt korrekt afstemt, og har mest form af at være et kladdepapir, men redegør alligevel for størstedelen af hvad vi fik diskuteret ved første møde. Det må forventes at vi næste gang revurderer planen, skriver den op igen, og får nedfotograferet en lidt pænere udgave.

Python integration i C++ og CMake

Målet for dagens arbejde var at lave en simpel klasse der havde python embedded så det var muligt at eksekvere externe python script. Derudover skulle CMake udvides så den fandt både boost_python og python.[h|dll] på ens platform.

Det at lave en embedded python klasse vha boost_python var let. Klassen er tænkt som en superklasse til andre mere specifikke anvendelser af denne funktionalitet. På nuværende tidspunkt har den en konstruktør og en run metode. Konstruktøren tager en base sti til alle de script man vil loade og run metoden tager det script navn som skal køres. Dette virker uden problemer.

Denne extension kan findes på http://www.daimi.au.dk/~abachn/oe/PythonBindings/

Vi har også lavet et simpelt projekt som tester at vores PythonBindings klasse virker, compiler og linker korrekt.

Dette projekt kan findes på http://www.daimi.au.dk/~abachn/oe/PythonEmbedTestsProject/

En meget større udfordring var det at få CMake til at finde de rigtige python libs og include paths. Dertil skulle der også udvides i den allerede eksisterende boost del af CMake opsætningen da vi også skulle bruge boost python abstraktion.
Der vil komme mere til dette når vi har fået afklaret hvordan dette skal distribueres.

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....

fredag, september 28, 2007

I skal da ikke snydes for et screenshot

Jamen I skal da ikke snydes for at screenshot....



Som man kan se så er vi igang med at kigge på quadbuilder men har ikke noget i sving lige nu :-)

Sjov detalje

Det virker også fint med at have vilkårlig mange SceneNode's efter hinanden. Så strukturen

+---------+
| SceneN |
+---------+
^
|
|
+---------+
| SceneN |
+---------+
^
|
|
+---------+
| SceneN |
+---------+
^
/ \
/ \
+------+ +------+
| GeoN | | GeoN |
+------+ +------+

Men underligt nok kan man ikke lave det samme med bare GeometryNodes .... man kan undre sig!!

Ting man ikke skal gøre med scene grafen

Vi er igang med både QuadNode og BSPNode og eftersom vi skulle have noget at teste vores QuadNodes på så skulle den nye Sahara level loades. Men så var det at tingene gik hen og blev underlige. Til en forelæsning havde vi hørt at man godt kunne have en GeometryNode som havde GeometryNodes som børn og få tegnet det hele. Virker meget lige til .... men prøv bare og din verden ser anderledes ud..

Vi fik oprettet en GeometryNode root og satte 2 GeometryNode's under med henholdsvis skybox og ground fra sahara modellen. Med stor spænding kiggede vi og opdagede at der ikke skete noget :-/ Skærmen blev ved med at være sort og ingen grafik viste sig.

Denne fejl er ikke den fedeste at vise screenshots af så det lader jeg være med. Men jeg tog problemet over til OE folkene og de kunne så konstatere at det skulle den sq ikke gøre... men hvorfor den gjorde sådan kunne de ikke svare på. Så hvis du ønsker at have 2 GeometryNodes over hinanden i din scenegraf så vær klar på mærkelig opførsel!

The way to do it... som I nok allesammen vidste er


+--------------+

| SceneNode |

+--------------+

^

/ \

/ \

/ \

+------+ +------+

| GeoN | | TraN |

+------+ +------+

^

/ \

/ \

/ \

+------+ +------+

| GeoN | | GeoN |

+------+ +------+


Så hav altid en SceneNode i toppen og lad være med at have GeometryNodes lige efter hinanden :) Ellers renderer det ikke ordentligt.

Nå, men tilbage til QuadTreeBuilder.....

onsdag, september 26, 2007

Scene representation og DirectX

For at state men nogle reflectioner på OE frameworket så er der tænkt over rigtig mange ting, men nogle gange er dokumentationen ikke præcis omkring hvor noget kan bruges. Et eksempel kunne være en node->GetTransformationMatrix().ToArray(blah) her står der ikke noget om at dette array som leveres tilbage har strukturen som kan bruges til noget i forhold til OpenGL, men det er noget som man selv skal gætte. Sådan er der flere små steder hvor dokumentationen kunne bruge en lidt skarpere formulering.

Selve scene repræsentationen er meget generel og kan derfor let udvides. Det virker meget som om at der er tænkt over hvordan dette hænger sammen.
Selve den måde at man gennemløber scenegrafen og brugen af visitor er igen generel og derfor let at forstå, men igen så er der nogle performance issues med alle de forskellige metoder der skal kaldes.

Hvis man skal se OE i forhold til DirectX og bruge det i stedet for OpenGL vil der være en række ændringer man skulle tage. Jeg vil ikke gå i detaljer med hvor men bare give et overordnet billed af hvor sådanne ændringer skulle laves.

  • Vi bruger GLSL men skulle i stedet bruge HLSL så der skulle skrive en HLSL plugin til at loade shaders

  • I vores RenderView klasse bruger vi OpenGL kald til at tegne face's på screen, dette skal laves om til DirectX kald.

  • I OE frameworket under Renderer::OpenGL skal der laves en tilsvarende Renderer til DirectX


Dette viser at det ikke bare er i vores kode, men i hele frameworket som skal udvides. Men det er bestemt ikke umuligt, da OpenGL kode er isoleret til en del af frameworket og ikke spredt ud over det hele.

Vi har ikke implementeret follow cameraet, da vi havde meget at gøre med bare at lave de shaders og forstå hvordan sådanne skulle udvikles.

Parallax og Oily Shaders

I denne uge skulle der udvikles 2 shaders. Nedenfor ses der nogle screenshots af vores implementation af de forskellige shaders.



Her ses parallax shaderen på RockWallBumpMapped modellen. Denne parallax er bygget over bumpmap coden og ændret i forhold til den tegning fra slides omkring hvordan de korrekte punkt findes i forhold til eyeVec.



Vores oily shader eller også kendt som thinfilm shader til at give en olie films agtig overflade.

Udviklingen af shaders er meget vanskeligt som begynder i game development. Der er nogle detaljer omkring at ting bliver compilet væk hvis de ikke bruges, dette kan give nogle underlige fejl. Der er også meget svært .. til tider at gennemskue fejl i shader kode. Det kunne være en ide at til en anden gang give 1 lidt mere gennemskuelig opgave og så en opgave som thinfilm eller parallax!

fredag, september 21, 2007

Shaders, mouselook, transforms og bugs

Så!
Nu fik vi langt om længe implementeret et (billigt) mouselook. Vi har udviddet Structen i IMouse klassen så der i mousemovedeventarg er kommet dx og dy på (efter kyndig vejledning fra Ian), og når denne løsning på et tidspunkt bliver officielt implementeret skulle det være meget let at patche vores kode. Er vi blevet lovet.

Det betyder at vores kamerahandler nu bliver kaldt med et mousemovedeventarg i stedet for ijkl til at rottere om kameraets akser. Det betyder også at vi ikke rotterer i chunks mere, men direkte anvender den afstand musen flytter sig, og det bør give et kønnere resultat, og vi kan også dreje på flere akser samtidig.



Vi prøvede at lave muse-centrering vha. SDL efter hvert movedevent blev sendt til kamera handleren, men det gik ikke så godt - Værdierne bliver forvrænget, "tilsyneladende" rammer vi den state i SDL som bliver brugt til at opbevare den præcise museplacering fra sidste cycle. Den bliver anvendt til at beregne næste cycles relative muse-bevægelser, og når den så bliver flyttet midt i at de relative bevægelser er ved at blive optaget, så sker der noget uventet (og grimt). Hvornår det er sikkert at kalde mouse-wrap funktionen så det ikke får side-effekter kan vi ikke umiddelbart overskue, så vi har droppet centreringen til en start og i stedet skal man holde venstre museknap inde for at kamerahandleren reagerer på de mouse-events den får tilsendt.

Vi har også lagt planer for hvordan et "rigtigt" fps-style kamera kan implementeres. Kameraets evne til automatisk at lave translates og rotations til een transformationsmatrix vil her være rigtig god, idet der bare skal opbevares en lille smule state i kameraet for at den horizontale og vertikale rotation kan foretages som det sker i for eksempel half life.

Det var mouselook - det næste er, at vi har fået vores kode til at virke sammen med den udleverede. Sådan da. Vores texturekode er ikke så køn som vi gerne ville ha, og den er vidst ikke engang aktiv lige pt. Til gengæld virker shaders nu.
Og vi har lavet en implementation af transformationnode; Den tager imod transformationsmatrixen som ligger i noden og omskriver den til en matrix som opengl kan forstå, og så bliver den applied (de andre på holdet må lige kommentere hvis det ikke er helt korrekt formuleret).

tirsdag, september 18, 2007

Enable key repeat

Når man nu bliver træt af at trykke hver gang man vil flytte på kameraet kan man jo enable keyboard repeat. Dette er gjort via

SDL_EnableKeyRepeat(int delay, int interval);

En finte er nu at det event som bliver sendt en en KeyDown og derfor skal man huske at lytte på KeyDownEvent køen.

FutureTank up and running

Efter at vi i sidste uge fik gjort vores OBJ loader færdig (troede vi) kunne vi i denne uge konstatere at vi ikke lyttede efter usemtl og derved ikke fangede hvornår vi skulle bruge en given material resource. Dette blev tilføjet og som hurtigt til at virke.

Det var relativt simpelt så at få tegnet vores loadede model uden textures. Dette var bare for at komme igang og derved få testet at vi havde fat i den rigtige ende.
Derefter tilføjede vi texture mapping hvilket gik relativt smertefrit hvis man tænker bort fra en cut'n'paste fejl der vagte lidt undren ;-)



Vi har i gruppen fået arrangeret os med to darcs repos her på uni, som vi kan tjekke ind og ud af og derfor holde folk i gruppen up-to-date.

lørdag, september 15, 2007

Fix i SDLInput og bedre OBJ loader

Efter at have fået nogle tips på mail listen omkring SDLInput og have tænkt lidt selv, blev vi enige om at have en mouse state inde i SDLInput og update den hver gang der kom et MouseMoved event, dette gør så at GetState() giver den korrekte mouse state hver gang!
Samtidig med dette blev der også lavet nogle små updates af koden!

Den anden store bedrift er at have en fungerende OBJ loader (eller det mener vi at vi har). Vi har brugt boost::algorithm::string::trim og boost::algorithm::string::split til at kunne klippe lidt i tekst strenge. Vi synes allesammen at gøre det ved hjælp af sscanf var en smule for ikke intuitivt så derfor ville vi gå efter en måde at klippe os frem til det.

Når man læser en OBJ fil, får det hele ud på at lave en Face ud fra nogle vertices, texture coordinates og nogle normals. Som det kan ses nedenfor har vi brugt nogle indbyggede klasser i OE for at gøre dette lettere.

vector< Vector<3,float> > vertices;
vector< Vector<3,float> > texture_coords;
vector< Vector<3,float> > normals;


Ved at bruge boost::algorithm::string::split og trim er det ikke sværere at klippe en tekst i stykker end at skrive.

in->getline(buf,255);
string str(buf);
vector<string> tokens;
// remove whitespaces from string
trim(str);
// populate tokens with the bits from str seperated by " "
split(tokens, str, is_any_of(" "));


Det var lettere i test of debug fasen at bruge en mindre OBJ fil som ind-put til loaderen. Der kunne måske godt have været udleveret en simpel model som en Cube beskrevet med de dele af OBJ formatet som vi skulle læse. Derved have vi noget simpelt som stadig skulle have det hele i sving.

torsdag, september 13, 2007

3dObjekter og fillæsning

I dag sad vi og nørklede med .obj formatet.
*.obj filer er, kort fortalt, filer som indeholder geometrisk data, enkodet med karakterer. Vi fik en container til geometriske faces stillet til rådighed, og ligeledes en container til containerne, som så, inden for openengine, kan opbevare store geometriske figurer svarende til dem som er i .obj filerne.

Vores hovedpine gik så på at skrive kode som kan iterere igennem en vilkårlig .obj fil, opdele indholdet i små bidder og fylde hver bid i "face" containere, og så derefter fylde disse containere i "faces-list" containere.

Efter at have sat fillæsnings delen op så den indlæste filen i tokens arbejdede vi med tolkninger af de tokens, som alle var strings, og fik opstillet en algoritme som fortolker dem fornuftigt, og indlæser dem i vektorer, og derefter løbende skal overføre indholdet af vektorerne til face objektor.

Det var sådan ca. her vi sluttede, med en dejlig masse fejl vi skal ha rettet næste gang vi kigger på det, men vi er fortrøstningsfulde og mener vi har den rette tilgangsvinkel.

Af andre nyheder kan vi støtte det seneste forslag mht. mousemotion der er kommet op på mailinglisten - der er, som vi ser det, ingen grund til at vores listener klasse selv sidder og roder med et mouse-motion-event når den alligevel modtager et godt event fra SDL - lad den sende eventet videre som det er, direkte ud til handlerne. Idet openengine ikke har noget overordnet specifikt formål, men derimod må forventes at blive anvendt til en række forskellige ting vil det, efter vores mening, være oplagt ikke at skære ting fra på den måde.

Det er rart med en listener som oversætter events så de giver mening i vores kontekst, men at reducere størrelsen af event arg'et virker ikke udpræget som noget vi har brug for.

Endelig er der ingen kode som vil gå i stykker hvis den strukt mouse-motion-event-arg benytte bliver udviddet så den er mage til det arg der kommer fra sdl.

Vi lavede gerne selv udviddelsen, men vi tør ikke give os i kast med så relativt stor en ændring i en motor som trods alt stadig er os relativt ukendt, en ændring som ikke nødvendigvis ville være kompatibel med fremtidige patches... og vi håber derfor at denne ændring vil blive foretaget fra kursusarrangørenes side.

Det må være det for denne gang - et af vores gruppemedlemmer har oplevet en del tekniske...issues, men de virker til at være udbedret nu, og de er veldokumenterede på mailinglisten så dem vil jeg ikke nævne her.

Over and out