03 Basi del Rendering

Nell'articolo precedente abbiamo discusso di come inizializzare Direct3D – come creare un oggetto Device. Non abbiamo mai parlato di codice però, che è poi la parte più divertente. In queste sede, parleremo delle basi del processo di rendering, includendo anche come porre l'assoluta base di una scena 3D: pulire lo schermo.

Ricordiamo il game loop. Ecco qui il codice:

static void Main() { Game app = new Game(); app.InitializeGraphics(); app.Show(); while (app.Created) { app.Render(); Application.DoEvents(); } app.DisposeGraphics(); }

Analiziamo la chiamata dell'applicazione a Render. Questo è il metodo che noi richimiamo per fare una scena 3D. Andando al sodo, ha bisogno di fare cinque cose:

1. Cancellare il back buffer. 2. Avvisare Direct3D che tutto è pronto per il disegno. 3. Disegnare la scena. 4. Indicare a Direct3D che abbiamo disegnato tutto. 5. Copiare il back buffer sullo schermo.

Parleremo di tutto a parte lo step 3. Il disegno di forme che comporanno una scena richiedono conoscenze del "VertexBuffers"" e dei sistemi di coordinate, quindi ne parleremo in seguito. Ma anche gli altri quattro passi sono fondamentali. Qui il codice che li imp'lementa:

protected void Render() { // Clear the back buffer device.Clear(ClearFlags.Target, Color.Black, 1.0F, 0); // Ready Direct3D to begin drawing device.BeginScene(); // Draw the scene - 3D Rendering calls go here // Indicate to Direct3D that we’re done drawing device.EndScene(); // Copy the back buffer to the display device.Present(); }

Step 1 – Cancellare il back buffer.

Quando si parla di grafica bisogna considerare l'enorme mole di lavoro che la CPU o la scehda video deve sopportare.

Per questa ragione, Direct3D ci da la possibilità di fare uso del back buffer. Semplicemente, questa è una regione su cui andiamoa disegnare, invece che direttamente sullo schermo. Questo ci permette di evitare l'invio di una miriade di informazioni attraverso il bus AGP o PCI alla scheda video. Così, semplicemente scriviamo in memoria, e poi tutto l'intero frame sulla scheda. Molto più efficiente.

Naturalmente, prima di scrivere sul back buffer, non è una cattiva idea cancellarlo, cosi da non avere residui della scena precedente. La chiamata è la seguente:

device.Clear(ClearFlags.Target, Color.Black, 1.0F, 0);

Nota che la chiamata si riferisce all'oggetto creato con la InitializeGraphics.

Il primo argomento dice a Direct3D cosa stiamo cancellando. Ci sono diverse opzioni,ma per il nostro semplice esempio noi siamo interessati a cancellare il back buffer, così passiamo ClearFlags.Target per indicare che stiamo cancellare l'obbiettivo del nostro rendering.

Il secondo parametro dice a Direct3D con che colore cancellare la superficie. Nota che stiamo usando un vaolore enumerato System.Drawing.Color – una delle cose carine che DirectX ci dà è l'abilità di lavorare con tipi familiari, inoltre può essere possibile in taluni casi usare interi per indicare colori.

Degli ultimi due argomenti ne parleremo in dettaglio in seguito. Settati a 1.0F e 0 andranno bene.

Step 2 - Avvisare Direct3D che tutto è pronto per il disegno.

Dobbiamo avvisare Direct3D sul fatto che tutto è pronto per essere disegnato. Questo è molto semplice - prende una sola linea di codice:

device.BeginScene();

Se stai cominciando a pensare che Direct3D ha un sacco di metodi nell'oggetto Device, hai ragione. Questa sorta di programmazione a “variabili globali” mi mise in guardia inzialmente – pensavo di trovare chiamate tipo Scene.Begin() invece che device.BeginScene() – ma ci ho fatto presto l'abitudine.

Step 3 - Disegnare la scena.

Questo è quello che ci serve per disegnare gli oggetti veri e propri sullo schermo: razzi, armi, sfere, piramidi, quello che è. Ancora una volta ripeto, saltiamo questa parte perchè molte cose dobbiamo ancora studiarle, ma niente paura ci arriveremo presto.

Step 4 - Indicare a Direct3D che abbiamo disegnato tutto.

Questa è facile. E' come la BeginScene, con una chiamata a EndScene, risolviamo:

device.EndScene();

Proprio come BeginScene, questa dice a Direct3D di incrementare alcune strutture interne.

Step 5 - Copiare il back buffer sullo schermo.

Questa è la paga per il nostro lavoro. L'unica cosa che in effetti produce qualche cosa di pratico: Chiamando

device.Present();

stiamo dicendo a Direct3D di prendere il backbuffer ed eventualmente darlo alla scheda grafica, where it will be shown on the monitor. Ho detto "eventualmente" perchè potremmo voler ritardare lo scambio di informazioni tra backebuffer e scheda per qualunque ragione, oppure migliorare la qualità delle nostre animazioni.

Per lo scopo del nostro semplice programma, possiamo pensare riguardo a Present come la cosa tramite cui si mette sullo schermo quello che abbiamo disegnato.

Ed ecco fatto! – una vera applicazione Direct3D! Ammettiamolo, disegna solo uno sfondo nero, ma è così efficiente nel farlo!

In coda tutto il codice completo relativo a questo articolo. Nel prossimo articolo, parleremo dei VertexBuffers, fondamentali per disegnare qualcosa di interessante sullo schermo.

The Code

using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace Craig.Direct3D { public class Game : System.Windows.Forms.Form { private Device device; static void Main() { Game app = new Game(); app.InitializeGraphics(); app.Show(); while (app.Created) { app.Render(); Application.DoEvents(); } app.DisposeGraphics(); } protected bool InitializeGraphics() { PresentParameters pres = new PresentParameters(); pres.Windowed = true; pres.SwapEffect = SwapEffect.Discard; device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, pres); return true; } protected void Render() { // Sets the surface to black everywhere device.Clear(ClearFlags.Target, Color.Black, 1.0F, 0); device.BeginScene(); // 3D Rendering calls go here device.EndScene(); device.Present(); } protected void DisposeGraphics() { device.Dispose(); } } }