<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE document PUBLIC "-//CNX//DTD CNXML 0.5 plus MathML//EN" "http://cnx.rice.edu/cnxml/0.5/DTD/cnxml_mathml.dtd">
<document xmlns="http://cnx.rice.edu/cnxml" xmlns:md="http://cnx.rice.edu/mdml/0.4" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:bib="http://bibtexml.sf.net/" id="None">
  <name>Composizione Grafica in Processing</name>
  <metadata>
  <md:version>1.12</md:version>
  <md:created>2005/02/15 03:16:36 US/Central</md:created>
  <md:revised>2006/11/13 02:39:12.136 US/Central</md:revised>
  <md:authorlist>
      <md:author id="drocchesso">
      <md:firstname>Davide</md:firstname>
      
      <md:surname>Rocchesso</md:surname>
      <md:email>Davide.Rocchesso@univr.it</md:email>
    </md:author>
  </md:authorlist>

  <md:maintainerlist>
    <md:maintainer id="drocchesso">
      <md:firstname>Davide</md:firstname>
      
      <md:surname>Rocchesso</md:surname>
      <md:email>Davide.Rocchesso@univr.it</md:email>
    </md:maintainer>
  </md:maintainerlist>
  
  <md:keywordlist>
    <md:keyword>2D graphics</md:keyword>
    <md:keyword>3D graphics</md:keyword>
    <md:keyword>curves</md:keyword>
  </md:keywordlist>

  <md:abstract>Elementi di composizione grafica 2D e 3D (curve incluse) per l'ambiente e linguaggio Processing</md:abstract>
</metadata>

  <content>
    <section id="primitive_grafiche">
      <name>Primitive grafiche</name>
      <para id="primp">
	In Processing si possono disporre punti, linee, superfici, e
      volumi (cioè oggetti geometrici a 0, 1, 2, o 3 dimensioni) in
      uno spazio tridimensionale ovvero, laddove la cosa abbia un
      senso, nello spazio bidimensionale della finestra immagine. Il
      numero di parametri delle primitive corrispondenti determinerà
      se tali oggetti debbano essere collocati nello spazio X-Y o
      nello spazio X-Y-Z. </para>
      <section id="zeroD">
	<name>0D</name> 
	<para id="punti"><name>Punti</name>
	La <code>point()</code> è la più semplice
	delle primitive grafiche. Se invocata con due coordinate,
	colloca un punto nello spazio X-Y. Se invocata con tre
	coordinate, colloca il punto nello spazio X-Y-Z. Un punto, in
	senso geometrico, non ha dimensione, ma ad esso può essere
	associata una occupazione in pixel ed un colore, mediante le
	funzioni <code>strokeWeight()</code> e <code>stroke()</code>,
	rispettivamente. Ad esempio, il semplicissimo sketch Processing
	<code type="block">
	  stroke(180,0,0);
	  strokeWeight(10);
	  point(60,60);
	</code>
	disegna un pallino nella finestra immagine. 
	</para>
	<para id="collezioni_punti"><name>Collezioni di punti</name>
	  Un insieme di punti può essere raggruppato in un unico
	  oggetto (nuvola di punti) mediante i due delimitatori
	  <code>beginShape(POINTS)</code> e <code>endShape()</code>,
	  tra i quali ogni punto va specificato con la funzione
	  <code>vertex()</code>. Trasformazioni di rotazione,
	  traslazione, o scalamento non si applicano internamente agli
	  oggetti compositi descritti da <code>beginShape()</code> e
	  <code>endShape()</code>, ma possono precedere la definizione
	  di un composito e applicarsi all'insieme.
	</para>
      </section>
      <section id="unoD">
	<name>1D</name> 
	<para id="rette"><name>Rette</name> La
	<code>line()</code> traccia un segmento di retta tra due punti
	del piano o dello spazio, con spessore e colore eventualmente
	impostati tramite <code>strokeWeight()</code> e
	<code>stroke()</code>, rispettivamente.
	</para>
	<para id="collezioni_segmenti"><name>Collezioni di
	segmenti</name> Un insieme di segmenti può essere definito,
	analogamente a quanto visto per i punti, mediante i
	delimitatori <code>beginShape()</code> e
	<code>endShape()</code>, tra i quali si elencano gli estremi
	dei segmenti mediante la funzione <code>vertex()</code>. Usando
	la invocazione <code>beginShape(LINES)</code> i vertici vengono
	presi a coppie, ciascuna identificante un segmento, mentre con
	la invocazione <code>beginShape(LINE_STRIP)</code> i vertici,
	presi uno dopo l'altro, definiscono una spezzata. Con
	l'invocazione <code>beginShape(LINE_LOOP)</code> la spezzata
	viene chiusa su se stessa mediante collegamento del primo e
	dell'ultimo vertice. Notare che il poligono così ottenuto non
	può essere manipolato, ad esempio mediante coloratura.
	</para>
	<para id="curve"><name>Curve</name> La funzione
	<code>curve()</code>, invocata con otto parametri, traccia una
	curva sul piano immagine, con punto iniziale e finale
	determinati, rispettivamente, dalle seconda e dalla terza
	coppia di coordinate passate come argomenti. Le due coppie di
	coordinate iniziale e finale definiscono due punti di
	controllo della curva tracciata, la quale è una spline
	interpolante, e quindi passa per tutti e quattro i punti.
	<definition id="spline">
	  <term>Spline</term> <meaning>Curva polinomiale a tratti, con
	  polinomi connessi con continuità ai nodi
	  (<emphasis>knot</emphasis>)<note>Si veda <cnxn document="m11153">Introduction to Splines</cnxn> e, per una
	  introduzione al tipo specifico di spline (Catmull-Rom) usato
	  in processing, la voce <term src="http://en.wikipedia.org/wiki/Spline_%28mathematics%29">
	  spline </term> in Wikipedia.</note></meaning>
	</definition>
	  Per avere un numero arbitrario di punti di controllo bisogna
	  usare la funzione <code>curveVertex()</code> per specificare
	  ciascun punto all'interno di un blocco delimitato da
	  <code>beginShape(LINE_STRIP)</code> e
	  <code>endShape()</code>.  
	</para>
	<para id="bezier"> 
	  A differenza della
	  <code>curve()</code>, nella funzione <code>bezier()</code> i
	  due punti di controllo specificati dai quattro parametri
	  intermedi non sono punti attraversati dalla curva. Essi
	  servono solo a definire la forma della  <term src="http://en.wikipedia.org/wiki/B%e9zier_curve">curva approssimante
	  di Bézier</term>,
	  la quale ha le seguenti proprietà notevoli:
	  <list id="proprieta_bezier">
	    <item>è interamente contenuta nell'inviluppo convesso
	    definito dai punti estremali e dai punti di
	    controllo;</item> <item>trasformazioni di traslazione,
	    rotazione, o scalamento applicate ai punti estremali e di
	    controllo determinano una identica trasformazione della
	    curva.</item>
	  </list>
	  Come si vede eseguendo il codice
	<code type="block">
	    stroke(255, 0, 0); 
	    line(93, 40, 10, 10); 
	    line(90, 90, 15, 80); 
	    stroke(0, 0, 0); 
	    bezier(93, 40, 10, 10, 90, 90, 15, 80);
	</code>
	  i punti di controllo stanno sulla tangente che passa per gli
	  estremi della curva.  Per avere un numero arbitrario di
	  punti di controllo bisogna usare la funzione
	  <code>bezierVertex()</code> per specificare ciascun punto
	  all'interno di un blocco delimitato da
	  <code>beginShape(LINE_STRIP)</code> e
	  <code>endShape()</code>. In questo modo si può tracciare una
	  curva arbitrariamente involuta in uno spazio a tre
	  dimensioni. In due dimensioni, la
	  <code>bezierVertex()</code> ha sei parametri che
	  corrispondono alle coordinate di due punti di controllo e di
	  un punto di ancoraggio. La prima invocazione di
	  <code>bezierVertex()</code> va preceduta da una invocazione
	  di <code>vertex()</code> che stabilisce il primo punto di
	  ancoraggio della curva.
	</para>
	<para id="extracurvep">
	  Ci sono ulteriori metodi che consentono di leggere le
	    coordinate o la direzione della tangente in un punto
	    qualsiasi lungo la curva di Bézier o spline interpolante,
	    stabilito mediante un parametro <m:math> <m:ci>t</m:ci>
	    </m:math> che può andare da <m:math> <m:mn>0</m:mn>
	    </m:math> (primo estremo) a <m:math> <m:mn>1</m:mn>
	    </m:math> (secondo estremo). E' anche possibile impostare
	    la precisione di tracciamento di curve approssimanti e
	    interpolanti in 3D. Per i dettagli si rimanda al <link src="http://www.processing.org/reference/index_ext.html">manuale
	    di riferimento</link> di Processing.
	</para>
	<para id="beziercurve">
	  Lo sketch processing <cnxn target="bezier_curve_table"> di tabella </cnxn> illustra la
	  differenza tra curva interpolante spline e curva di
	  Bézier<note>Si veda la voce <term src="http://en.wikipedia.org/wiki/B%e9zier_curve">Bézier
	  curve</term> in Wikipedia.</note>.
	    <table id="bezier_curve_table" frame="all">
	      <tgroup cols="2" align="left" colsep="1" rowsep="1">
		<colspec colname="col1" colnum="1" colwidth="50"/>
		<colspec colname="col2" colnum="2" colwidth="300"/>
		<tbody>
		  <row>
		    <entry>
		      <link src="bezier_curve.html">applet che
