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]