Visualizzazione post con etichetta OpenGL. Mostra tutti i post
Visualizzazione post con etichetta OpenGL. Mostra tutti i post

venerdì 4 febbraio 2011

OpenGL SecondProject - Texture sui modelli!

Vedere una casa tutta bianca e senza luci né ombre è certo un bel passo in avanti, ma ad ogni passo ne deve seguire un altro. Per questo ho dato ai modelli le loro texture. Anzi la loro texture. Sì, perchè un modello tridimensionale per coprirsi di colore può usare o più file o uno solo, equivalente ai "più file" opportunamente ruotati per stare tutti in un'unica immagine, e per ora ho dato ad ogni modello solo una texture.
Sono partito con l'idea di usare tutte le texture, per dare la possibilitá a modelli con texture multiple di entrare nel mondo in construzione, ma sono incappato in un problema: in un 3ds, da quello che vedo grazie alla libreria lib3ds, per ogni mesh sono elencati in array tutti i vertici e tutti i triangoli, ognuno con i 3 indici dei vertici che lo compongono e l'indice del materiale di cui è fatto. Ogni materiale ha 2 texture, e tante altre cose, come normalMaps, ecc. Le informazioni sulla posizione della texture per i vertici cono messe in un bell'array di coppie UV, il che mi fa pensare che vi sia una coppia UV per ogni vertice, peccato che se così fosse potrebbe funzionare solo con una sola texture poichè, in caso di texture multiple, ad un vertice dovrebbero corrispondere diverse coordinate UV a seconda di quale triangolo si sta considerando. Ho cercato un po' online, ma non ho trovato gran che (se qualcuno avesse trovato qualcosa mi farebbe un favore facendomelo sapere :D), così ho deciso di caricare solo la texture del primo materiale che incontro e di usarla per tutto il modello. Che poi pensandoci bene avere una texture sola per un singolo modello dovrebbe aumentare le prestazioni rispetto a dover caricare più texture. Certo si perde il vantaggio di poter riusare texture base per comporre texture più complesse (ad esempio una texture per il cemento usata su diversi modelli di edificio), ma si può ovviare a questo creando asset componibili, ovvero non modellare un edificio intero, ma le sue parti separatamente, il che porta anche il vantaggio del riutilizzo dei modelli oltre che delle texture.

Usando solo la prima texture i modelli con più texture appaiono corretti solo nelle parti originariamente coperte dalla texture usata.

il modello della casa dovrebe avere anche altre texture...

Mentre modelli con una sola texture appaiono corretti al cento percento!

il modell del carretto ha una sola texture, quindi è visualizzato correttamente

Implementando questa nuova caratteristica di base ho anche introdotto un gestore di texture, ceh permette di non caricare più volte una stessa texture. Ho scelto di implementarlo con metodi statici, invece di ricorrere ad una variabile globale, ma si può sempre cambiare.

Per caricare le texture dei modelli nella loro cartella ho incluso la libreria Boost FileSystem, perfettamente portabile, per poter usare la cartella del modello come base per il path della sua texture.

Dovrò poi capire come usare normal-maps, reflection-maps e compagnia bella.
Per qualsiasi cosa commentate!

lunedì 31 gennaio 2011

Imparando OpenGL: OpenGL SecondProject has begun

Come saprete "da grande" voglio programmare videogiochi (sì, proprio tutto :D), quindi, dopo aver terminato il corso di grafica, riprendo a giochicchiare con OpenGL, ma adesso più consapevole e più seriamente. Ho deciso di postare i miei progressi (fiducioso che ce ne saranno :) ), poiché visto che ho perso un sacco di tempo a cercare cose online magari sarò utile a qualcun altro.

Per prima cosa ho scaricato il sorgente di Lugaru (gran gioco, lo consiglio) e ci ho dato una letta: "OMG complesso! Iniziamo con calma..".

Prima di iniziare a scrivere codice: installare svn e creare un repository. Pensavo fosse complicato, ma non c'è da fare quasi nulla, visto anche che NetBeans dialoga volentieri con svn :). Sapendone poco o nulla ho cercato un tutorial: html.it aiuta sempre. Per non usare il terminale (a parte per la creazione che è una riga) ho installato le GUI che ho trovato nelle repository di Ubuntu: RapidSVN e esvn (optando poi per RapidSVN).
Usare un programma di VersionControl è una buona prassi quando si creano progetti medio grandi: mi evita di fare tanti zip con tutto il progetto dentro e mi permette di avere uno storico delle modifiche dettalgiato e di poter tornare ad una versione precedente con semplicità.