confronta curva di Bézier (rossa) e spline interpolante (nera) </link>
		    </entry>
		    <entry>
	    <code type="block">
          <![CDATA[  
                
void setup() {
  c1x = 120;
  c1y = 110;
  c2x = 50;
  c2y = 70;
  background(200);
  stroke(0,0,0);
  size(200, 200);
}

int D1, D2;
int X, Y;
int c1x, c1y, c2x, c2y;

void draw() {
  if (mousePressed == true) {
    X = mouseX; Y = mouseY;
    // selezione del punto che si modifica
    D1 = (X - c1x)*(X - c1x) + (Y - c1y)*(Y - c1y); 
    D2 = (X - c2x)*(X - c2x) + (Y - c2y)*(Y - c2y);
    if (D1 < D2) {
    c1x = X; c1y = Y;
    }
    else {
     c2x = X; c2y = Y;
     }
    }
    background(200);
    stroke(0,0,0);
    strokeWeight(1);
    
    beginShape(LINE_STRIP); 
    curveVertex(10,  10); 
    curveVertex(10,  10); 
    curveVertex(c2x, c2y); 
    curveVertex(c1x, c1y); 
    curveVertex(190, 190); 
    curveVertex(190, 190); 
    endShape(); 
       
    stroke(255,30,0);
    bezier(10,10,c2x,c2y,c1x,c1y,190,190);
    strokeWeight(4);
    point(c1x,c1y);
    point(c2x,c2y);
}
                   ]]>	      
	    </code>
		    </entry>
		  </row>
		</tbody>
	      </tgroup>
	    </table>
  	</para>
     </section>
      <section id="dueD">
	<name>2D</name> 
	<note>Le figure in due o tre
	dimensioni assumono un colore che può essere determinato dalla
	illuminazione, come spiegato nella <cnxn target="illuminazione"/>, oppure stabilito mediante il metodo
	<code>fill()</code>, il quale prevede anche la possibilità di
	impostare la trasparenza.</note>

	<para id="triangoli"><name>Triangoli</name> Il triangolo è
	l'elemento costruttivo fondamentale per la grafica 3D, in
	quanto mediante giustapposizione di triangoli si approssimano
	superfici continue. In Processing, però, i triangoli sono
	elementi specificati nel 2D mediante la primitiva
	<code>triangle()</code>, la quale ha sei parametri
	corrispondenti alle coordinate dei tre vertici nella finestra
	immagine. Pur essendo definito nel 2D, ogni triangolo può
	essere soggetto a trasformazioni di rotazione e traslazione
	all'interno dello spazio 3D, come avviene nello sketch
	Processing 
	<code type="block"> 
	void setup(){ 
	    size(200, 200, P3D); 
	    fill(210, 20, 20);
	    }

	float angle = 0;

	void draw(){
	    background(200); // clear image
	    stroke(0,0,0);
	    angle += 0.005;
	    rotateX(angle);
	    triangle(10,10,30,70,80,80);
	}	    

	</code>
	</para>
	<para id="collezioni_triangoli"><name>Collezioni di
	triangoli</name> Un insieme di triangoli può essere definito,
	analogamente a quanto visto per i punti e segmenti, mediante i
	delimitatori <code>beginShape()</code> e
	<code>endShape()</code>, tra i quali si elencano i vertici dei
	triangoli mediante la funzione <code>vertex()</code>. Usando
	la invocazione <code>beginShape(TRIANGLES)</code> i vertici
	vengono presi a terne, ciascuna identificante un triangolo,
	mentre con la invocazione
	<code>beginShape(TRIANGLE_STRIP)</code> i vertici, presi uno
	dopo l'altro, definiscono una striscia di superficie a facce
	triangolari. Se le <code>vertex()</code> hanno tre argomenti,
	i vertici vengono collocati nello spazio 3D e i corrispondenti
	triangoli individuano superfici planari nello spazio.
	</para>
	<para id="quadrilateri"><name>Quadrilateri</name> I rettangoli
	  si definiscono, in Processing, mediante la funzione
	  <code>rect()</code> di quattro parametri, in cui i primi due
	  specificano, per default, la posizione nel piano 2D
	  dell'angolo in alto a sinistra, e il terzo e quarto
	  specificano, rispettivamente, la larghezza e la altezza. Il
	  significato dei primi due parametri si può cambiare con la
	  funzione <code>rectMode()</code>:
	  <code>rectMode(CORNER)</code> corrisponde al posizionamento
	  di default; <code>rectMode(CENTER)</code>
	  corrisponde al posizionamento del centro del rettangolo nel
	  punto specificato dalle prime due coordinate;
	  <code>rectMode(CORNERS)</code> fa in modo che i quattro
	  parametri vengano interpretati come le coordinate del
	  vertice in alto a sinistra e del vertice in basso a destra. 

	  Un quadrilatero generico si definisce mediante le coordinate
	  dei suoi quattro vertici, passate come parametri alla
	  funzione <code>quad()</code>.

	  E' importante notare che in 3D, mentre un triangolo rimane
	  in ogni caso planare, una quadrupla di punti può dare luogo
	  ad una superficie curva. Viceversa, i quadrilateri definiti
	  mediante roto-traslazioni 3D di quadruple di vertici 2D
	  rimangono planari. Processing permette di passare solo otto
	  parametri alla <code>quad()</code>, in tal modo forzando la
	  definizione del quadrilatero mediante una quadrupla di
	  vertici 2D.
	</para>
	<para id="collezioni_quadrilateri"><name>Collezioni di
	quadrilateri</name> Un insieme di quadrilateri può essere
	definito, analogamente a quanto visto per i triangoli,
	mediante i delimitatori <code>beginShape()</code> e
	<code>endShape()</code>, tra i quali si elencano i vertici dei
	quadrilateri mediante la funzione
	<code>vertex()</code>. Usando la invocazione
	<code>beginShape(QUADS)</code> i vertici vengono presi a
	quadruple, ciascuna identificante un quadrilatero, mentre con
	la invocazione <code>beginShape(QUAD_STRIP)</code> i vertici,
	presi uno dopo l'altro, definiscono una striscia di superficie
	a facce quadrilatere. Se i <code> vertex()</code> usati hanno
	tre parametri, non è garantita la planarità delle facce
	risultanti, e quindi la resa grafica può essere fuorviante. Ad esempio, eseguendo il codice
	  <code type="block">
	    size(200,200,P3D);
	    lights();
	    beginShape(QUADS);
	    vertex(20,31, 33);
	    vertex(80, 40, 38);
	    vertex(75, 88, 50);
	    vertex(49, 85, 74);
	    endShape();
	  </code>
	  ci si rende conto che il quadrilatero viene reso come
	  giustapposizione di due triangoli giacenti su piani diversi.
	</para>
	<para id="poligoni"><name>Poligoni</name> Un poligono generico
	è definito da una successione di vertici, ed è un oggetto
	dotato di una superficie che può essere colorata. In
	Processing tali vertici si elencano dentro a una coppia
	<code>beginShape(POLYGON);</code> - <code>endShape();</code>
	In realtà il poligono è da intendersi in senso
	generalizzato, essendo possibile usare le
	<code>bezierVertex()</code> e <code>curveVertex()</code> per
	specificare profili curvi. Ad esempio, si provi a disegnare la
	luna:
	  <code type="block">
	    fill(246, 168, 20);
	    beginShape(POLYGON); 
	    vertex(30, 20); 
	    bezierVertex(80, 10, 80, 75, 30, 75); 
	    bezierVertex(50, 70, 60, 25, 30, 20); 
	    endShape(); 
	  </code>
	</para>

	<para id="ellissi"><name>Ellissi</name> La funzione
	<code>ellipse()</code> traccia una ellisse nel piano 2D. I
	quattro parametri sono interpretati, come nel caso della
	<code>rect()</code>, come posizione seguita da larghezza e
	altezza. La posizione può essere regolata mediante la chiamata
	<code>ellipseMode()</code>, il cui parametro può assumere
	valori <code>CORNER, CORNERS,
	CENTER, CENTER_RADIUS</code>. I primi due di questi
	quattro possibili valori vanno riferiti al rettangolo
	circoscritto alla ellisse. </para>
      </section>
      <section id="treD">
	<name>3D</name> <para id="intro3D">Processing offre un
	repertorio assai limitato di primitive di oggetti
	tridimensionali, essenzialmente solo sfere e
	parallelepipedi.</para> <para id="scatole"><name>Scatole</name> La funzione
	<code>box()</code> produce un cubo se invocata con un solo
	parametro (lato), un parallelepipedo se invocata con tre
	parametri (larghezza, altezza, profondità).  </para> <para id="palle"><name>Palle</name> La funzione
	<code>sphere()</code> produce, mediante un poliedro
	approssimante, una sfera il cui raggio è specificato come
	parametro. La funzione <code>sphereDetail()</code> può essere
	usata per specificare il numero di vertici del poliedro che
	approssima la sfera ideale.</para>
      </section>
    </section>
    <section id="stack">
      <name>Lo stack delle trasformazioni</name>
      <para id="stackp">
	Una rotazione o una traslazione possono essere pensate come
      operazioni che ruotano o traslano il sistema di riferimento
      cartesiano. In altri termini, dopo una <code>rotate()</code> o
      una <code>translate()</code> le successive operazioni di
      posizionamento di oggetti grafici avranno un nuovo sistema di
      assi coordinati. Quando si posizionano diversi oggetti in vario
      modo nello spazio, è utile tenere traccia dei diversi sistemi di
      assi coordinati che via via si vanno ad impostare. La struttura
      dati atta a contenere tali sistemi è il cosiddetto stack (o
      pila) delle trasformazioni (<emphasis>matrix
      stack</emphasis>). Con la funzione <code>pushMatrix()</code> il
      sistema di coordinate corrente viene impilato in testa allo
      stack. Invece, per recuperare il sistema di coordinate
      precedente alla ultima trasformazione operata, bisogna operare
      una <code>popMatrix()</code>. Di fatto, lo stack contiene le matrici
      di trasformazione affine, secondo quanto prescritto da <term src="http://www.opengl.org">OpenGL</term> e descritto in <cnxn target="pillole_di_opengl"/>.
  </para>
      <example id="stack_example">
	<para id="stack_exp">
