Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 51 di 53
  • livello principiante
Indice lezioni

Dual texturing

Applicare due texture allo stesso oggetto combinando la texture del colore con effetti di illuminazione
Applicare due texture allo stesso oggetto combinando la texture del colore con effetti di illuminazione
Link copiato negli appunti

Come abbiamo visto nelle lezioni sulla gestione della telecamera, sappiamo che gli effects contenuti nelle mesh di un modello non sono necessariamente dei BasicEffect. Possiamo infatti decidere quali effetti includere nel modello utilizzando le impostazioni del progetto Content associate al modello stesso.

Figura 07. Decidere quale effetto usare
(clic per ingrandire)


Decidere quale effetto usare

In questa lezione familiarizzeremo con il DualTextureEffect, un effetto molto semplice ma al tempo stesso molto potente che consente di applicare due textures differenti allo stesso modello. In genere, questo effetto è utilizzato per realizzare effetti di illuminazione "precalcolati" (e dunque decisamente più leggeri rispetto ad effetti in real time), ma al tempo stesso di grande impatto visivo.

Questo risultato è ottenuto combinando la texture che rappresenta il colore effettivo del modello, con una seconda texture che riproduce l'effetto dell'illuminazione precalcolata staticamente (usando algoritmi come radiosity, ad esempio) dall'editor con cui è stato realizzato il modello (es. Cinema 4D, Maya, 3D Studio Max, ecc.). Non solo, ma cambiando le texture di illuminazione durante il gioco, possiamo ottenere effetti "semi-dinamici" con un risparmio in termini di performance tutt'altro che secondario (soprattutto se sviluppiamo per Windows Phone).

Disegno con dual texturing

Per prima cosa, come sempre carichiamo il nostro modello in memoria, assieme alla texture che useremo come lightmap più avanti:

model = Game.Content.Load<Model>("model");
lightMap = Game.Content.Load<Texture2D>("lightmap");

Adesso iteriamo attraverso le meshes e gli effetti del modello. Per ciascuno di questi effetti, carichiamo una texture che contenga la mappa di illuminazione appropriata (ottenuta tramite il cosiddetto texture baking, ossia la tecnica di "registrare" in un'immagine 2D differenti effetti creati su una superficie 3D dall'illuminazione):

foreach (var mesh in model.Meshes)
{
  foreach (DualTextureEffect fx in mesh.Effects)
  {
    fx.Texture2 = lightMap;
  }
}

Nota: Come abbiamo già sottolineato nel parlando dei Modelli di base, il ciclo foreach più interno funziona solo a patto che, nel modello, ciascuna mesh sia effettivamente associata a un DualTextureEffect (in caso contrario aspettiamoci una bella eccezione a runtime). La semplificazione del codice, anche in questo caso, è dettata da motivi puramente illustrativi.

Si noti come la classe DualTextureEffect esponga due proprietà, Texture e Texture2, corrispondenti, rispettivamente, alla texture contenente le informazioni sul colore delle mesh (detta anche base texture) e alla mappa di illuminazione (detta anche overlay texture).

Per poter osservare meglio gli effetti di illuminazione sull'oggetto 3D, useremo come base texture un'immagine neutrale, di colore grigio, realizzata in questo modo:

grey = new Texture2D(GraphicsDevice, 1, 1);
grey.SetData(new Color[] { new Color(128, 128, 128, 255) });

Per prima cosa, abbiamo inizializzato la nostra texture grey passando come parametri di overload il GraphicsDevice corrente e le dimensioni della texture (nel nostro caso 1 pixel x 1 pixel). Con il metodo SetData, infine, abbiamo effettivamente colorato la nostra texture con un colore grigio pieno.

Una volta preparata la texture di base, applichiamola alle nostre meshes aggiungendo la seguente riga in grassetto:

foreach (var mesh in model.Meshes)
{
  foreach (DualTextureEffect fx in mesh.Effects)
  {
    fx.Texture = grey;
    fx.Texture2 = lightMap;
  }
}

A questo punto carichiamo le informazioni sulle bones del modello in un apposito array e procediamo al disegno del modello iterando manualmente attraverso le meshes e i relativi DualTextureEffect, come abbiamo già visto parlando dei modelli di base.

Ricordiamoci inoltre di impostare le nostre matrici World, View e Projection (anche in questo caso ci siamo presi la libertà di impostarle nel metodo Draw, per sole finalità illustrative). Ecco come dovrebbe apparire il nostro metodo Draw:

Matrix rotation = Matrix.CreateRotationY(MathHelper.ToRadians(124.0f)) * Matrix.CreateRotationZ(MathHelper.ToRadians(-12.0f));
Matrix view = Matrix.CreateLookAt(new Vector3(35, 13, 0), new Vector3(0, 3, 0), Vector3.Up);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 2, 100);
Matrix[] transforms = new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(transforms);
foreach (ModelMesh mesh in model.Meshes)
{
  foreach (DualTextureEffect effect in mesh.Effects)
  {
    Matrix world = transforms[mesh.ParentBone.Index];
    effect.World = world;
    effect.View = view;
    effect.Projection = projection;
    effect.Texture = grey;
    effect.Texture2 = lightMap;
  }
  mesh.Draw();
}

Ecco come si dovrebbe vedere il nostro modello una volta attivate entrambe le texture (di base e di illuminazione):

Figura 08. Entrambe le texture attive
(clic per ingrandire)


Entrambe le texture attive

Nella figura seguente vediamo invece come appare lo stesso modello se non attiviamo la lightmap, ma solo la texture base:

Figura 09. Nessuna lightmap attiva
(clic per ingrandire)


Nessuna lightmap attiva

Non è certo un granché. Infine, vediamo come appare lo screenshot del gioco se, invece di utilizzare una texture grigia, lasciamo la texture di default del modello:

Figura 10. Texture originale e lightmap attivo
(clic per ingrandire)


Texture originale e lightmap attivo

Ti consigliamo anche