scarica il seguente tutorial in formato PDF
Transcript
scarica il seguente tutorial in formato PDF
IRRLICHT GUIDE - TUTORIAL 4- Illuminazione Tutorial by Santostefano “Blizzard” Giovanni contact: [email protected] NEL SEGUENTE TUTORIAL POTETE TROVARE ERRORI DI CASE SENSITIVITY NELLA SCRITTURA DELLE FUNZIONI AD ESEMPIO clearzBuffer sarebbe clearZBuffer. QUESTO PERCHE' IL PROGRAMMA DI VIDEOSCRITTURA CORREGGE A VOLTE AUTOMATICAMETNE. VISIONATE QUINDI I SORGENTI ALLEGATI PER LA PRECISIONE Irrlicht realtime 3d engine è un motore grafico sviluppato da Nikolaus Gebhardt e dalla crescente community che orbita attorno a questo stupendo progetto open source. PREMESSA Salve, vi ricordate di me? (domanda d'obbligo, dato che non vedete miei tutorial da un bel po di tempo). Riprendiamo il nostro piccolo discorso sull'irrlicht parlando questa volta dell'illuminazione della scena. Il processo di lighting è una cosa molto importante nell'industria videoludica e se non altro è uno dei punti di forza del fotorealismo dei motori grafici. In questo tutorial esploreremo il sistema di illuminazione fornito dall'irrlicht, scoprendo come può essere utilizzato all'interno del vostro codice. Classi, metodi e membri da descrivere sono davvero pochi, pertanto non avrete di fronte a voi un megatutorial... ^_^ PROCESSI DI ILLUMINAZIONE Credo che la maggior parte delle persone che stia leggendo questo articolo è a conoscenza del fatto che l'illuminazione di un poligono è un processo che avviene via hardware(riferendosi al gergo della computer grafica), ovvero gestito da un hardware dedicato allo scopo: nel nostro caso la scheda video. Tuttavia, originariamente la computazione dell'illuminazione di ogni singolo poligono veniva effettuata via software, un'operazione molto esosa per i gia lenti processori di un tempo (il riferimento temporale è prima dell'uscita dei primi accelleratori grafici). L'illuminazione in generale si divide in due categorie principali: • Per vertex lighting (pvl) • Per pixel lighting (ppl) La prima categoria è stata utilizzata sin dagli albori della computer grafica 3d, in quanto è un processo di illuminazione molto veloce, poiché è calcolata per ogni singolo vertice. Calcolare la luminosità di un vertice è in qualche modo come modificarne il colore originale(scurendolo o schiarendolo). L'illuminazione per vertice è molto approssimativa e nell'industria videoludica è stata sempre utilizzata solo per oggetti animati o comunque non statici. Per gli oggetti statici infatti si utilizzano le cosiddette lightmaps che sono texture che contengono luci ed ombre precalcolate maniera molto accurata; queste poi vengono blendate con la texture del materiale per creare un falso effetto luce statico(ma molto bello da vedere). Il secondo tipo di lighting (per pixel) è un sistema relativamente nuovo e nasce e si sviluppa di pari passo con lo sviluppo degli shader. Il sistema di illuminazione per pixel, calcola un valore di luminosità per ogni singolo pixel del poligono, aumentando di molto l'accuratezza dell'illuminazione. Irrlicht implementa entrambi i tipi. Tuttavia la ppl è disponibile solo con lo shader del normal mapping e quindi non è legata al normale utilizzo del motore che a livello di classi fornisce supporto per la sola illuminazione al vertice. Pertanto è la pvl che descriveremo. IRRLICHT LIGHTING Una luce in irrlicht (dal punto di vista implementativo) non è nient'altro che un nodo della scena, pertanto gode delle proprietà di questi ultimi, come ad esempio valori posizionali ecc... e inoltre ha delle proprietà proprie. Ad esempio: state costruendo un giochetto alla Morrowind (non diciamo oblivion va! ) e state programmando l'effetto del vostro tizio che raccoglie una torcia del muro. Quando portate con voi la torcia, questa deve illuminare l'ambiente circostante... niente di più semplice! basta che sul bastone della torcia attacchiate la luce e il gioco è fatto, dato che la luce sarà posizionata sempre sul bastone bastone->addChild(light); Le luci calcolate in fixed pipeline sono generalmente 3: • Omni Light • Directonal Light • Spot Light Irrlicht implementa solo la omni e la directional light. La spot light ovvero la luce tipo torcia elettrica (un cono di luce proiettato in una direzione) non è implemetata. La omni invece è una luce che si muove in tutte le direzioni, praticamente si sviluppa in una sfera. La direzionale è invece una luce senza attenuazione (praticamente infinita) che si muove in una sola direzione (un'ottima simulazione della luce solare!). Per creare una luce, utilizziamo ovviamente un metodo implemetato nello scene manager... e catturiamo il puntatore che questo metodo restituisce in un ILightSceneNode*. Quindi creiamo il nostro nodo definiamo prima un puntatore: ILightSceneNode* light; Poi invochiamo il metodo dello scene manager virtual ILightSceneNode* addLightSceneNode(ISceneNode* parent = 0, const core::vector3df& position = core::vector3df(0,0,0), video::SColorf color = video::SColorf(1.0f, 1.0f, 1.0f), f32 radius=100.0f, s32 id=-1) = 0; Parent al solito è il nodo genitore nell'albero della scena. Position è la posizione della luce. Color è il colore della radiazione diffusa della luce. Radius è il raggio della sfera che segna l'area illuminata. ID è il classico identificatore del nodo(se fate qualche query) light->addLightSceneNode(0, core::vector3df(0,100,0), video::Scolorf(1.0f,0.0f,0.0f), 200.0f,1); Questa riga crea una luce in posizione 0,100,0 ovvero sopra la nostra testa, di colore rosso (1,0,0)(r,g,b) di raggio 200 e con ID 1. Tuttavia vi avevo specificato di 2 tipi di luce... in questo caso abbiamo creato una luce omnidirezionale... ma quella direzionale? Per fare questo dobbiamo accedere alla struttura dati che descrive la luce. La struttura SLight.h . dati è una struct SLight, definita nel file Definiamo quindi un reference a questa struttura: video::SLight& ldata; Ora utilizziamo ILightSceneNode un metodo descritto nell'interfaccia di classe virtual video::SLight& getLightData() = 0; questo restituisce appunto un istanza di questa struttura dati riferimento(reference) ad una ldata = light->getLightData(); Da qui è possibile editare tutti i parametri della luce. //! Ambient color emitted by the light SColorf AmbientColor; //! Diffuse color emitted by the light. /** This is the primary color you might want to set. */ SColorf DiffuseColor; //! Specular color emitted by the light. /** For details how to use specular highlights, see SMaterial::Shininess */ SColorf SpecularColor; Ovviamente la radiazione ambient, che sarebbe il colore che c'è anche in assenza di luce. Quella diffusa ovvero il colore che emana la luce e quella speculare, ovvero il colore di riflesso della luce. //! Position of the light. If Type is ELT_DIRECTIONAL, this is the direction vector the light is coming from. core::vector3df Position; Position è la posizione della luce omnidirezionale oppure l'angolo della luce direzionale. L'angolo della luce direzionale 1è il versore di propagazione della luce1. In pratica dovete passare il vettore direzione (lo ritroveremo nella gravità). Per esempio position=core::vector3df(0.0f,1.0f,0.0f); imposta una luce direzionale per puntare in alto verso il soffitto. //! Radius of light. Everything within this radius be be lighted. f32 Radius; Radius è il raggio di azione di una luce omnidirezionale. Nella 1 Ringrazio Mobius per la correzione effettuata rispetto alla precedente versione direzionale che è infinita ovviamente non vale... //! Does the light cast shadows? bool CastShadows; Un booleano per decidere se la luce deve castare ombre (true) oppure no (false). Le ombre sono un argomento molto avanzato, quindi non ne parleremo in questo tutorial. //! Type of the light. Default: ELT_POINT E_LIGHT_TYPE Type; L'ultimo parametro è un istanza della enum valere: E_LIGHT_TYPE e può //! Enumeration for different types of lights enum E_LIGHT_TYPE { //! point light, it has a position in space and radiates light in all directions ELT_POINT, }; //! directional light, coming from a direction from an infinite distance ELT_DIRECTIONAL ELT_POINT è puntiforme). la luce omnidirezionale (ovvero emettitore ELT_DIRECTIONAL è la luce direzionale. Vediamo ora un esempio su come settare una luce direzionale video::SLight& ldata; ldata = light->getLightData(); ldata.Type = ELT_DIRECTIONAL; ldata.Position = core::vector3df(0,-1,0); Questa luce direzionale punta al pavimento ovvero perfettamente in basso. Vediamo lo stesso esempio con un puntatore, se siete poco pratici dei reference video::SLight* ldata; ldata = &light->getLightData(); ldata->Type = ELT_DIRECTIONAL; ldata->Position = core::vector3df(0,-1,0); Per vedere infine l'illuminazione sui vostri nodi, accertatevi di eseguire queste poche operazioni: node->setMaterialFlag(video::EMF_LIGHTING, true); Abilita l'illuminazione del nodo node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); Se scalate il nodo questo flag abiliterà il motore a rinormalizzare le normali dei poligoni in modo da evitare errori di calcolo della luce. CONCLUSIONE Siamo giunti alla fine di questo quarto appuntamento. Nei prossimi tutorial si intodurranno i materiali e i colori che completeranno l'utilizzo dell'illuminazione real time. Se al momento magari non ottenete i risultati che sperate pertanto attendere il tutorial sui materiali. Come sempre, se ho commesso errori concettuali, di trattazione o di codice, fatemelo sapere così da rendere sempre migliori i tutorial scrivo. Grazie per la lettura e arrivederci alla prossima puntata. Santostefano “Blizzard” Giovanni contact: [email protected]