Thursday, January 31, 2008

Prototipo di motore e hud


Ne approfitto per farvi vedere come procede l'implementazione del motore, e anche quella dell'HUD, anche se la qualità scarsa del filmato rende di fatto impossibile leggere i nomi.
Noterete che il movimento laterale e sopra/sotto e' ancora troppo inverosimile, mentre quello avanti-indietro è più morbido e realistico.
Penso di aggiungere un campo di "polvere" per dare maggiormente l'illusione del movimento, necessaria in quanto nello spazio, mancando punti di riferimento vicini, è quasi impossibile capire se ci si sta muovendo o se si è fermi.

Doveva succedere...

Oggi mi hanno comunicato che dovrò iniziare un nuovo lavoro, che senz'altro sull'immediato mi impedirà di dedicare al gioco (e al blog) il tempo che ho avuto questo mese.
Era inevitabile, e a dirla tutta anche giusto.

Questo però non vuol dire che mollerò. Quando iniziai, in Dicembre, l'intenzione era quella di sfruttare l'assenza di lavoro non per grattarmi ma per dare almeno un senso alla giornata, e che sarebbe tutto finito nel momento in cui avessi finalmente ripreso a produrre per ciò per cui mi pagano.
Durante questo mese però mi son reso conto di come sia preziosa per me questa esperienza, di come mi faccia sentire realizzato il riuscire anche solo a far apparire un pianeta, il poter "annusare" quello che giornalmente fanno coloro che sviluppano videogiochi, uno dei miei sogni nel cassetto (l'altro è fare l'astronauta, ma lasciamo perdere :) ), e da quando mi ci dedico mi sento molto meglio con me stesso, e credo di riflesso anche coloro che mi circondano: sono meno musone, ho il mio angolino di fantasia nel quale rifugiarmi quando tutto attorno va a rotoli, e pertanto non voglio rinunciare a tutto questo.
E' però ovvio che non potrò impegnare lo stesso tempo che ho impegnato fino ad oggi, le cose saranno più lente ma probabilmente anche più meditate. Tanto non ho nessuna fretta, non devo conquistare nessun mercato, nè ho delle scadenze da rispettare.

Per questo motivo colgo l'occasione per cambiare il titolo del blog.

Wednesday, January 30, 2008

HUD 2


Lo so, ieri parlavo di motori, ed oggi son di nuovo qui a parlare del computer di bordo.
Ma ieri riflettevo sull'utilità del HUD così come l'avevo implementato e mi sono accorto che può diventare ancora più prezioso se, oltre ad indicare gli oggetti visibili, riuscisse a dare qualche informazione su dove si trovano quelli che invece escono dal campo visivo.
Tutto nasce dal fatto che ora ho implementato il movimento della telecamera non piu' lungo una circonferenza, ma sulla superficie di una sfera, per poter così guardare in tutte le direzioni, e non solo a destra e a sinistra. E mi sono accorto che così facendo, diventa un'impresa riuscire ad inquadrare un qualsiasi oggetto. Oggetti molto lontani infatti sono altrettanto sensibili alla rotazione della telecamera, e spesso basta un piccolo movimento per perderli di vista (chiunque abbia mai provato a guardare il cielo con un telescopio mi ha capito).
L'idea quindi è quella di indicare con delle frecce la posizione degli oggetti che sono fuori dallo schermo, in modo da permettere all'osservatore di sapere dove ruotare la visuale per poterli inquadrare.
L'immagine che vi propongo (solito click per ingrandirla) è la testimonianza di quello che vi ho appena raccontato: la terra è inquadrata, la luna e' invece più a sinistra, e giove infine è in alto a sinistra. Il sole è dietro, pertanto non compare il suo identificatore.
Ed in effetti ora è diventato semplice trovare un oggetto, mentre prima era a dir poco proibitivo!

Tuesday, January 29, 2008

Signor Scotty