In questo esempio vengono collocati due oggetti, uno quadrato planare
	ed un cubo, nello spazio 3D. Il primo <code>push()</code>
	salva sullo stack il sistema di coordinate, quindi vengono
	applicate alcune trasformazioni che precedono il disegno del
	quadrato. Per tornare al sistema di coordinate precedente, e
	quindi operare nuove trasformazioni per collocare il cubo, si
	applica una <code>popMatrix()</code>. Di fatto, le
	<code>pushMatrix()</code> e <code>popMatrix()</code> delimitano lo scope
	relativo al posizionamento geometrico di un oggetto.
 </para> 
	<code type="block">float angle;

	void setup(){
          size(100, 100, P3D); 
	  angle = 0;
	}

	void draw(){
	  background(200);
	  angle += 0.003;
	  pushMatrix();
	  translate(25,50);
	  rotateZ(angle);
	  rotateY(angle);
	  rectMode(CENTER);
	  rect(0,0,20,20);
	  popMatrix();
	  translate(75,50,-25);
	  rotateX(angle);
	  box(20);
	}

	</code>
      </example>
 
    </section>
    <section id="illuminazione">
      <name>Illuminazione</name> <para id="lucip"> Il modello di
      illuminazione di Processing ricalca direttamente quello di <term src="http://www.opengl.org">OpenGL</term>, cioè lo <term src="http://en.wikipedia.org/wiki/Phong_shading">shading di
      Phong</term>.  Tale modello non è giustificato fisicamente, ma è
      particolarmente efficiente. OpenGL considera illuminato ogni
      poligono la cui normale forma un angolo acuto con la direzione
      di provenienza della luce. Questo a prescindere dalla presenza
      di oggetti mascheranti, e quindi le ombre non vengono rese. Si
      dice che OpenGL adotta un modello locale di illuminazione, in
      quanto le riflessioni multiple tra le superfici e le proiezioni
      di ombre non vengono automaticamente elaborate.
      </para>
      <para id="types_of_light">E' disponibile una sorgente di luce di
      ambiente, cioè non proveniente da alcuna direzione particolare,
      il cui colore viene specificato mediante i parametri della
      chiamata di attivazione <code>ambientLight()</code>. Una
      sorgente di luce direzionale viene impostata con
      <code>directionalLight()</code>, i cui parametri specificano
      colore e direzione di provenienza. Il metodo
      <code>lights()</code> attiva una combinazione di default di luce
      ambientale grigia e luce direzionale, anch'essa grigia,
      proveniente dalla direzione frontale. E' possibile impostare una
      sorgente luminosa puntiforme in una data posizione dello spazio,
      mediante la chiamata <code>pointLight()</code>. Infine, il
      metodo <code>spotLight()</code> attiva un fascio di luce di cui,
      oltre a colore, posizione e direzione di irraggiamento, è
      possibile controllare l'apertura dell'angolo e la concentrazione
      intorno all'asse, mediante l'esponente <m:math> <m:ci>e</m:ci>
	</m:math>
	che regola la rapidità di decadimento all'allontanarsi
	dall'asse: 
	<equation id="apertura">
	  <m:math>
	  <m:apply>
	    <m:power/>
	    <m:apply>
	      <m:cos/>
	      <m:ci>φ</m:ci>
	    </m:apply>
	    <m:ci>e</m:ci>
	  </m:apply>
	</m:math>
	</equation>
      </para>
      <para id="riflessioni">
	Considerata una superficie piana, una luce direzionale che
      incida su di essa produce luce riflessa secondo varie direzioni,
      in maniera dipendente dalle proprietà superficiali. Nel caso di
      riflessione perfettamente diffusiva (o
      <term>lambertiana</term>), l'irraggiamento è prodotto in tutte
      le direzioni allo stesso modo, con una intensità tanto maggiore
      quanto più la direzione di incidenza è vicina alla direzione
      ortogonale (o normale) alla superficie. Viceversa, se la
      superficie è perfettamente riflettente, la luce viene riflessa
      solo lungo la direzione simmetrica, rispetto alla normale, alla
      direzione di incidenza. In OpenGL, per avere la massima
      flessibilità nella definizione della illuminazione, ogni
      sorgente racchiude in sé le tre componenti di illuminazione
      ambientale, lambertiana, e speculare. Queste tre componenti sono
      definibili separatamente, e interagiscono con le rispettive tre
      componenti che definiscono le proprietà superficiali degli
      oggetti. I colori definiti nei parametri dei metodi
      <code>directionalLight()</code>, <code>pointLight</code>, e
      <code>spotLight()</code> definiscono la componente lambertiana
      di illuminazione.  La <code>lightSpecular()</code> specifica il
      colore della componente di luce incidente che viene trattata con
      riflessione speculare. </para>
      <para id="materiali">
	In Processing è possibile controllare le proprietà delle
      superfici mediante i metodi <code>ambient()</code> (che agisce
      sulla componente ambientale di luce) e <code>specular()</code>
      (che agisce sulla componente speculare). Quest'ultimo metodo
      prevede anche la possibilità di specificare, mediante un
      parametro <code>alpha</code>, se la superficie debba essere di
      tipo traslucido. La <code>shininess()</code> controlla la
      concentrazione del fascio riflesso specularmente, mediante un
      coefficiente che agisce in modo analogo all'esponente della
      <cnxn target="apertura"/>. Gli oggetti rappresentati possono
      anche essere considerati sorgenti di luce, e quindi si può
      assegnare loro una luce di emissione, mediante la
      <code>emmissive()</code>. Tuttavia, le sorgenti definite in
      questo modo non producono illuminazione sugli altri oggetti
      della scena.
      </para>
      <para id="decadimento">In OpenGL, le luci puntiformi, a spot, e ambientali subiscono una attenuazione dipendente dalla distanza, secondo il modello 
	<equation id="attenuazione">
	  <m:math>
	  <m:apply>
	    <m:eq/>
	    <m:ci>attenuation</m:ci>
	    <m:apply>
	      <m:divide/>
	      <m:mn>1</m:mn>
	      <m:apply>
		<m:plus/>
		<m:ci>a</m:ci>
		<m:apply>
		  <m:times/>
		  <m:ci>b</m:ci>
		  <m:ci>d</m:ci>
		</m:apply>
		<m:apply>
		  <m:times/>
		  <m:ci>c</m:ci>
		  <m:apply>
		    <m:power/>
		    <m:ci>d</m:ci>
		    <m:mn>2</m:mn>
		  </m:apply>
		</m:apply>
	      </m:apply>
	    </m:apply>
	  </m:apply>
	</m:math>
	</equation>  Il metodo <code>ligthFalloff()</code> consente di
	specificare i parametri <m:math> <m:ci>a</m:ci> </m:math>,
	<m:math> <m:ci>b</m:ci> </m:math>, and <m:math> <m:ci>c</m:ci>
	</m:math>