Come prima cosa ho scritto le solite classi Vec3 e Vec2 (credo si capisca cosa sono, ma non si sa mai: rispettivamete vettore tridimensionale(XYZ) e vettore bidimensionale(XY)) con tutti i metodi che ho potuto immaginare. In uno spazio 3D non possono mancare le rotazioni. Come si effettuano le rotazioni in 3D? O con matrici o con quaternioni. La differenza? I quaternioni sono composti da 4 variabili, mentre una matrice ne ha 16, e per i calcoli è più semplice (leggi con meno errori numerici) e veloce; difatti in computer grafica si usano quasi sempre i quaternioni (attenzione perchè per effettuare trasformazioni generiche vengono usate le matrici, vedi OpenGL, quindi è bene implementare anche loro). Unico problema: mai usati quaternioni. Ero abbastanza fuso e abbattuto, dopo aver tentato di capire come usarli leggendo un po' di roba su wikipedia e varie google ricerche, quando la salvezza mi si carica in una tab di Chrome: il codice con un poco di spiegazione di una classe Quaternions sulla GameProgramming Wiki!
Amore per la wiki <3.
Dopo 4 classi matematiche (ho scritto anche Matrix4) c'è bisogno di vedere dei risultati per tirare su il morale. Ancora una, dai forza: Camera. Per poter esplorare un mondo 3D serve un occhio! La visuale in OpenGL è gestita con una matrice di trasformazione che viene applicata ai vertici per il rendering: un po' complicato da gestire, quindi serve un wrapper! Una bella classe Camera con tutti i suoi bei metodi per muoverla, impostarla e applicarla in OpenGL. Riporto gli header:
class Camera
{
public:
    Vec3 pos;
    Vec3 target;
    Vec3 vertical;
    virtual void setGLCamera(void)=0;
    Camera(void);
};

class PerspectiveCamera : public Camera
{
protected:

public:
    double near, far;
    double width, height;
    Vec2 vanishingPoint; // 0.0 - 1.0
    double FOV;
    double ratio;
    PerspectiveCamera(void);
    void setGLCamera(void);
    void setFOV(double FOV);
    void setAspectRatio(double ratio);
    void setVanishingPoint(Vec2 vp);
    void setNear(double near);
    void setFar(double far);
    Vec3 getDirection(void);
    void moveX(double deltax);
    void moveY(double deltay);
    void moveZ(double deltaz);
    void move(Vec3 v);
    void rotateX(double alphax);
    void rotateY(double alphay);
};
Ho fatto una classe Camera e una sua estensione PerspectiveCamera per non precludermi altri tipi di visuale, come la proiezione ortogonale o la isometrica. La classe madre ha solo una classe virtuale, ma nel caso ne metterò altre, come move* ad esempio (che sarebbe da mettere...).
Per applicare la camera prospettica alle OpenGL uso due funzioni: glLookAt per posizionarla e gñFrustum per impostarne le caratteristiche.
void PerspectiveCamera::setGLCamera()
{
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(pos.x, pos.y, pos.z, target.x, target.y, target.z, vertical.x, vertical.y, vertical.z);
    glMatrixMode(GL_PROJECTION);
    glFrustum(-vanishingPoint.x*width, (1-vanishingPoint.x)*width, -vanishingPoint.y*height, (1-vanishingPoint.y)*height, near, far);
}

Attenzione al rapporto che ci dev'essere tra FOV, near e width:
void PerspectiveCamera::setFOV(double FOV)
{
    this->FOV = FOV;
    this->width = near*tan(DEG2RAD(FOV/2.0))*2.0;
    this->height = width/ratio;
}
(ovviamente questa relazione si vede anche in tutti metodi che modificano near o width)

Oh, finalmente si possono vedere dei risultati!
Imposto un main con GLUT e grazie alla presenza di un buon wrapper con tanti utili metodi voillà: una telecamera in prima persona!