Bene, abbiamo un piccolo motore che disegna pianeti e che gestisce le distanze reali tra corpi celesti. Abbiamo l'illuminazione dinamica, che dipende dalla posizione della stella. Abbiamo un prototipo di HUD che ci aiuta ad identificare la posizione deglio oggetti scuri o lontani, manca ancora una mappa del settore (quella della galassia è abbozzata, se ricordate).
Che facciamo adesso?
Credo sia tempo di iniziare a lavorare alla propulsione.
Nel mio piccolo prototipo per ora ci si sposta orientandoci col mouse e muovendoci con i consueti tasti WASD, comodo per esplorare velocemente le zone del sistema solare, ma non certo realistico per il gioco. Ci vuole quindi una propulsione di tipo newtoniano, ovvero la simulazione di come si muove un'astronave nello spazio.
Principalmente vi son due tipi di motori: quelli di propulsione e quelli di manovra. I motori di propulsioni permettono di dare la spinta all'astronave e in sostanza di muoversi per lo spazio. Motori che però hanno un limite: spingono, e spingono solo lungo il vettore dell'astronave. Come del resto avviene in una comune automobile, la quale si sposta seguendo la direzione "puntata" dal muso. Per cambiare la direzione di movimento una macchina utilizza le ruote anteriori, con lo sterzo si girano le ruote e l'attrito con l'asfalto fa il resto.
Nello spazio ovviamente non è possibile usare questo trucco, quindi pensavo di prevedere 4 piccoli motori aggiuntivi, che permettono alla navicella di ruotare a sinistra, a destra, verso l'alto e verso il basso.
Il difficile sarà implementare il medesimo tipo di movimento anche nelle astronavi guidate dal computer, quindi creare una AI che sappia quale motore accendere e quando farlo se vuole arrivare dal punto X al punto Y, ma di questo mi preoccuperò in un secondo momento.

Pro memoria mio personale: supposto che l'astronave pesi m kg, supposto che il motore di propulsione abbia una forza f, supposto che il motore venga tenuto acceso per t secondi, e supposto che prima di accendere il motore l'astronave avesse una velocità v1, la velocità al termine dell'uso del motore e' v2=v1+f*t/m

Già meglio...



:)

Monday, January 28, 2008

HUD


Uno strumento essenziale, quando si viaggia nello spazio, oltre alla mappa, è senz'altro l'HUD, ovvero il computer di bordo in grado di sovrapporre delle immagini sintetiche a quello che viene visto fuori dal "finestrino".
Al di là del nome che fa molto "Star Trek", l'HUD si rende necessario specie per identificare quegli oggetti che sono troppo lontani o troppo scuri e che quindi non risultano visibili.
L'immagine che vi allego è un esempio abbastanza chiarificatore (clickateci per ingrandirla): di fronte a noi c'è la Terra e la Luna, ma son piccolissime visto che sono lontane, mentre Giove è molto visibile.
Se dovessi dirigermi verso la terra come faccio? L'idea è quella di racchiudere tra un rettangolino il centro di ciascun oggetto in modo che anche se l'oggetto è invisibile siamo comunque in grado di localizzarlo.
Ancora è troppo grezzo, oltre al rettangolino voglio metterci anche il nome del corpo inquadrato (sareste in grado di distinguere nell'immagine la Terra dalla Luna?), ma intanto la versione "base" funziona, e sopra di questa posso costruirci qualcosa di più appetibile

Thursday, January 24, 2008

A spasso per lo spazio...

Ho appena terminato lo sviluppo della parte che si occupa di disegnare (correttamente) più di un oggetto, quindi finalmente ho l'occasione di mettere tutti gli "attori" che vi ho fatto vedere nei giorni scorsi.
Così ecco sullo schermo il sole, giove, la terra, la luna, e una piccola astronave.
L'algoritmo di ordinamento pare comportarsi davvero bene, ed i problemi del depth buffer speriamo siano chiusi una volta per tutte.
Quindi ne approfitto per farvi vedere un filmato di quel che ho per ora tra le mani.
Purtroppo ho dovuto usare fraps non registrato per creare il video, e i 600 fps che ho nella realtà son scesi a 30 per via della versione demo (no, quasi 40 dollari per catturare lo schermo non glie li do, mi dispiace), quindi la scena non è fluida, quindi vi chiedo un atto di fede :)
Ad ogni modo vuole solo essere un breve filmato che riassume quel che vi ho raccontato in questa settimana.

Wednesday, January 23, 2008

Luna chiama Terra, Terra rispondete.

Oggi nessuna gran novità, prima di imbarcarmi nell'avventura di gestire via CPU l'ordinamento degli oggetti, ho voluto fare ancora alcune prove, indirizzato dai suggerimenti di un esperto, per vedere se il depth buffer globale poteva in qualche modo essere salvato senza dover far a fette lo spazio, che è comunque una complicazione che porta via tempo.
Non ci son riuscito (tecnicamente parlando: ho verificato se per caso la scheda video mi permettesse di usare il wbuffer, ma niente da fare, la mia 7600 go non lo gestisce...), quindi salvo colpi di scena vado avanti per la strada che vi ho raccontato ieri.
Nel frattempo però volevo lasciarvi con uno screenshot appena fatto, che illustra il tramonto della terra visto dalla luna.
Non fa urlare al miracolo ma ha la sua dignità.
Ovviamente sentitevi liberi di commentare e criticare.

Tuesday, January 22, 2008

Buongiorno, vorrei una fettina di spazio. Senza grasso.