</para>

      <example id="light_example">
	<para id="lightexp"> Qui un cubo e una <code>QUAD_STRIP</code>
	vengono collocati nello spazio ed illuminati da una sorgente
	rotante. Inoltre, viene impostate una tenue luce fissa. Si
	noti l'assenza di ombre e la apparente planarità delle
	superfici della <code>QUAD_STRIP</code>. </para>
	<code type="block">
import processing.opengl.*;

float r;
float lightX, lightY, lightZ;

void setup() {
  size(400, 400, OPENGL);
  r = 0;
  ambient(180, 90, 0);
  specular(0, 0, 240, 0.99);
  lightSpecular(200, 200, 200);   
  shininess(5);
}
  
void draw() {
  lightX = 100*sin(r/3) + width/2;
  lightY = 100*cos(r/3) + height/2;
  lightZ = 100*cos(r);
  background(0,0,0);
  noStroke(); 
  ambientLight(153, 102, 0);
  
  lightSpecular(0, 100, 200);
  pointLight(100, 180, 180, 
             lightX, lightY, lightZ);
  pushMatrix();
    translate(lightX, lightY, lightZ);
    emissive(100, 180, 180);
    sphere(4); //Put a little sphere where the light is
    emissive(0,0,0);
  popMatrix(); 
  pushMatrix();
    translate(width/2, height/2, 0);
    rotateX(PI/4);
    rotateY(PI/4); 
    box(100);
  popMatrix();
  pushMatrix();
    translate(width/4, height/2, 0);
    beginShape(QUAD_STRIP);
    vertex(10,13,8);
    vertex(13,90,13);
    vertex(65,76,44);
    vertex(95,106,44);
    vertex(97,20,70);
    vertex(109,70,80);
   endShape();
  popMatrix();
  r+=0.05;
}
	</code>
      </example>
    </section>

    <section id="projections">
      <name>Proiezioni</name>
      <section id="perspective_projection">
	<name>Proiezione prospettica</name> <para id="projectionp">Una
	proiezione prospettica è caratterizzata da un <term>centro di
	proiezione</term> e da un <term>piano di proiezione</term>. I
	<term>raggi proiettori</term> collegano i punti della scena
	con il centro di proiezione, individuando i corrispondenti
	punti proiettati sul piano di proiezione. La <cnxn target="projection2D"/> mostra una vista in sezione in cui il
	piano di proiezione è individuato da una retta di ascissa
	<m:math>
	    <m:apply>
	      <m:minus/>
	      <m:ci>d</m:ci>
	    </m:apply>
	  </m:math>, e il centro di proiezione è collocato
	  nell'origine. 
	  <figure id="projection2D">
	    <media type="image/png" src="perspective2D.png">
	    </media>
	  </figure>
	  Mediante similitudine dei due triangoli rettangoli, è facile
	    rendersi conto che il punto di ordinata <m:math>
	    <m:ci>y</m:ci> </m:math> viene proiettato sul piano nel
	    punto di ordinata <m:math>
	    <m:apply>
	      <m:eq/>
	    <m:msub>
	      <m:mi>y</m:mi>
	      <m:mn>p</m:mn>
	    </m:msub>
	      <m:apply>
		<m:minus/>
	      <m:apply>
		<m:divide/>
		<m:apply>
		  <m:times/>
		  <m:ci>y</m:ci>
		  <m:ci>d</m:ci>
		</m:apply>
		<m:ci>z</m:ci>
	      </m:apply>
	    </m:apply>
	      </m:apply>
	  </m:math>.
	</para>
	<para id="projection3Dp">
	  Più in generale, la proiezione di un punto di coordinate omogenee 	<m:math>
	  <m:vector>
	    <m:ci>x</m:ci>
	    <m:ci>y</m:ci>
	    <m:ci>z</m:ci>
	    <m:cn>1</m:cn>
	  </m:vector>
	</m:math>
	  su un piano perpendicolare all'asse <m:math>
	    <m:ci>z</m:ci>
	  </m:math> e secante tale asse in posizione <m:math>
	    <m:apply>
	      <m:minus/>
	      <m:ci>d</m:ci>
	    </m:apply>
	  </m:math> si effettua, in coordinate omogenee, per moltiplicazione con la matrice 
	  <m:math>
	    <m:matrix>
	      <m:matrixrow>
		<m:mn>1</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
	      </m:matrixrow>
	      <m:matrixrow>
		<m:mn>0</m:mn>
		<m:mn>1</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
	      </m:matrixrow>
	      <m:matrixrow>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>1</m:mn>
		<m:mn>0</m:mn>
	      </m:matrixrow>
	      <m:matrixrow>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		  <m:apply>
		    <m:minus/>
		  <m:apply>
		  <m:divide/>
		  <m:mn>1</m:mn>
		  <m:ci>d</m:ci>
		  </m:apply>
		  </m:apply>
		<m:mn>0</m:mn>
	      </m:matrixrow>
	    </m:matrix>
	  </m:math>. Il punto proiettato diventa 	<m:math>
	  <m:vector>
	    <m:ci>x</m:ci>
	    <m:ci>y</m:ci>
	    <m:ci>z</m:ci>
		  <m:apply>
		    <m:minus/>
		  <m:apply>
		  <m:divide/>
		  <m:ci>z</m:ci>
		  <m:ci>d</m:ci>
		  </m:apply>
		  </m:apply>
	  </m:vector>
	  </m:math>, il quale può essere normalizzato moltiplicando tutti i suoi elementi per <m:math>
		  <m:apply>
		    <m:minus/>
		  <m:apply>
		  <m:divide/>
		  <m:ci>d</m:ci>
		  <m:ci>z</m:ci>
		  </m:apply>
	      </m:apply>
	  </m:math>. Si ottiene quindi <m:math>
	  <m:vector>
	      <m:apply>
		<m:minus/>
	      <m:apply>
		<m:divide/>
		<m:apply>
		  <m:times/>
		  <m:ci>x</m:ci>
		  <m:ci>d</m:ci>
		</m:apply>
		<m:ci>z</m:ci>
	      </m:apply>
	      </m:apply>
	      <m:apply>
		<m:minus/>
	      <m:apply>
		<m:divide/>
		<m:apply>
		  <m:times/>
		  <m:ci>y</m:ci>
		  <m:ci>d</m:ci>
		</m:apply>
		<m:ci>z</m:ci>
	      </m:apply>
	      </m:apply>
	      <m:apply>
		<m:minus/>
	    <m:ci>d</m:ci>
	      </m:apply>
	    <m:mn>1</m:mn>
	  </m:vector>
	  </m:math>
	</para>
      </section>
      <section id="parallel_views">
	<name>Viste parallele</name>
	<para id="parallel_viewsp">
	  Le viste parallele sono quelle che si ottengono facendo
	    retrocedere a infinito (<m:math> <m:infinity/> </m:math>)
	    il centro di proiezione. In questo modo, i raggi
	    proiettori sono tutti paralleli.
	</para>
	<section id="orthographic_projection">
	  <name>Proiezione ortografica</name>
	  <para id="orthographic_projectionp">
	    La proiezione ortografica produce una classe di viste
	    parallele mediante conduzione di proiettori perpendicolari
	    al piano di proiezione.  Se il piano di proiezione viene
	    posto perpendicolare all'asse <m:math> <m:ci>z</m:ci>
	    </m:math> e passante per l'origine, la matrice di
	    proiezione risulta particolarmente semplice:
	  <m:math>
	    <m:matrix>
	      <m:matrixrow>
		<m:mn>1</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
	      </m:matrixrow>
	      <m:matrixrow>
		<m:mn>0</m:mn>
		<m:mn>1</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
	      </m:matrixrow>
	      <m:matrixrow>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
	      </m:matrixrow>
	      <m:matrixrow>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>1</m:mn>
	      </m:matrixrow>
	    </m:matrix>
	  </m:math>.  Tra le proiezioni ortografiche, le
	    <term>assonometrie</term> si basano sulla possibilità di
	    descrivere l'oggetto da proiettare secondo tre
	    <emphasis>assi</emphasis> ortogonali, e sull'orientazione
	    del piano di proiezione rispetto a questi assi. In
	    particolare la <link src="http://en.wikipedia.org/wiki/Isometric_projection">assonometria
	    isometrica</link> è tale che le proiezioni degli assi
	    formano tra loro angoli di <m:math>
	      <m:apply>
		<m:times/> <m:mn>120</m:mn>
	    <m:mi>°</m:mi> 
	      </m:apply>
	    </m:math>. Essa ha la
	    proprietà che lunghezze uguali lungo i tre assi rimangono
	    tra loro uguali lungo le proiezioni degli stessi.  Per
	    ottenere una assonometria isometrica di un oggetto i cui
	    assi principali sono inizialmente paralleli agli assi
	    coordinati, si può procedere mediante una prima rotazione
	    di <m:math>
	      <m:apply>
		<m:times/>
		<m:mn>45 </m:mn> <m:mi>°</m:mi> </m:apply>
		</m:math> intorno all'asse <m:math> <m:ci>y</m:ci>
		</m:math>, seguita da una seconda rotazione di
		<m:math>
	      <m:apply>
		<m:eq/>
		<m:apply>
		  <m:arctan/>
		  <m:apply>
		    <m:divide/>
		    <m:mn>1</m:mn>
		      <m:msqrt>
			<m:mn>2</m:mn>
		      </m:msqrt>
		  </m:apply>
		</m:apply>
		<m:apply>
		  <m:times/>
		<m:mn>35.264  </m:mn>
		<m:mi>°</m:mi>
		</m:apply>
	      </m:apply>
	    </m:math> intorno all'asse <m:math> <m:ci>x</m:ci>
	    </m:math>
	  </para>