Ringraziamo GLUT e diciamogli addio. Sì, perchè GLUT è una libreria tanto utile e semplice da usare, ma non è pensata per videogiochi: dobbiamo passare a SDL!
Come OpenGL, SDL è una libreria gratuita, aperta e multipiattaforma. Permette di comunicare con i vari dispositivi di input, come mouse, tastiera e pad, con l'eventuale gestore di finestre, e ci dà una mano in altri vari campi. Rispetto a GLUT è meno specifica e più versatile: c'è da scrivere di più, ma il gioco vale la candela.
Per usare SDL con OpenGL in C++ ci sono vari tutorial segnalati sul sito ufficiale. Io ho usato questo di Cone3d e vari dal sito SDLtutorials.com, grazie ai quali ho scritto una classe per gestire i vari input e una per le finestre. Per quanto riguarda gli input più in là credo che proverò l'ottimizzazione di Game Programmer.

prima visione: 2 quadrati


Che bello: posso esplorare il mio mondo 3D! Due quadrati... un po' vuoto no? Prima di andare avanti con la grafica bisogna mettersi nelle condizioni di poter testare il lavoro: caricare modelli 3d.
Dando un'occhiata al codice di David (il genio che ha scritto Lugaru) apprendo che usa il formato .solid, credo fatto da lui ma non ne ho la certezza, e che lo legge e parsa direttamente, senza usare librerie esterne. Io preferisco usare un formato diffuso per semplificare la vita ai modellatori (quindi a me :D) e a me che dovrei scrivere tool e plug-in di conversione. Mi metto a esplorare il mondo dei formati per modelli tridimensionali. Ero alla ricerca di un formato aperto e usato da programmi gratuiti come blender, una sorta di standard creato dal mondo Open, come esiste l'OpenDocumentper i documenti, ma sono rimasto deluso e a bocca asciutta. Blender ha un suo formato, il .blend, ma sembra lo usi solo lui e mi sembrava complicato. Cercando guide trovo che alcuni usano formati creati per i vari Quake Engine, altri il .obj, ma la maggior parte usa il 3ds, il formato di 3dStudioMax, programma di modellazione 3d professionale (avete presente cose come Shrek?) la cui ultima versione ora costa 3945$. Ok che potrei scaricarlo gratuitamente con licenza studente (grazie AutoDesk :) ), ma non tutti possono, ok che molti usano copie pirata, ma è una cosa cattiva e, per fortuna, non tutti rubano, e ok che molti software ne supportano l'import/export (no, non si parla di commercio...), ma io volevo qualcosa di più libero, quindi ho tentennato. Dopo un po' mi sono arreso e mi sono deciso per il 3ds. Non rimaneva che trovare una libreria gratuita e usabile commercialmente per gestirlo: ahahah! T_T Altro tempo lanciato nel vuoto alla ricerca dell'arcana libreria. Ho trovato due librerie in licenza LGPL: C3ds, di un italiano, e lib3ds. Dopo averle lette e valutate entrambe ho scelto la seconda perchè mi ci son trovato subito meglio.
Così, predendo conoscenza importante dal codice di Lugaru, ho scritto la classe Model, con il suo bel metodo load, che sfrutta lib3ds per caricare il suo modello e convertirlo in vertici e triangoli. Per ora non ho messo l'uso di texture, normali e mappature varie, ma di certo lo metterò.
A dire il vero prima di preoccuparmi del codice mi sono messo a cercare qualche modello in LGPL da usare come test: altre risatone! È quasi impossibile! Si trovano modelli gratuiti ma nessuno permette l'uso commerciale! Ho trovato solo qualcosa su TurboSquid, un sito che vende modelli 3d, ma ha anche qualcosa gratis. Prima di scaricarne anche solo uno, anche solo per usarlo come test, ho cercato di capire se la licenza permetteva l'uso commerciale: nelle FAQ, presenti anche in italiano, si parla della licenza per modelli comprati, ma credo che i modelli gratuiti si "comprino" a 0€. Si scaricano con licenza lì detta Standard Royalty Free. Se qualcuno sa o crede che mi sbagli al riguardo me lo faccia sapere, grazie :D.
I modelli gratis lì presenti non sono moltissimi, in più io cercavo qualcosa di medioevale, però qualcosa ho trovato.
Ecco l'immagine del primo modello nel mondo virtuale del mio progetto!

il primo modello


Ora dovrò aggiungere un po' di luce per raccapezzarsi meglio, e tutto il resto :D
Per qualsiasi domanda o osservazione, commentate!
Al prossimo post!
Related Posts Plugin for WordPress, Blogger...