Ok, come accennavo ho trovato la soluzione, e a quanto pare funziona.
DirectX, come anticipato in precedenza, usa uno strumento chiamato "depth-buffer" per aiutarsi nel disegnare gli oggetti tridimensionali, evitando che vengano elaborati inutilmente pezzi che tanto non si vedranno.
Il problema è che il buffer fornito ha uno spazio limitato, o meglio, una precisione limitata.
E' uno strumento in grado di dire quali sono gli oggetti che stanno davanti, e quelli che stanno dietro, ma per farlo ha bisogno di appicicare un numero a ciascuno di questi componenti della scena.
"A te do il numero zero perche' sei lontanissimo"
"A te do il numero 1 perche' sei proprio davanti al mio naso"
"Tu che stai in mezzo ti do il numero 0.5".

E così via. Più il numero è grande e più l'oggetto e' vicino a noi.

Ora sarebbe bellissimo che questo strumento avesse tutti i numeri possibili ed immaginabili così da poter gestire anche casi tipo:
"Tu che stai due millimetri davanti a tizio ti do il numero 0.50000000000002"
"Tu che stai tra tizio e quello che e' appena andato a 2 millimetri di distanza, ti do il numero 0.50000000000001"
Purtroppo la realtà è che questo buffer può contare "solo" su 16 milioni circa di numeri.
Sembrano tantissimi ma in realtà non mi bastano affatto. Se infatti considero come distanza massima, ad esempio, la distanza tra il sole e giove (oltre il sole appare come un puntino e non ha nemmeno senso farsi troppi problemi), sono 816 081 455 km di distanza.
Diviso 16 milioni fa una tacca ogni 51 km, ovvero per due oggetti che distino tra loro meno di 51 km il buffer non ce la fa a dire quale dei due è avanti e quale dietro.
Ve l'ho un pò semplificata, in realtà le cose sono più complesse, e il depth-buffer comunque garantisce una maggior precisione per gli oggetti vicini, a discapito di quelli lontani (le prime tacche, a partir dal vostro naso, son tra di loro molto vicine, ma la distanza tra l'una e l'altra va via via aumentando man mano che si allontanano da voi) , ma concettualmente la questione sta esattamente in questi termini. Ecco quindi il perchè con tutto un universo da rappresentare, la scheda video si confonde quando due oggetti son tra di loro relativamente vicini. E purtroppo, come detto, per dar maggior precisione a ciò che ci sta vicino, viene trascurato quello che invece è molto lontano, assumendo che "tanto è lontano, vabbè farò dei pasticci, ma pazienza, in lontananza si vedrà piccolissimo, chi vuoi che se ne accorga". Già, ma nel mio caso i pianeti e gli astri son MOLTO grandi, quindi pur lontanissimi sono tutt'altro che minuscoli, ed ecco che appaiono le schifezze che vi ho fatto vedere nella puntata precedente.
Come si fa allora?
Beh, se il problema è fare stare quelle 16 milioni di tacche molto vicine tra di loro c'è poco da fare: o si aumentano il numero di tacche (e non si può), oppure occorre ridurre la distanza che devono ricoprire. Ridurre lo spazio però non mi va, altrimenti rischio di tornare verso ciò che non amo dei giochi visti fino ad oggi, ovvero dimensioni spaziali ridicole tipo "100 km tra il pianeta e il sole".

La soluzione che ho trovato leggendo in un forum, è una sorta di compromesso: faccio fare al depth buffer il lavoro di decidere chi disegnare prima e dopo solo all'interno di un oggetto complesso. Ovvero, considero la scena non più composta da migliaia di triangolini, come avveniva prima, ma piuttosto da "una sfera", "un'altra sfera", "un'astronave", ecc..
Al depht buffer do il compito di disegnarmi di volta in volta solo un oggetto coi suoi innumerevoli triangolini che lo compongono , quindi lui deve solo preoccuparsi che l'ala dell'astronave che sta dietro non appaia in quanto nascosta da quella davanti, dopodichè sarò io (la cpu) a disegnare i macro oggetti in ordine, dal più lontano al più vicino, visto che io (la cpu) ho tantissimi numeri in piu' rispetto alla scheda grafica, e non ho il problema di dovermi accontentare di 16 milioni.
Di contro la scheda video non dovrà più ragionare in termini di 800 milioni di km: se deve disegnare il sole ad esempio, ovvero l'oggetto più grosso, e se pensiamo di appoggiarci al nostro naso la superficie solare (dopo esserci messi abbondanti dosi di crema), il punto più lontano del sole disterà a questo punto da noi circa 600.000 km. E in questo caso la precisione è sufficiente. Gli altri oggetti poi sono tutti più piccoli.. et voilà!