<!--	  <para id="orthop">
	    In processing, gli oggetti della scena sono visualizzati
	    con una proiezione ortografica se viene invocata la
	    primitiva <link
	      src="http://www.processing.org/reference/ortho_.html"><code>ortho()</code></link>.
	  </para> -->
	</section>
	<section id="oblique_projection">
	  <name>Proiezione obliqua</name>
	  <para id="oblique_projectionp">
	    Si parla di proiezione obliqua ogniqualvolta il piano di
	    proiezione è obliquo (non perpendicolare) rispetto ai
	    raggi proiettori. Per introdurre una deviazione dei raggi
	    proiettori dalla perpendicolare secondo angoli <m:math>
	    <m:ci>θ</m:ci> </m:math> e <m:math>
	    <m:ci>φ</m:ci> </m:math> si deve usare una matrice di
	    proiezione
 <m:math>
	    <m:matrix>
	      <m:matrixrow>
		<m:mn>1</m:mn>
		<m:mn>0</m:mn>
		  <m:apply>
		    <m:minus/>
		    <m:apply>
		      <m:tan/>
		      <m:ci>θ</m:ci>
		    </m:apply>
		  </m:apply>
		<m:mn>0</m:mn>
	      </m:matrixrow>
	      <m:matrixrow>
		<m:mn>0</m:mn>
		<m:mn>1</m:mn>
		  <m:apply>
		    <m:minus/>
		    <m:apply>
		      <m:tan/>
		      <m:ci>φ</m:ci>
		    </m:apply>
		  </m:apply>
		<m:mn>0</m:mn>
	      </m:matrixrow>
	      <m:matrixrow>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
	      </m:matrixrow>
	      <m:matrixrow>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>0</m:mn>
		<m:mn>1</m:mn>
	      </m:matrixrow>
	    </m:matrix>
	  </m:math>
	  </para>
	</section>
      </section>
      <section id="shadow_casting">
	<name>Proiezione di ombre</name>
	<para id="shadow_castingp">
	  Come abbiamo visto, Processing offre un modello di
	  illuminazione locale, e quindi non è possibile proiettare
	  ombre (<term>shadow casting</term>) per via
	  diretta. Tuttavia, la manipolazione delle matrici di
	  trasformazione affine ci consente di proiettare abbastanza
	  agevolmente ombre su piani. La tecnica che si usa è detta
	  <term>flashing in the eye</term>, con questo termine
	  intendendo che si sposta il centro ottico della scena nel
	  punto in cui è collocata la sorgente luminosa, e si procede
	  con una trasformazione prospettica con piano di proiezione
	  coincidente con quello su cui si vuole proiettare l'ombra.
	</para>
	<example id="perspective_shadow">
	  <para id="perspective_shadowp">
	    Il codice seguente proietta sul pavimento l'ombra generata
	      da una sorgente di luce collocata sull'asse <m:math>
	      <m:ci>y</m:ci>
	    </m:math>. Il risultato è mostrato in <cnxn target="projectedShadow"/>
	 <figure id="projectedShadow">
	  <name>Proiezione di un'ombra</name>
	  <media type="image/png" src="projectedShadow.png">
	  </media>
	</figure>
	    <code type="block">
size(200, 200, P3D);
float centro = 100; 
float yp = 70; //distanza pavimento dal centro
float yl = 40; //altezza luce dal centro
translate(centro, centro, 0); //centra tutto sul cubo
noFill();
box(yp*2); //disegna la stanza
pushMatrix();
  fill(250); noStroke();
  translate(0, -yl, 0); // sposta in alto (rispetto al centro)
                        // la lampadina
  sphere(4); //disegna la lampadina;
  stroke(10);
popMatrix();
pushMatrix(); //disegna il cubo wireframe
  noFill();
  rotateY(PI/4); rotateX(PI/3);
  box(20);
popMatrix();
translate(0, -yl, 0); // riporta sorgente di luce e 
                      // pavimento al loro posto
applyMatrix(1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 1/(yp+yl), 0, 0); // proietta sul pavimento
                                 // spostato in basso di yl 
translate(0, yl, 0); // porta sorgente di luce al centro 
                     // e pavimento in basso di yl
pushMatrix();
  fill(120, 50);
  noStroke();
  rotateY(PI/4); rotateX(PI/3);
  box(20);
popMatrix(); 
	    </code>
	  </para>
	</example>
      </section>
    </section>
    <section id="pillole_di_opengl">
      <name>Pillole di OpenGL</name> <para id="openglp"> <term src="http://en.wikipedia.org/wiki/Opengl"> OpenGL</term> è un
      insieme di funzioni che consentono al programmatore di accedere
      al sistema grafico. In gergo tecnico è una <term src="http://en.wikipedia.org/wiki/API">Application Programming
      Interface (API)</term>. Principalmente essa si occupa della resa
      grafica (<emphasis>rendering</emphasis>) di una scena popolata
      di oggetti tridimensionali e luci, da un certo punto di
      vista. Per quanto riguarda il programmatore, OpenGL consente di
      descrivere oggetti geometrici ed alcune loro proprietà, nonché
      di stabilire come tali oggetti debbano essere illuminati e
      visti. Dal punto di vista realizzativo, OpenGL è basato su una
      <emphasis>pipeline </emphasis> grafica composta di moduli, come
      riportato in <cnxn target="pipelineOpenGL"/>.  Un ottimo
      libro di grafica interattiva in OpenGL è quello di <cite src="#Angel">Angel</cite>.
	<figure id="pipelineOpenGL">
	  <name>La pipeline di OpenGL</name>
	  <media type="image/png" src="pipelineOpenGL.png">
	  </media>
	</figure>