Riassumendo quindi, decido di fare a fette lo spazio, in cubetti che avvolgono i vari oggetti, limito al volume dei cubetti l'azione della scheda video per disegnarli, dopodichè, ottenuti tutti i cubetti dipinti, sarà compito mio, ovvero il signor CPU, decidere qual è il più lontano e quale il più vicino, così li dispongo in ordine e vedrò tutto correttamente.

Certo, perdo l'ottimizzazione fatta dalla scheda video, se il sole sta dietro a giove, io comunque disegno tutto il sole, e poi ne ricopro un pezzo o tutto con il disegno di giove ma... onestamente con l'immensità dello spazio in gioco quante probabilità vi sono di avere un'eclisse?

Monday, January 21, 2008

Buffer non troppo profondo


Appena finito di litigare con il coprocessore matematico si inizia subito col depth buffer.
Ovvero quello strumento della scheda video che permette alla medesima di decidere quali sono gli oggetti che stanno davanti, quelli che stanno dietro, e quindi quelli che vanno disegnati e quelli invece che non serve rappresentare visto che son comunque nascosti da qualcosa di più vicino.
Nell'ottica infatti di rendere le schede più veloci, si è deciso che è inutile disegnare un oggetto che poi verrà comunque nascosto da un altro oggetto più vicino.
Insomma se mi trovo dentro una stanza senza finestre, e fuori c'è un albero, non ha senso disegnare l'albero che tanto poi verrànascosto dalle mura della stanza.
Il problema è che il depth-buffer non è preciso al 100%, anzi, più gli oggetti sono lontani e più diventa impreciso. Figuriamoci con pianeti e stelle che son lontanissime.. ed infatti ecco rappresentato (in figura) cosa succede.
La domanda è: come risolvo?
L'idea che per prima mi viene in mente è quella di ridurre distanze e dimensioni. In fondo ho già una scala in double che mi rappresenza con precisione "al metro" posizioni e distanze, potrei provare a fare un cambio di coordinate in modo che i pianeti ad esempio che visualizzo siano 1000 volte piu' piccoli e mille volte piu' vicini, l'effetto sarebbe identico.
Quel che pero' mi spaventa è che se riduco le dimensioni, lo devo far per tutto, anche per gli oggetti piccoli, e non vorrei che la cosa finisse per crearmi dei problemi quando ho a che fare con piccole astronavi che volano vicino, che al momento del rendering magari appaiano sovrapposte o con altri problemi.
Altrimenti potrei provare a disegnare gli oggetti in ordine di posizione: prima i più lontani e poi quelli più vicini, perdendo in ottimizzazione, visto che di fatto non userei piu' il depth buffer, ma almeno risolvendo il problema.
Sennò... altre idee?

AGGIORNAMENTO 17.00 : ho probabilmente trovato l'escamotage per risolvere il problema una volta per tutte. Ma ora è tardi, ne parlo domani.

Friday, January 18, 2008

149597870 + 1 = 149597872

Sarò un pò più tecnico del solito, ma ciò che ho passato, per colpa di una somma, merita senz'altro la pubblicazione.
Come detto in precedenza ho deciso di utilizzare la doppia precisione, così da riuscire a gestire sia distanze siderali, che distanze ravvicinate.
Bene: ho posizionato la mia astronave a 1 au di distanza dal sole, ovvero 149597870 km dal sole.
Dopodichè ho impostato la tastiera affinchè premendo il tasto W la posizione aumentasse ogni volta di 1 km.
Provo e.. l'astronave non si muove.
Guardo e riguardo il codice e mi sembra tutto a posto.
A questo punto decido di stampare a video le coordinate per vedere che succede.. e mi accorgo che la prima volta che premo W, il valore diventa 149597872 (!!), e alle seguenti pressioni rimane 149597872.
Cioè, pure una calcolatrice anni '70 sa fare 149597870 + 1, possibile che un dual core con FPU no?
Ovviamente mi dico: "è senz'altro colpa mia, chissà che ho combinato".
Provo a creare un progetto vuoto e ci scrivo quella somma e lancio.
Funziona.
"Come immaginavo, ho sbagliato io"
Torno al mio progetto, eseguo la somma ad inizio programma e nel punto dove sbaglia. Ad inizio programma funziona, nel punto in cui gestisce la pressione del tasto W no.
Comincio a togliere tutto il superfluo per isolare la causa dell'errore.. arrivo a commentare TUTTO, tranne la gestione del tasto W, sparisce tutto quanto, rimangono solo due somme; una all'inizio e una dopo la "se ho premuto W". Nient'altro.
Non va. All'inizio la somma e' corretta, dopo l'if no.
L'informatica è una scienza esatta, almeno fino a ieri lo pensavo.. disperato inizio a chiedere in giro, non riesco davvero a capire.
E una persona, gentilissima, mi rivela l'arcano.