</para>

      <para id="coordinate_transp"> In Processing (ed in OpenGL),
	l'utente specifica gli oggetti mediante coordinate mondo
	(<emphasis>standard coordinates</emphasis>). La
	<emphasis>model-view matrix</emphasis> è la matrice di
	trasformazione usata per passare da coordinate mondo a uno
	spazio associato alla camera da presa. Ciò consente di
	cambiare dinamicamente il punto di vista e l'orientazione
	della camera. In OpenGL ciò avviene mediante la funzione
	<code>gluLookAt()</code>, la quale è riprodotta in Processing
	dalla <code>camera()</code>. I primi tre parametri
	identificano la posizione, in coordinate mondo, del centro
	ottico della camera (<term>eye point</term>). La seconda terna
	di parametri identifica un punto al quale è rivolta la camera
	(<term>center of the scene</term>). La terza terna di
	coordinate identifica un vettore atto a specificare la
	verticale di ripresa. Ad esempio, il codice
	<code type="block">
          <![CDATA[  
	void setup() {
           size(100, 100, P3D); 
           noFill(); 
           framerate(20);
        }

        void draw() {
           background(204); 
           camera(70.0, 35.0, 120.0, 50.0, 50.0, 0.0, 
             (float)mouseX /width, (float)mouseY /height, 0.0); 
           translate(50, 50, 0); 
           rotateX(-PI/6); 
           rotateY(PI/3); 
           box(45); 
        }
        ]]>
	</code>
        traccia il <term>wireframe</term> di un cubo e permette la
        rotazione della camera da presa.
	</para>
        <para id="proiezp">
	La <emphasis>projection matrix</emphasis> si occupa di fare la
	proiezione sulla finestra di vista, proiezione che può essere
	parallela (o ortografica) o prospettica. La proiezione
	ortografica si può attivare con la chiamata
	<code>ortho()</code>. La proiezione prospettica è quella di
	default, ma si può esplicitamente attivare con
	<code>perspective()</code>. Proiezioni particolari, quali
	quelle oblique, possono essere ottenute per distorsione degli
	oggetti mediante applicazione della
	<code>applyMatrix()</code>.  C'è inoltre la <emphasis>texture
	matrix</emphasis>, di cui ci si occupa in un altro modulo.
      </para>
<!--      <para id="colori_openglp">
	Nella rappresentazione interna degli oggetti della scena, i
	vertici hanno un colore associato. Il colore di una superficie
	delimitata da un insieme di vertici viene reso per
	interpolazione bilineare.
      </para> -->
      <para id="matrici_opengl">
	Per ogni tipo di matrice, OpenGL mantiene uno stack di