A quanto pare DirectX, quando invocata, si diverte a abbassare la precisione del coprocessore matematico, "dimenticandosi" di risistemarla quando ripassa il controllo al mio programma.
Ergo: il programma parte, la precisione è a posto, e la somma funziona, subito dopo DirectX mette le mani, ed ecco che la seconda non va più.

Pazzesco.

Ad ogni modo, per la cronaca, per risolvere tutto è bastato aggiungere

_control87(_CW_DEFAULT, MCW_PC);

prima della somma.

Wednesday, January 16, 2008

Unità di misura 2

Tanti ragionamenti.. tutti sbagliati purtroppo.
DirectX lavora internamente in singola precisione (formato float in C++), e la singola precisione è ahimè insufficiente per riuscire a rappresentare il sistema solare.
Mi spiego: una volta decisa l'origine del nostro ambiente, che avevo scelto coincidente col sole, e scelta come unità di misura 1 = 10.000km, andando a lavorare con dimensioni piccole, tipo 10 metri, (la dimensione di una navicella), i numeri diventano dell'ordine di 0.000001
Ora: se ci troviamo sufficientemente vicini all'origine non c'e' problema usando questa scala, se pero' siamo nei pressi di plutone, che sta a (581000.0,0,0) , il numero "grande" prende il sopravvento e viene "sacrificato" il piccolo, col risultato che si ottengono dei troncamenti che fan si' che la navicella si muova a "balzi" di 1 kilometro od oltre, con un risultato visivo orribile.
La stessa cosa avviene se abbassiamo la scala.. il numeri diventano dell'ordine di 0.1 (per ipotesi), ma la coordinata di plutone diventa una cosa del tipo (5810000000,0,0), e nuovamente entrano in gioco i troncamenti.
Come risolvere? L'idea che ho avuto è quella di:

1) utilizzare un sistema di coordinate in doppia precisione (che però non è compatibile con directX), per rappresentare tutti gli oggetti che fan parte del sistema solare. Dovrebbe garantirmi una precisione sufficiente a rappresentar distanze siderali come distanze nell'ordine dei metri quando due astronavi ad esempio son vicine

2) impostare l'origine non più nel sole ma nella telecamera, così che gli oggetti vicini alla telecamera siano anche prossimi allo zero.. quindi se ho un oggetto vicinissimo, lo converto da double a float ma non perdo precisione. Un oggetto invece molto distante probabilmente, convertito, perderà di risoluzione, ma essendo molto lontano apparirà piccolissimo, probabilmente invisibile. Un errore, da lontano, sembra piccolo, e più lontano è, e più sembrerà microscopico. Come una macchia su una giacca, se la persona sta a 500 metri da voi, non ve ne accorgete.

Speriamo sia la strada giusta. Nel frattempo ho implementato anche la gestione delle mesh create esternamente da altri programmi (es: blender), e questo screenshot è una prova con un'astronave (orribile) trovata assieme al SDK di DirectX. Uso questa per ora come sistema di riferimento, poi col tempo spero di arrivare a disegnare qualcosa di più decente.

Friday, January 11, 2008

Telecamera


Nei corridoi deserti di una nota compagnia assicurativa non si muove una foglia, non ho mangiato, non mi arriva nulla da fare, così per non impazzire vado avanti con Tau Ceti.
Ho implementato un semplice controllo della telecamera, che prima poteva solo orbitare attorno al sole, ora invece la posso muovere ovunque e ruotare il punto di vista.
Cosi' son riuscito a scattare un paio di foto interessanti: Giove dal lato illuminato, che prima era impossibile vedere in quanto la telecamera puntava sempre solo al centro del sole, e un'immagine "apocalittica" di Giove prima di tuffarsi all'interno del sole.
Da notare che giocando con la luce speculare e con la potenza che ne regola la dimensione dello spot, si ottiene un effetto "bloom" che aumenta l'impatto di quella che in fondo e' una scena banalissima.






Vado a letto.
Urgentemente.

Unità di misura

Periodo di cambiamento professionale, come accennato. Passaggi di consegne ed altre scocciature, il tempo per star dietro a Tau Ceti è e sarà poco, purtroppo. Oggi ad esempio in ufficio fino alle 22
Ma non mi pagano per sviluppare videogames quindi pazienza :)
Nel tempo che riesco a ritagliarmi comunque le cose vanno avanti. Una volta riuscito a visualizzare oggetti dotati di texture e propriamente illuminati, è arrivato il tempo di dedicarsi all'unita' di misura.
Directx, come le altre librerie, definiscono un mondo virtuale, dotato ovviamente di un sistema di coordinate, che e' privo di unità di misura. Posso disegnare una sfera alle coordinate (1,2,3), ma non c'e' scritto da nessuna parte che quel punto vada inteso come 1,2,3 millimetri o anni luce.
Va quindi definita una scala, devo decidere quel (1,2,3) come va inteso.
Per decidere ho scelto il nostro sistema solare come riferimento.
La distanza tra il Sole e Plutone è di quasi 40 unità astronomiche.
1 au = 149 597 870,691 chilometri.
Potrei prendere quindi l'au come scala, ma se questa va bene per rappresentare con numeri ragionevoli le distanze tra i pianeti, va molto meno bene per rappresentarne la dimensione.
Prendiamo ad esempio la terra. Ha un raggio di meno di 7.000 km, ovvero dovrei dire a directx di disegnarmi una sfera di raggio = 0,0000047 au, e in virgola mobile usare numeri così piccoli può essere pericoloso quando si devono fare operazioni di precisione, c'è il rischio che si verificano brutti errori di arrotondamento.
Del resto nemmeno utilizzare come unità di misura il kilometro pare essere una scelta azzeccata, visto che per il sole dovrei creare una sfera di raggio 70.000, per non parlare della posizione che avrebbe plutone, ovvero un punto avente come coordinate (5876560000,0,0).
Il compromesso che per ora ho trovato è quello di 1 directX = 10.000 km.
La terra ha raggio 0.7 circa, il sole 70, giove 7, e plutone sta a (587656,0,0), ancora parecchio, ma comunque una cifra che dovrebbe essere gestibile senza grossi problemi in float.
Semmai abbasso a 100.000 km, ma non credo vi sia la necessità.
Prima di concludere un'immagine, realizzata con la scala 10.000 km, che mette a confronto le dimensioni del sole con quelle di giove. Chiaramente per ora l'orbita è ancora del tutto inverosimile, ma le dimensioni dei due corpi celesti rispettano la realtà.
Ho aggiunto anche un abbondante dose di antialiasing, tanto a 800fps ancora me lo posso permettere :)

Thursday, January 10, 2008

Giove Pluvio


... con le texture, e' tutta un'altra cosa.

Il texture mapping, come per l'illuminazione, è implementato tramite shaders usando il linguaggio HLSL. Ringrazio un lettore per la texture di giove, che ho usato senza pensaarci due volte.
Non nascondo l'entusiasmo che ho per il risultato ottenuto, mi rendo conto che è ridicolo se confrontato a tanti altri giochi, ma parto da zero, fino a dicembre manco sapevo cosa fosse un device di directx, e mi piange il cuore sapere che molto probabilmente entro pochi giorni, causa lavoro, dovrò sospendere o comunque rallentare di molto quel che sto facendo. Ma era nelle regole del gioco, lo sapevo fin dall'inizio, e la soddisfazione comunque che ne ho ricevuto fino a qui non ha prezzo.
Comunque vada ne sarà valsa la pena, e per ora si prosegue

Wednesday, January 9, 2008

Luce


Dopo tanti screenshot, finalmente un piccolo video.
Niente di che, ma non è stato immediato. Si tratta di un test di illuminazione attraverso gli shader di directx, nello specifico si tratta di un modello di illuminazione che tiene conto della luce diffusa, di quella ambientale, dell'effetto speculare del materiale, della posizione della luce e del tipo di attenuazione che ha in base alla distanza dalla medesima.
Ci ho messo un bel pò perchè i parametri da passare agli shader son tanti e me ne ero dimenticato accidentalmente uno, col risultato che la luce pareva illuminare indistintamente tutti gli oggetti, indipendentemente da dove si trovassero, poi finalmente ho risolto l'arcano ed ora funziona. Il test mi è servito più che altro per verificare che il pianetino che orbita attorno alla stella presentasse sempre il lato illuminato in fronte al sole, cosa che come vedete funziona.
Mi sorprende che, a quanto pare (ma potrei sbagliarmi), per illuminare una mesh occorra scriversi a mano gli shaders corrispontenti, è senz'altro flessibile poter creare un qualsiasi modello, anziche' doversi accontentare dei soliti classici "luce puntuale", "cono di luce" ecc.. pero'.. che fatica!
Un chiarimento: l'orbita del pianetino sembra balorda, sembra che si muova a scatti, poi si ferma, poi accelera... in realta' l'orbita e' perfetta, solo che durante la ripresa ho manovrato anche la telecamera, spostandola e facendola a sua volta orbitare attorno al sole. La composizione delle due orbite genera il risultato bizzarro, che senz'altro non si noterà più non appena aggiungero' il background stellare che avete visto ieri.

Tuesday, January 8, 2008

Che ve ne pare?