matrici, la matrice corrente essendo quella in cima. Il meccanismo
dello stack consente di salvare uno stato (mediante
<code>pushMatrix()</code>) prima di operare nuove trasformazioni, o di
rimuovere lo stato corrente evidenziando uno stato precedente
(mediante <code>popMatrix()</code>). Ciò si riflette nelle operazioni
Processing descritte in <cnxn target="stack"/>. Le trasformazioni in
OpenGL sono applicate secondo lo schema:
	<list id="operazioni_matricil" type="enumerated">
	  <item> Push sullo stack; </item> <item id="trasfid"> Applica
	    tutte le trasformazioni desiderate mediante
	    moltiplicazione con la matrice in cima allo stack; </item>
	    <item> Disegna l'oggetto (che risulterà affetto dalle trasformazioni);</item>
	    <item> Pop dallo stack.</item>
	</list>
      </para>
      <para id="modelviewp">
	Un <emphasis> viewport </emphasis> è un'area rettangolare
       della finestra di display. Il passaggio dal piano di proiezione
       prospettica al viewport avviene in due passi: (i)
       trasformazione in una finestra 2 x 2 centrata nell'origine
       (<emphasis> normalized device coordinates </emphasis>) (ii)
       mappatura della finestra normalizzata sul viewport. Usando la
       rappresentazione intermedia a coordinate normalizzate,
       l'operazione di <term> clipping</term>, cioè di eliminazione
       degli oggetti o loro parti non visibili attraverso la finestra,
       diventa banale. In Processing, le funzioni
       <code>screenX()</code>, <code>screenY()</code>, e
       <code>screenZ()</code> consentono di ottenere le coordinate X-Y
       prodotte dalla trasformazione di viewport e dagli elementi
       precedenti della catena di <cnxn target="pipelineOpenGL"/>.
      </para>
      <para id="frustum">Il <term>frustum</term> di vista è l'angolo
      solido attraverso il quale si attua la proiezione prospettica,
      come indicato in <cnxn target="frustumf"/>. Vengono visualizzati
      gli oggetti (o le loro parti) presenti nel volume di vista, le
      rimanenti parti essendo soggette a clipping. In Processing (e in
      OpenGL) il frustum si può definire mediante posizionamento dei
      sei piani che lo individuano (<code>frustum()</code>), oppure
      mediante specificazione di angolo verticale, <term>aspect
      ratio</term>, posizione dei piani anteriore e posteriore
      (<code>perspective()</code>).  Ci si può chiedere come avvenga
      la rimozione delle facce nascoste, cioè di quelle facce che sono
      mascherate da altre facce presenti nel volume di vista. OpenGL
      usa l'algoritmo dello <term src="http://en.wikipedia.org/wiki/Z_buffer">z-buffer</term>, che
      è supportato dalle schede grafiche. La scheda tiene un'area di
      memoria bidimensionale (lo z-buffer) corrispondente ai pixel
      della finestra di vista e contenente valori di profondità. Prima
      di proiettare un poligono sulla finestra di vista la scheda va a
      controllare che i pixel affetti da tale poligono non abbiano già
      un valore di profondità inferiore rispetto a quello del poligono
      in oggetto. In questo caso significherebbe che c'è un oggetto
      grafico che maschera quello che si sta disegnando.  </para>

      <figure id="frustumf">
	  <name>Il frustum di vista</name>
	  <media type="image/png" src="frustum.png">
	  </media>
      </figure>

      <para id="processingBGraphicsp">
	Elaborazioni geometriche sofisticate si possono ottenere
	 manipolando direttamente le matrici di proiezione e
	 model-view. Ciò è possibile, in Processing, a partire dalla
	 matrice unitaria, caricata con <code>resetMatrix()</code>,
	 mediante moltiplicazioni matriciali eseguite con
	 <code>applyMatrix()</code>.
	<!-- Elaborazioni più
	 sofisticate di quelle ottenibili con le primitive Processing,
	 si possono ottenere utilizzando l'oggetto <code>g</code>,
	 istanza della classe <code>BGraphics</code>. Ad esempio, con
	 <code>g.transform()</code> si può imporre una matrice di
	 trasformazione, per fare uno scalamento obliquo
	 (<emphasis>shearing</emphasis>) o per proiettare ombre (si
	 veda l'esempio <code>shadows </code> in <link
	 src="http://www.cs.unm.edu/~cello/processing/"> I like
	 processing </link>). L'oggetto <code>g</code> è già stato
	 menzionato nella <cnxn target='illuminazione'/> a proposito
	 della regolazione delle sorgenti luminose. Purtroppo
	 l'utilizzazione della classe <code>BGraphics</code> non è
	 documentata, e per sapere quali metodi e variabili sono
	 disponibili bisogna riferirsi al <link
	 src="http://cvs.sourceforge.net/viewcvs.py/processing/cbagel/bgraphics.h">
	 codice sorgente</link>. -->
      </para>
      <exercise id="isometric_cube">
	<problem>
	  <para id="isometric_cubep">
	    Si esegua e si analizzi il codice Processing 
	    <code type="block">
	      size(200, 200, P3D);
	      println("Default matrix:"); printMatrix();
	      noFill(); 
	      ortho(-width/2, width/2, -height/2, height/2, -100, 100); 
	      translate(100, 100, 0); 
	      println("After translation:"); printMatrix();
	      rotateX(atan(1/sqrt(2))); 
	      println("After about-X rotation:"); printMatrix();
	      rotateY(PI/4); 
	      println("After about-Y rotation:"); printMatrix();
	      box(100); 
	    </code>
	    Cosa visualizza e con che tipo di proiezione? Come si
	    interpretano le matrici stampate nella consolle? Posso
	    invertire l'ordine delle rotazioni?
	  </para>
	</problem>
	<solution>
	  <para id="isometric_cubes">
	  Il wireframe di un cubo viene visualizzato in assonometria
	    isometrica. Le ultime tre matrici rappresentano,
	    accumulandole una dopo l'altra, le tre operazioni di
	    traslazione (per allineare il cubo al centro della
	    finestra), rotazione intorno all'asse <m:math>
	    <m:ci>x</m:ci> </m:math>, e rotazione intorno all'asse
	    <m:math> <m:ci>y</m:ci> </m:math>. Una successione di due
	    rotazioni corrisponde al prodotto di due matrici di
	    rotazione, e il risultato non è indipendente dall'ordine
	    delle matrici (il prodotto non è commutativo). Il prodotto di due matrici di rotazione <m:math>
	      <m:apply>
		<m:times/>
		<m:msub>
		  <m:ci>R</m:ci>
		  <m:ci>x</m:ci>
		</m:msub>
		<m:msub>
		  <m:ci>R</m:ci>
		  <m:ci>y</m:ci>
		</m:msub>
	      </m:apply>
	    </m:math> corrisponde ad eseguire prima la rotazione intorno a <m:math>
	      <m:ci>y</m:ci>
	    </m:math>, e poi la rotazione intorno a <m:math>
	      <m:ci>x</m:ci>
	    </m:math>.
</para>
	</solution>
      </exercise>
      <exercise id="oblique_projectione">
	<problem>
	  <para id="oblique_projectionep">
	    Si scriva un codice Processing che produca la proiezione
	    obliqua di un cubo.
	  </para>
	</problem>
	<solution>
	  <para id="oblique_projectionesp"> Ad esempio: 
	    <code type="block">
	    size(200, 200, P3D);
	    float theta = PI/6; 
	    float phi = PI/12;
	    noFill(); 
	    ortho(-width/2, width/2, -height/2, height/2, -100, 100); 
	    translate(100, 100, 0);
	    applyMatrix(1, 0, - tan(theta), 0,
	                0, 1, - tan(phi), 0,
                        0, 0, 0, 0,
                        0, 0, 0, 1);
	    box(100); 
	    </code>
	  </para>
	</solution>
      </exercise>
      <exercise id="ombre">
	<problem>
	  <para id="ombretp"> Si visualizzi un cubo che proietti la
	  sua ombra sul suolo, assumendo che la sorgente luminosa sia
	  a distanza infinita (quale si può considerare, in pratica,
	  la distanza del sole).
	  </para>
	</problem>
	<solution>
	  <para id="ombresp">Si opera in modo simile a quanto visto in
	  <cnxn target="perspective_shadow"/>, ma la trasformazione
	  proiettiva è di tipo ortografico:
	    <code type="block">size(200, 200, P3D);
	      noFill();
	      translate(100, 100, 0);
	      pushMatrix();
	        rotateY(PI/4); rotateX(PI/3);
	        box(30);
	      popMatrix();
	      translate(0, 60, 0); //proietta un'ombra da infinito (sole)
	      applyMatrix(1, 0, 0, 0,
	                  0, 0, 0, 0,
                          0, 0, 1, 0,
                          0, 0, 0, 1); 
	      fill(150);
	      pushMatrix();
	      noStroke();
	      rotateY(PI/4); rotateX(PI/3);
	      box(30);
	      popMatrix(); 
	    </code>
	  </para>
	</solution>
      </exercise>
      
    </section>
  </content>
  
<bib:file>

<bib:entry id="Angel">
<bib:book>
<bib:author>Edward Angel</bib:author>
<bib:title>Interactive Computer Graphics: A Top-Down Approach With OPENGL primer package-2nd Edition</bib:title>
<bib:publisher>Prentice-Hall, Inc.</bib:publisher>
<bib:year>2001</bib:year>
</bib:book>
</bib:entry>
</bib:file>

</document>