Sarò breve stavolta.
Ho provato a mettere un background dietro al pianeta, e vi ho aggiunto una luna. Per ora niente textures o effetti particolari, ma comunque da una primissima idea dell'aspetto verso il quale mi sto dirigendo.
Che ve ne pare? Sono graditi commenti e suggerimenti.

Monday, January 7, 2008

Spazio




Oggi ho verificato che:





  1. La gestione del mouse è abbastanza semplice, nell'ottenere le coordinate x,y del puntatore, quello che invece è più problematico è la selezione di una stella. L'idea mia era di convertire le coordinate della stella da 3D a 2D, e confrontarle con quelle del mouse: se sono sufficientemente vicine, ed il tasto del mouse è premuto, allora la stella è stata selezionata. Il problema è che se una stella è decisamente vicina alla telecamera, apparirà molto grande, e in questo caso cosa vuol dire "sufficientemente vicina"? In teoria potrebbe essere grande quanto tutto lo schermo, e per assurdo clickando su un qualsiasi punto dovrei poterla selezionare. Credo si debba passare per directx e considerare lo sprite per quel che e': una coppia di triangoli, usando perciò la corrispondente tecnica per la selezione, che devo ancora studiarmi bene. Per il momento quindi lascio stare.
  2. La gestione di un'interfaccia utente la posso fare usando gli sprites. Insomma occorrono tutta una serie di bottoni per poter interagire con la mappa. Col mouse ruoto e seleziono, e al limite eseguo lo zoom, ma comunque occorreranno pulsanti per cercare un sistema, centrare la mappa, abilitare/disabilitare la stampa dei nomi dei sistemi ecc.. Ho fatto un paio di test ed i risultati sono incoraggianti: son riuscito a mixare 2D e 3D, definendo posizione degli sprites e profondita' dei medesimi (gli sprites sono davanti al 3D o dietro?).
Ho perciò deciso di passare finalmente alla "real thing", ovvero alla rappresentazione dello spazio. Che è un pò il cuore di tutto il gioco. Qui interviene finalmente il 3D solido, con tutte le sue implicazioni: textures, luci, shaders..
Per ora ho iniziato col rappresentare un pianetino, molto banale e senza dettagli, giusto per testare gli shaders che simulano la luce diffusa (nello spazio non c'è luce ambientale), e il risultato è quello che vedete illustrato.
Non è nulla di che, ma è finalmente la prima cosa "solida" che faccio apparire, meritava un post :)

Friday, January 4, 2008

Grandi pulizie...

...più o meno.

Ho dedicato la giornata di oggi alla razionalizzazione dei sorgenti; abituato come sono a Java, preferisco mantenere la filosofia "un file per classe", così almeno sono in grado di capire subito cosa contiene un file sorgente, e dove andare in cerca della classe x dopo una settimana di ferie e non ricordandomi più nemmeno come mi chiamo.
E così abbiamo Galaxy.cpp, Map.cpp, Planet.cpp, System.cpp e via discorrendo.
Andava fatto un robusto refactoring (purtroppo a mano, VC++ non è ahimè Netbeans..) di alcuni metodi che stavano proprio nella classe sbagliata: la parte di codice che disegna la mappa è giusto che stia in Map.cpp, non in Galaxy.cpp, tanto per dirne una. E se non sto attento rischio di generare un "mostro" che poi difficilmente avrò il tempo e la voglia di riordinare.
Così ho colto l'occasione per togliere parti di codice ormai obsolete, dare una nomenclatura alle variabili un pò più sensata, e con l'occasione ho pure scoperto un pò di strutture che rimanevano allocate anche dopo il termine del programma, prontamente corrette.
Non che ora si respiri aria di pulito, ma cose tipo

D3DVECTOR Pos;
Pos.x = s.coords.lyX+s.coords.sectorX*10;
Pos.y = s.coords.lyY;
Pos.z = s.coords.lyZ+s.coords.sectorZ*10;

HR(pSprite->Begin(D3DXSPRITE_OBJECTSPACE|D3DXSPRITE_DONOTMODIFY_RENDERSTATE));

D3DXMatrixTranslation(&T,Pos.x,Pos.y,Pos.z);

A=R*S*T;

HR(pSprite->SetTransform(&A));


almeno hanno un briciolo di dignità rispetto al caos che regnava prima.

Quindi nessuna novità di rilievo per il week end, tranne forse la gestione finalmente funzionante del full screen, in aggiunta alla modalita' window. Per scoprire tra l'altro che a 1440x900 gira con gli stessi identici FPS di una finestrella 800x600, a dimostrazione che l'overhead è per ora tutto a carico della CPU, nello specifico nel rendering dei nomi delle stelle: ancora non ho capito come mai si porti via tutto sto tempo, e se vi sia una strada alternativa per farla andare più veloce.
Ogni vostro suggerimento è ben accetto!

Una curiosita': l'eseguibile per ora occupa la "bellezza" di 56 kbytes (!), che aggiunto al singolo kilobyte dello sprite e a 2kb di un semplice shader che uso, porta il tutto a circa 60kb. Siamo a un decimo della dimensione di Frontier per Amiga, il quale fu scritto comunque in assembly (di sua natura più compatto del C++) e su un processore a 16 bit.
Messo per ora da parte l'intenzione di rendere più sofisticata la gestione dei nomi, e l'ottimizzazione negli FPS, il prossimo passo che voglio compiere è la gestione del mouse: per ora col tasto destro si ruota la mappa, e con la tastiera si alza/abbassa la telecamera. Ora manca il vero scopo della mappa, ovvero la selezione col tasto sinistro della stella di destinazione.
Un click sul pallino, e si sceglie la stella verso la quale si vuole dirigersi. Sembra facile ma c'e' di mezzo il solito problema della conversione da coordinate bidimensionali, a tridimensionali.
Il mouse infatti lavora su un piano, il puntatore idem, mentre le stelle hanno una dimensione in più. Che succede quindi se, ad esempio, a causa della particolare prospettiva selezionata con la telecamera, vado a clickare su una stella che ne nasconde un'altra? Entrambe anno la stessa posizione sullo schermo, quando seleziono una con il mouse, in realta' quali delle due devo considerare?
Ne parliamo la prossima volta, buon week-end.

Thursday, January 3, 2008

Dannato billboarding

Innanzitutto buon anno a tutti: non so quante sono le persone che leggono, ma mi fa piacere sapere che c'è chi si prende persino la briga di leggere le porcherie che scrivo, quindi grazie e auguri :)
Per l'anno nuovo l'augurio impossibile è quello di finire questo progetto: impossibile non perchè non lo voglia, anzi, ma perchè dubito durerà a lungo ancora questo particolare momento che mi permette di dedicarmi a Tau Ceti. Senz'altro prima o poi sarò costretto ad altre attività che mi lasceranno ben poco tempo, e addio sviluppo (o arrivederci!). Per ora colgo l'attimo e vado avanti, vedremo fin dove arriverò, certo se si riuscisse a valicare il traguardo beh...

Ma basta coi sogni, oggi son diventato isterico, nel cercare di implementare una realizzazione decente del billboarding, ovvero di quella tecnica che permette di far apparire un oggetto bidimensionale come fosse tridimensionale.
Le stelle della mappa infatti sono realizzate con degli sprite, ovvero con dei disegni 2D che vengono aggiunti all'ambiente 3D. Non avessi scelto questa strada avrei dovuto realizzare, per ciascuna stella, una piccola sfera, e 150 stelle, moltiplicate per il numero dei triangoli necessari a realizzare una (seppur grezza) sfera, mi son sembrati uno spreco eccessivo per una mappa.
Molto più economico disegnare un cerchio pieno con Paint Shop Pro, salvarlo in png, e disegnare quello al posto della sfera.
Il problema di questa soluzione è che fino a quando la telecamera riprende l'oggetto frontalmente l'illusione funziona, ma non appena cominciamo a ruotarla per andare magari a vedere cosa c'è "dietro", ci si accorge subito che l'oggetto è piatto, per l'appunto bidimensionale.
Questa immagine è un esempio di come il trucco sia esteticamente orribile.
Come risolvere? Il modo migliore è quello di mantenere gli sprites sempre orientati verso la telecamera, un pò come se fossero dei girasoli: se ruoto la telecamera, si ruota anche lo sprite, in modo che in qualsiasi posizione io mi trova, sia in grado di vederlo sempre perfettamente circolare.
Non entro nei meandri matematici della faccenda, dico solo che, come segnalatomi da un gentile utente su usenet, esiste una funzione delle direcxt che fa proprio al caso mio.
E in effetti la cosa funzionava.. se non fosse che come effetto collaterale avevo che le stelle, più lontane erano dall'origine, e più risultavano traslate dal "bastoncino" che le regge.
Ho passato 4 ore buone a cercar di capire cosa andava, facendo tutte le permutazioni possibili nella moltiplicazione delle matrici di roto-scala-traslazione, ma niente.
Alla fine disperato, notando che vi era una componente di traslazione aggiuntiva in seguito alla rotazione correttiva, ho provato ad azzerarla brutalmente.
Magia, miracolo, funziona.

Quattro ore per:

R._41=0;
R._42=0;
R._43=0;





Bastava solo questo.
Vado a farmi un caffè e a piangere.

Ancora buon anno.