continua (next page) Index of UNOFFICIAL Circumvesuviana Home Page main index Beh, se proprio volete vedere cosa si può combinare con POVray potreste vedere cosa combinano principianti e appassionati quando gareggiano nell'Internet Ray Tracing Competition...

Ovviamente lui ha una filosofia leggermente diversa dalla mia: mentre io candidamente prediligo le primitive elementari, lui è un matematico che spreme a fondo il linguaggio di programmazione di POV per tirar fuori una quantità abominevole di smooth_triangle e patch bicubiche...!

Ovviamente noi semplici esseri umani utilizziamo il gustosissimo KPovModeler!!!


Mostruoso: è uscito POVray 3.6.

Prima segnalazione: c'è da osservare, nella sua documentazione, l'esempio che hanno fatto per dimostrare la potenza del suo scene description language: hanno scritto un intero raytracer usando solo il linguaggio del raytracer di POV!

Seconda segnalazione (e questo è il motivo principale, se non unico, per lavorare con POV 3.6): tra le numerose features spicca una radiosity assolutamente incredibile, che rende POV definitivamente il miglior raytracer in circolazione, aggiungendo alla sua versatilità la caratteristica più colossale degli engine commerciali per il raytracing.


Ho il pallino del ray tracing fin dall'uscita della primissima versione di Persistence Of Vision (detto "POVray", per gli amici "POV").

Purtroppo la scarsità di potenza di calcolo mi è stata sempre di ostacolo: fino a pochi anni fa avevo disponibile solo un modesto 386dx40 che, sotto Linux, per il rendering di palline.pov impiegò la bellezza di quindici giorni di infaticabile lavoro in background a bassa priorità...

I simply happen to love ray-tracing, since the first available version of POVray. You can follow the Continua -- next page links to see my best works (source and rendered image).

I miei lavori migliori li puoi vedere (listato e immagine risultante) cliccando di volta in volta su continua - next page. A causa degli aggiornamenti del linguaggio di POVray durante gli anni, alcuni listati potrebbero richiedere piccole modifiche per essere compilati senza warnings.


Musica suggerita durante la visione di queste pagine: La Moldava di Smetana, diretta dal grande Frincsay.


Ecco il testo di un piccolo "corso" sul POVray che tenni alcuni anni fa sulla rete di BBS PNet.


RAYTRACING, COME GODO                                    alfmar   luglio 1995

"Papa', ora che abbiamo una piastra Doppio Pentium (Doppio Bug) a 120MHz, si
puo' sapere che ce ne facciamo?" --> "Zitto che sto lanciando Wordstar 3.3".

Non staro' a fare una discussione computerfilosofica del raytracing, mi limito
a dire solo un paio di cosucce a chi si sente preso da un brivido ancestrale
di sentirsi un "incompetente in materia", prima di entrare in azione.

Raytracing per fortuna non e' il diminutivo di Raymond Tracing, l'americano
che ha inventato l'algoritmo e ha scritto il primo programma a risoluzione
240x120 in bianco e nero su Apple II nel lontano 1983 in una notte di
pioggia.

Il raytracing, che io sappia, e' il processo di disegno (bidimensionale) di
una scena tridimensionale descritta per "primitive" (cubi, sfere, coni, etc).
Ad ogni oggetto e' associata una posizione nello spazio (quindi le coordinate
3D) nonche` altri parametri caratteristici (riflettenza, brillanza, etc).
L'osservatore della scena e' in una certa posizione dello spazio e guarda in
una certa direzione; nello spazio esistono uno o piu' punti dove "comincia" la
luce che forma, con gli oggetti, i vari giochi di ombre, trasparenza, etc.

Un "normale" programma di disegno 3D (e pressoche` tutti i giochi in grafica
vettoriale 3D) si preoccupa al piu' di ricolorare in modo uniforme le zone
ombrate e di eliminare le superfici nascoste; il raytracing e' assai piu'
evoluto perche` prevede appunto ombre (superfici opache), trasparenza (acqua),
riflessione (specchi), rifrazione (vetro), etc, per cui "modellando" i
parametri si puo' ottenere un disegno di un realismo estremo.

Il raytracing si basa su un concetto tanto semplice quanto dispendioso in
termini di potenza di calcolo richiesta: per ogni punto vengono generati i
raggi (rays) da tutte le sorgenti di luce e a furia di intersezioni e
riflessioni con gli oggetti (chi ha studiato ottica sapra' di riflessione
diffusa, speculare, luce ritrasmessa, specchi "quasi perfetti", rifrazione,
etc) si determina il colore finale del pixel nell'immagine.

Un programma di raytracing fa proprio tutto questo. Fa definire gli oggetti
(in termini di posizioni e di caratteristiche) nello spazio tridimensionale;
fa definire la posizione dell'osservatore e delle sorgenti di luce ed infine
calcola l'immagine (rendering). Non conosco 3D-Studio ma so che lo fa :-)...
quello che invece vi presento in questo messaggio e' il POVray (Persistence Of
Vision raytracer, v2.2), per gli amici: POV.

I risultati migliori, per la visualizzazione, li ottengo - inutile a dirsi -
con una scheda truecolor (24 bit per pixel); con una scheda hicolor a 32000 o
64000 colori si ottengono ancora dei risultati decenti, ma a 256 colori non si
vede proprio niente. I miei lavori sono tutti a 640x480 a 16 milioni di colori
per punto - ho una 2-The-Max con Tseng ET4000 e AcuMos ADAC1 a 15-16-24 bit
per pixel, comprata un paio di anni fa abbondanti; il monitor e' un Mitsubishi
a colori (14 pollici) e i risultati sono eccellenti. POV mi genera delle
immagini in formato Targa-uncompressed di oltre 900k l'una (640x480x3=...),
passandole in JPEG si scende fino a 20k, ma si rischia di perdere qualcosa per
la solita storiaccia della compressione "lossy" (le immagini generate sono di
una perfezione da paranoia)... ma questo e' un problema che tratteremo a parte
- e comunque si tratta solo di spazio su hard disk.

In area P_UNIX do' qualche consiglio per compilare ed usare massicciamente il
POV sotto Linux; chi ha un DX4/100 si deliziera' con al piu' qualche ora di
calcolo; io ho uno stupido 386/40 senza coprocessore e per un rendering
"pesante" (con molti oggetti) devo far girare il programma anche per una
quindicina di giorni.

POV fa semplicemente il "calcolo". Vuole in input un file ascii in una specie
di linguaggio di programmazione che descrive la scena e genera - previo uso
intensivo della cpu per un mostruoso numero di ore - l'immagine in formato
Targa-uncompressed (.TGA), visualizzabile sotto DOS col CSHOW 8.xx (per il
Linux ho scritto un programmino io per la mia scheda, ne parliamo in P_UNIX).
Vediamo l'esempio piu' semplice (il mio mitico "pittura.pov"), di appena
quattro righe:

  #include "colors.inc"

  camera  {   location <0, 2, -3>    look_at <0, 1, 2>   }

  sphere  {   <0, 1, 2>, 2   texture {  pigment  { color Yellow }  }   }

  light_source  {  <2, 4, -3>  color White }

(gli spazi non sono troppo importanti). All'inizio includo ovviamente il file
che ha tutti i colori predefiniti (ho usato solo Yellow e White). La seconda
riga definisce dov'e' l'osservatore, pardon, dov'e' la sua telecamera: alla
locazione x=0, y=2, z=-3 (prendeteli per metri, centimetri, quello che volete)
e guarda esattamente il punto x=0, y=1, z=2 (che dunque nel rendering
corrispondera' proprio al centro dell'immagine).

Nella terza riga finalmente ci metto un oggetto: una sfera, di centro x=0,
y=1, z=2 (proprio dove sto puntando la telecamera), di raggio 2 (centimetri,
metri o quel che vi pare: stessa unita' di misura per tutti), che ha uno
stupendo colore giallognolo. Nella quarta riga dico che la lampadina (pardon,
sorgente di luce di colore bianco) e' posizionata a x=2, y=4, z=-3.

L'asse x e' l'asse orizzontale del video che abbiamo davanti. L'asse y e'
quello verticale (quindi il video pare proprio in coordinate cartesiane) e
l'asse z e' quello che parte da noi e va verso l'interno dello schermo. Dunque
la sorgente di luce e' 2 metri piu' a destra di noi (2-0=2), 2 metri piu' su
di noi (4-2=2), e non e' ne` piu' avanti ne` piu' indietro ((-3)-(-3)=0).
Spero non si siano offesi i bimbi delle elementari per questa considerazione
algebrico-matematica.

Il modo preoccupante di definire il colore della sfera:
  sphere  {   <0, 1, 2>, 2   texture {  pigment  { color Yellow }  }   }

era semplicemente perche` il secondo esempio e':
  sphere  {   <0, 1, 2>, 2   texture {  Bronze_Texture  }   }

Le caratteristiche di un oggetto si definiscono proprio nel blocco parametri
"texture"; il "pigment" e' solo il gruppo parametri "colore"+"trasparenza".
Nel primo esempio la sfera era gialla e basta (tutti gli altri hanno un
default, nel nostro primo esempio la sfera e' opaca e sembra dipinta col
pennarello); aggiungendo altri parametri (brillanza, riflessione) si ottiene
un effetto "cambio materiale": nel secondo esempio il materiale e' appunto il
bronzo, di colore "bronzeo" (55/100 di rosso, 47/100 di verde, 14/100 di blu,
nessuna trasparenza), brillanza 6, riflessione 25%, etc.

I parametri su cui si puo' intervenire sono veramente numerosi, e si possono
ovviamente dare valori assurdi (un oggetto che riflette troppo e rifrange
ancora di piu'; non so se esista in natura un materiale che "specchi" gli
oggetti intorno lasciando passare la luce da tutti gli altri lati...).

C'e' per esempio la finitura "phong" che fa "specchiare" la luce in maniera
plastica; la caretterizzazione "metallic", l'effetto "marble" (marmo?), etc;
un oggetto puo' anche essere ruvido ("roughness"); si puo' dare un po' di
"turbulence" nella colorazione o nella definizione dell'oggetto; si possono
cambiare i gia' citati parametri di brillanza, riflettenza, rifrazione e
cambiare, in POV, anche l'indice di rifrazione che normalmente vale 1.33 per
l'acqua, 2.5 per i diamanti, etc.

Nei prossimi messaggi parlero' un po' piu' diffusamente di POV e di quel
poco che ho imparato finora (il manuale appare a prima vista ostico, invece
e' di una chiarezza e di una semplicita' deliziose). Nel frattempo scaldate
pure i processori perche` finalmente avrete modo di usare la CPU per piu'
di venti secondi totali al giorno (aho', ogni operazione vi finisce in un
centesimo di secondo, sarebbe pure ora di sfruttare tanta potenza di calcolo,
no?).

PS- cerco un volenteroso con un Pentium che mi calcoli i miei script piu'
tremendi e me li mandi via modem... :-)

----------------------------------------------------------------------------

Visto che nessuno ha risposto al mio primo messaggio in materia,
mi permetto di insistere sull'argomento perche` queste immagini
raytraced sono veramente la delizia degli occhi...

Faccio prima un po' di debug dello scorso messaggio: avevo citato la
texture { Bronze_Texture }, senza dirvi pero' che per usarla dovreste
#includere "textures.inc".

Il linguaggio di POVray (Persistence Of Vision raytracer, POV per gli amici)
e' come ho gia' detto, un linguaggio descrittivo. In pratica serve per dire
a POV, in ordine sparso, quali sono gli oggetti, dove sono, e come sono.

In questo messaggio pero', piu' che dilungarmi sulle caratteristiche degli
oggetti, preferirei fare qualche considerazione sulla potenza di calcolo e
poi dare un'occhiatina ai parametri da command-line di POV. Personalmente
mi sono preparato due batch files POV e POVFAST che, manco a dirlo,
renderizzano rispettivamente a 640x480 in massima qualita' e a 128x96
in minima qualita' (ho scelto 128x96 perche` e' esattamente 1/25 dello
schermo).

Occhio! I parametri che si usano sotto Linux sono gli stessi che si usano
sotto DOS. L'unico serio inconveniente sotto DOS puo' essere la mancanza
di memoria RAM - all'epoca con qualche giochetto strano riuscivo a "sfondare"
i 640k (VGARAM, DESQview, etc: 704k col primo e 735k col secondo, altro che
640k!); non ho visto finora tra i demo nessuno richiedere piu' di 700k
(perlomeno sotto Linux), pero' non posso giurare che sia sempre cosi'.

Dicevo: anche se avete un Pentium/120, renderizzare un'immagine puo'
costarvi ore di CPU. Un Pentium/120 dovrebbe essere non piu' di 3 o 4
volte piu' veloce di un 486/66, che dovrebbe essere non piu' di 3 o 4
volte piu' veloce di un 386+387/33, che dovrebbe essere non piu' di 5
volte piu' veloce di un 386/40. Un rapido e pagnottesco conto ci dice
che un Pentium/120 e' 80 volte piu' veloce del mio 386/40 senza 387,
che e' poco meno di due ordini di grandezza. In parole povere, se
a me ci mette 15 giorni di cpu (normale, per certe immagini con molti
specchi e parecchie luci - altre sono anche peggio), sul Pentium/120
ci mettera' 4 ore e mezza. Se commettete un errorino nel .POV, ve ne
accorgerete dopo 4 ore e mezza... grunt!

Morale della favola: uno script "veloce" e' indispensabile per avere
un "preview veloce" dell'immagine senza morire di noia, anche sul
Pentium/120 che, a quanto mi risulta, non e' ancora in commercio.
Nel frattempo cominciamo a far lavorare le macchine che abbiamo,
sarebbe ora di sfruttare piu' dell'uno per mille della *vera* potenza
di calcolo di questi arnesi - a che pro una directory velocissima,
mega di memoria, transfer rate elevati e... e poi li sottosfruttiamo
sotto DOS o li lasciamo sprecare a Windoze e OS2/Purp?

POV non ha una fissata risoluzione, gliela specifichiamo noi. Il
consiglio che ovviamente do' per le immagini di qualita' (quelle
"definitive") e' di considerare la massima risoluzione che avete
sulla scheda video quando scegliete un modo a 16 milioni di colori
(truecolor, 24-bit o come volete chiamarlo). La mia scheda video
supporta in truecolor solo il 640x480, quindi non ho che l'imbarazzo
della scelta. Alcune schede se non sbaglio fanno anche gli 800x600 -
inutile dire che i rendering dureranno il 60% in piu' perche` ci
sono il 60% in piu' di pixels rispetto alla precedente risoluzione.

Il massimo numero di colori distinguibili dall'occhio umano e' intorno
ai trecentomila; i "16 milioni di colori per punto" sono un abbondante
sovradimensionamento che in ogni caso "imbroglia" l'occhio e da'
delle immagini spaventosamente perfette. Anche a 320x200 dovrebbe
essere cosi', pero' la "grana grossa" dei punti vi farebbe scorgere
qua e la' qualche piccola differenza, per cui considerate soltanto
le risoluzioni 640x480 e superiori (se ce ne sono). Anche se in fin
dei conti la 640x480 e' gia' una "fotografia", per cui forse la 800x600
non aumenta veramente di tanto la qualita'...

Dicevo prima: i preview a risoluzione inferiore li ho fatti a 128x96
perche` e' esattamente un venticinquesimo dello schermo. Se avessi
scelto 320x240 (meta' larghezza e meta' altezza; non conviene usare
rapporti diversi per l'asse x e l'asse y altrimenti l'immagine viene
falsata), avrei ridotto ad un quarto i tempi di calcolo (che su 15
giorni e' ancora un po' troppo). Il minimo accettabile e' dunque
(per me) un rapporto di un quinto sull'asse x ed un quinto sull'asse y,
che risolve in tempi abbastanza brevi e da' perfino un'idea di quanto
sara' lungo il calcolo dell'immagine a 640x480.

POV dunque accetta i parametri sulla risoluzione:

    povray +w640 +h480 ...

I parametri da command-line cominciano per "+" (enable) o "-" (disable);
per alcuni non e' necessaria questa distinzione (come per i citati comandi
w ed h), per cui ho messo il "+" che mi piace di piu'...

Un altro comando e' il +V (occhio alle maiuscole e alle minuscole!),
che abilita una visualizzazione a video del tipo "calc line 306 of 480",
comodissima per sapere a che punto e' arrivato.

Abbiamo poi i comandi +Q9 e +A0.3 che io uso per le versioni definitive
(quelle di qualita'): quality 9, cioe' massima (max numero di iterazioni,
etc), ed antialiasing 0.3, cioe' valore piu' o meno ottimale per tutte
- l'antialiasing e' quello "sfasamento medio" sui pixel per evitare
delle rapide "cadute" del contrasto: se un pixel bianco ed un pixel nero
sono adiacenti, con l'antialiasing il primo diventera' grigio chiaro ed
il secondo grigio scuro, cosi' l'effetto "scaletta" (rogna infame di
chi nell'88 usava Autocad 2.17 con la CGA a 640x200) sparisce. Inutile
dire che questi comandi non li useremo nello script POVFAST... ;-)

Il parametro +FT specifica che l'output sara' un file Targa-uncompressed
(che consta di un header di 18 bytes seguito dalla descrizione esatta
dei pixel uno per uno, tre bytes per ogni tripla R/G/B). Il formato +FR
(raw file) pare che sia lo stesso del .TGA suindicato, senza i 18 bytes
citati. Il guaio e' che Cshow vede solo i .TGA, non ne capisce niente
di "raw" o di "dump" (che e' l'altro ed ultimo formato supportato da POV).

Aggiungiamo poi il parametro +C ("continue image"), per cui se
interrompiamo il calcolo (manca la corrente o resettiamo noi),
ricomincera' dall'ultima linea salvata su disco (se l'immagine
non esiste, protestera' con una riga a video e comincera' daccapo,
per cui io lo uso sempre e comunque... usare -C significherebbe
far ripartire daccapo il calcolo dell'immagine).

Mancano soltanto i comandi per i files:
+L/povray/include/   +I/povray/prova.pov   +O/povray/output/prova.tga

il primo dice qual e' la directory dove sono contenuti i files .INC
(avevamo esaminato "colors.inc" nello scorso messaggio e abbiamo
citato "textures.inc" in questo); il secondo dice qual e' il file
di input ed il terzo qual e' il file di output. In Linux lo slash
per le directories e', come in Unix, il carattere '/'; ovviamente
nel DOS dovrete usare il backslash '\'.

Dunque gli script sono:

POV.BAT:
          povray +C +V +FT +w640 +h480 +Q9 +A0.3 +L/povray/include/
                           +I/povray/$1.pov +O/povray/output/$1.tga

POVFAST.BAT:
                  povray +C +V +FT +w128 +h96 -A +L/povray/include/
                           +I/povray/$1.pov +O/povray/out-fast/$1.tga

(notate che la shell di Linux usa "$1" per il primo parametro da
command-line mentre il DOS usa "%1"; notate inoltre che ho messo
in due directories separate gli output 640x480 di qualita' e quelli
128x96 senza qualita' e senza antialiasing).

Una volta creato il citato PITTURA.POV, possiamo avere un preview
lanciando POVFAST PITTURA (l'estensione .POV e .TGA ce la mette il
batch file) e possiamo renderizzarlo alla perfezione con POV PITTURA.

Questo e' tutto per oggi... buon divertimento; la prossima volta
cominciamo a smanettare sul serio col linguaggio di POV.

----------------------------------------------------------------------------

Finalmente uno interessato, incredibile ma vero...:-)
Allora posso continuare, non sto parlando a vuoto :-)

Abbiamo parlato nei giorni scorsi di un po' di tutto tranne che
del linguaggio... prima di passare definitivamente al linguaggio
di POVray, vorrei fare un paio di osservazioni per far passare un
po' di paura a quelli che cominciano con "ma io non so compilare".

Il dramma di tutti i programmi forniti in sorgente e' il tremendo
"errore durante la compilazione" perche` compilatori diversi hanno
abitudini (ottimizzazioni, standard, etc) diverse.

POV per fortuna non e' cosi'. Due anni fa lo compilai sotto DOS
(con il Borland C++ 2.0) senza problemi; uscirono una marea di
"Warning:..." a video, ma mi genero' l'EXE senza troppa fatica.
Stessa cosa per Linux e Gnu C/C++ (GCC 2.6.3 e GCC 2.5.8), anzi
qui ricordo di aver avuto neppure un warning, segno che POV e'
stato scritto in C "puro e semplice", senza usare stranezze che
vanno bene su un determinato compilatore e male su tutti gli altri
- come aneddoto racconto sempre che il MASM 5.1 della Microsoft
era talmente bacato da costringere il team TASM della Borland
ad implementare un comando "MASM51" che emulava gli stessi bug :-).
Il guaio e' che non si tratta di un aneddoto ma della verita'!!!

Dicevo: *facile* da compilare. Basta masticare un minimo di
inglese e saper editare un file ascii - non serve nessuna modifica
al codice, neppure ridefinire qualche #include file di configurazione.
Basta solo rinominare unixconf.h in config.h e lanciare il makefile
adatto (rinominare unix.mak in Makefile). Basta ovviamente avere
compilatore e librerie su disco (il compilatore dopo non serve
piu' e quindi potete pure buttarlo). Se qualcuno avesse *davvero*
problemi, posso fornire il mio eseguibile o al limite ricompilarlo
io (sempre pero' quello sotto Linux, per il DOS non ho da tempo
un compilatore decente, ci potro' provare quando ce l'avro').

Qualcuno si potra' lagnare che l'interfaccia utente e' testuale,
ma per un programma che vi costa 5 secondi lanciarlo e ore e ore
(quando non giorni e giorni) di attesa per l'output, chiedere
qualcosa piu' di tanto e' come chiedere di sprecare risorse
senza motivo... cercatevi piuttosto un programma che visualizzi
bene le schermate in truecolor o perlomeno a 32000 colori, che
e' la cosa piu' importante.

Veniamo finalmente al linguaggetto di POV (era ora). Il manuale
e' abbastanza chiaro (e qui potrei pure smettere di scrivere),
pero' io non mi sono mai fidato troppo dei manuali, per cui
vediamo direttamente "su strada" come si comporta, e poi ci
andiamo a guardare pure il manuale per vedere cos'altro si puo'
fare. Citero' spesso i file di #include (colors.inc, textures.inc,
etc) perche` contengono un sacco di roba gia' pronta e gia' tarata
al millimetro, il che ci risparmiera' prove ed esperimenti (per
esempio gia' possiamo definire oggetti di "vetro", "bronzo",
"marmo", "legno", etc - chi non mastica l'inglese si procuri
un dizionarietto perche` parlero' di "glass", "wood", etc).

Dicevamo del primo esempio:

  #include "colors.inc"
  camera  {   location <0, 2, -3>    look_at <0, 1, 2>   }
  sphere  {   <0, 1, 2>, 2   texture {  Bronze_Texture  }   }
  light_source  {  <2, 4, -3>  color White }

I primi esperimenti che possiamo fare su questo sono...

- spostare la telecamera piu' dietro: vedremo la pallina piu' piccola,
  provate a mettere la telecamera a <0, 2, -10> (7 unita' in meno
  sull'asse delle z, cioe' telecamera spostata dal video verso di noi):
  vedrete la pallina con il raggio ridotto a circa meta'; con un po'
  di conti (che per motivi di sonno non vi faccio :-) scopriremo
  che e' esattamente quello che doveva succedere perche` abbiamo
  aumentato la distanza della telecamera dal centro della sfera
  (prima era 5, cioe' da -3 a +2, dopo era 12, cioe' da -10 a +2,
  dunque circa il doppio della distanza diventa circa meta' della
  grandezza);

- colorazione (intendo "texture") - al posto della Bronze_Texture,
  proviamo qualcuna a caso, tipo:
  White_Marble   un marmo bianco/grigio/nero delizioso
  Pinkalabaster  pare un marmo sgrigiato, come i piani di lavoro delle cucine
  DMFWood1       legno scuro, che delizia
  Glass          vetro, trasparente ma non troppo
  Brass_Valley   metallico con sfumature, pare materia grezza
  Per motivi di fretta - per concludere presto questo messaggio -
  ho provato solo Brass_Valley e Glass. Nel primo caso ci appare una
  specie di pianetoide con una colorazione difficile da descrivere
  (intorno al marmoreo), che dal modo in cui riflette la luce ci
  sembra metallico. Nel secondo caso, sorpresa! Il vetro lascia
  passare la luce e si vedono solo gli "spicchi" di luce sopra e
  sotto (e' l'effetto "phong" che vedremo nei prossimi giorni);
  per il resto e' vetro purissimo, dunque odiosamente trasparente,
  la luce si perde nel vuoto e rimane un po' nei due punti (agli
  antipodi tra loro) e sul bordo esterno in alto a destra.
  Provare per credere!

- cambiare la posizione o il colore della luce. Questo non lo faccio
  perche` sto morendo di sonno, fatelo voi come "compiti per casa":-)

Domani scrivo un altro messaggio, stavolta parleremo di altri oggetti
perche` di sfere ne abbiamo le tasche piene :-)

----------------------------------------------------------------------------

Riparto all'assalto con altri files .POV, stavolta vediamo un po' di tutto.

La prima cosa da considerare e' il caos che si puo' fare con le coordinate
tridimensionali (i vettori specificati tra parentesi angolari: <0,0,0>...).

Nella mia piccola esperienza ho notato che la cosa migliore e' definire una
scena con unita' di misura "quasi reali". Per cui "assemblando" una stanza
conviene usare per esempio i "centimetri" - consideriamo uno spazio largo, in
centimetri, x=500, y=300, z=400, cioe' una stanza di 5 metri per 4 ed alta 3:
l'osservatore (camera) sara' alla porta (cioe' x=150, y=160, z=0), il
lampadario sara' a x=250, y=260, z=200 (centro soffitto meno 40 cm), e cosi'
via. Ovviamente questo livello di difficolta' lo affronteremo in seguito, per
immagini piu' semplici quasi sempre conviene usare come look_at della
telecamera il punto <0,0,0>, cioe' l'origine degli assi, e piazzare la
location in un altro punto un po' piu' lontano degli oggetti (che saranno
evidentemente disposti intorno all'origine, altrimenti non vedremo un bel
tubo). Nei prossimi esempi faro' proprio cosi'.

Gli oggetti che consideriamo oggi sono ancora oggetti del linguaggio di POV
(sui quali ovviamente POV fa tutte le ottimizzazioni possibili). Abbiamo a
disposizione, oltre alla sphere, anche i parallelepipedi, per esempio:

box  { <1,2,3>, <5,4,8>  texture { Silver2 } }

equivale ad un parallelepipedo di grandezza x=4, y=2, z=5 (ricordate che z e'
la "profondita'" cioe' dal vostro occhio verso l'interno dello schermo), con
uno dei due spigoli a <1,2,3> e l'altro a <5,4,8> (per cui la grandezza sara'
x=5-1=4, y=4-2=2, z=8-3=5).

Abbiamo a disposizione anche coni e tronchi di cono:

cone  { <1,2,3>, 1.5,  <5,6,8>, 5   texture { Silver2 } }

Il primo vettore <1,2,3> specifica il centro superiore; segue il raggio della
circonferenza superiore, quindi il centro inferiore e il raggio inferiore.
L'esempio citato e' un cono il cui asse centrale e' la linea da <1,2,3> a
<5,6,8>. Per ottenere un cono perfetto anziche` un tronco di cono basta usare
0 al posto del raggio superiore (anziche` 1.5 come nell'esempio).

Infine abbiamo i cilindri; usano piu' o meno la stessa logica (e magari anche
le stesse routines, visto che un cono con i raggi superiore e inferiore uguali
non e' altro che un cilindro)... tanto per usarli, si usano cosi':

cylinder { <5,2,1>, <9,5,3>, 1.3333  texture { Silver2 } }

Nell'ordine: i due punti estremi dell'asse centrale, il raggio, e la deliziosa
immancabile texture.

Tutti gli oggetti sono "texturizzabili"; negli esempi uso sempre quelle
definite in "textures.inc" perche` il discorso in dettaglio (come crearne o
modificarne una) lo analizzeremo piu' avanti; nel frattempo queste qui a base
di granito, marmo, legno, metallo, sono una vera delizia... :-)

Vediamo dunque un esempio:

   #include "colors.inc"
   #include "textures.inc"

   camera        {  location <0, 0, -20>       look_at <0, -4.5, 0>       }

   sphere        {  <-5, 0, 0>,  2             texture { Gold_Texture  }  }
   box           {  <-2, -2, -2>,  <2, 2, 2>   texture { Apocalypse    }  }
   cone          {  <5, 2, 0>, 0
                    <5, -2, 0>, 2              pigment { DMFWood4      }  }
   cylinder      {  <-5, -5, 0>,
                    <5, -5, 0>, 2              texture { Yellow_Pine   }  }

   light_source  {  <-9, 4, -2>                color White                }
   light_source  {  <0, 5, -2>                 color Magenta              }
   light_source  {  <9,  4, -2>                color Yellow               }

Inizialmente avevo posto la telecamera a <0,0,-20> guardando verso <0,0,0>,
poi dopo aver "sistemato" anche il cilindro, ho pensato che non ce l'avrei
fatta ad inquadrarlo tutto ed ho spostato piu' giu' il centro del mirino,
precisamente <0, -4.5, 0>  ("-4.5" sull'asse y, cioe' proprio "piu' giu'").

Solita sfera, un po' a sinistra della visuale (che originariamente era a
<0,0,0>), di raggio 2 - quindi "sfruttera'" nell'asse delle x lo spazio da
-5-2=-7 a -5+2=-3. Per cui la "box" la piazzo a partire da x=-2. Nel nostro
esempio e' un cubo perfetto, di lato 4 (2-(-2)=4), guardacaso con centro
proprio nell'origine. Non ho letto il manuale, se non sbaglio c'e' anche un
comando "cube" per risparmiarsi ancora un po' di fatica...

La box finisce a x=2, per cui piazziamo un cono con la base maggiore a x=5 e
di raggio 2 (quindi sara' largo da x=5-2=3 a x=5+2=7), sempre "allineato" come
altezza a sfera e cubo. Dunque abbiamo messo in linea sfera, cubo e cono,
quest'ultimo non ha una texture completa ma solo il colore.

Infine ho messo "sotto" il cilindro, di raggio 2, -5 unita' piu' giu'
dell'origine - i tre oggetti di sopra sono "estesi" sull'asse delle y da y=2 a
y=-2, dunque il cilindro, essendo da -5-2=-7 a -5+2=-3, non andra' a collidere
con loro. Anche questo vedremo in seguito - intersezioni e unioni potranno
fare "forme" stranissime ed effetti notevoli.

Osservate infine come ho messo le tre (!) sorgenti di luce (per cui il
rendering sara' piu' lentuccio dei primi velocissimi esempi dello scorso
messaggio). Guardando le coordinate scoprirete che la prima e la terza sono
piu' o meno "simmetriche", e la piu' vicina ha una luce meno intensa delle
altre due. Per "meno intensa" intendo minor "carico R/G/B". Infatti i colori
si definiscono proprio in termini di "carico" Red/Green/Blue, con valori che
vanno da 0 a 1, che ricordano il modo di costruire le "palette VGA".

Per esempio il rosso completo si ottiene con:

                color red 1 green 0 blue 0

In colors.inc e' definito gia' come Red, per cui scrivere "color {Red}"
anziche` "color red 1 green 0 blue 0" non cambia niente. NB- dato che green e
blue sono zero, possiamo anche eliminarli.

Dicevo prima, "carichi" diversi: infatti il giallo e' "color red 1 green 1" e
il magenta e' "color red 1 blue 1", mentre il bianco e' "color red 1 green 1
blue 1". Oops, questo significa che giallo e magenta hanno lo stesso "carico",
anch'io sono un essere umano e posso sbagliarmi :-).

Nell'esempio si vedono solo zeri e uni; sono valori in virgola mobile; volendo
infatti ottenere un "due terzi magenta" basta fare "color red 0.66 blue 0.66".
Il colore oro (occhio, il colore, non la texture) e' definito ("Gold") come
"color red 0.8 green 0.498 blue 0.196".

Terminato il rendering dell'immagine di sopra, notiamo il piccolo grave errore
di valutazione commesso poco fa: il "-4.5" era un po' troppo. Gli oggetti a
video si vedono lo stesso; sono un po' lontanucci, quindi portare un po' piu'
avanti la telecamera fara' bene; al momento sono ancora ben visibili, in
particolare le ombre. Non essendoci nessuna superficie riflettente dietro,
l'immagine e' un po' scura (infatti lo spazio 3D inizialmente e' vuoto e tutto
nero; mettere solo le luci non servirebbe a niente perche` se non riflettono
su nessun oggetto dello spazio, si "disperdono" nel vuoto.

Una volta completato questo, voglio fare una piccola modifica e commetto un
errore grossolano, aggiungendo infatti l'oggetto:

        plane  { -z, 7  texture { PinkAlabaster }  }

Con questa linea ho definito un piano che ha come normale l'asse "-z", cioe'
l'asse z pero' nella direzione del nostro occhio. In pratica avrei definito un
"pavimento" di alabastro con normale "-z=7" (vi ricordo che nel linguaggio di
POV "x", "y" e "z" sono le famose tre abbreviazioni dei vettori di base
unitari: x = <1,0,0>,  y = <0,1,0>,  z=<0,0,1>, per cui -z = <0,0,-1>).

La normale "-z = 7" (cioe' il piano z=-7), che nelle mie intenzioni doveva
essere "a quota 7", cioe' giusto dietro gli oggetti (nel senso di "molto piu'
in profondita' di loro"), e' invece andata a coprirli - col rendering mi e'
uscita una tremendissima immagine completa di alabastro, ben illuminato, ma
senza gli oggetti (che sono evidentemente andati a finire dietro) perche`,
dato che i piani si definiscono come in geometria (ax+by+cz=k), ho commesso
l'errore di piazzarlo "prima" dell'origine e non "dopo" (infatti -z=7 diventa
z=-7, cioe' "7 unita' dall'origine verso l'occhio", cioe' piu' delle 2 o 3
unita' di misura della profondita' massima degli oggetti verso il mio occhio).

Correggo dunque il piano e ne approfitto anche per correggere la visuale: dato
che mi son finalmente sprecato a misurare e a notare che gli oggetti si
estendono sull'asse y da -7 a 2 (cioe' 9 unita', cioe' il centro e' 4.5 sopra
il punto piu' basso, cioe' -7+4.5=-2.5), cambio l'errato "look_at <0, -4.5,0>"
in "look_at <0, -2.5, 0>" e ne approfitto per spostare avanti la telecamera
alla "location <0, 0, -15>". Tutti i calcoli (piano e telecamera) sono esatti
e dunque non dovrei avere problemi (vi faccio il report a fine render :-).

Prima di chiudere la "puntata" di oggi, una piccola osservazione. Gli oggetti
che abbiamo visto (sphere, cone, etc) sono tutti "finiti", mentre il piano e'
"infinito" - il che ovviamente richiede maggiore complessita' di calcolo. Per
definire altri oggetti ci sara' bisogno di mettere mano a quadriche, quartiche
ed altre cose dai nomi similmente preoccupanti. Per fortuna i pochi oggetti
che abbiamo a disposizione gia' ci permettono di fare parecchio.

----------------------------------------------------------------------------

Qualche giorno fa parlavamo di piani e di normali, vediamo un po' di chiarire.

Definito un piano, la "normale" e' quel vettore che parte dal piano e va
"normalmente" verso l'esterno (cioe' perpendicolare al piano), a cominciare
ovviamente dalla parte colorata del piano. Pare che il piano sia colorato su
entrambe le facce, per cui basta definire il vettore esatto (x, y o z, che nel
linguaggio di POV sono i vettori unitari) e poi il valore k della famigerata
equazione del piano "ax+by+cz=k". Se vogliamo infatti definire il piano
3x+2y-4z=19 ci basta usare "plane { <3,2,-4>, 19  texture { ... } }".

Se ci immaginiamo in una stanza, il pavimento e il tetto sono piani che hanno
come normale l'asse y (cioe' l'altezza della stanza; ovviamente la normale del
soffitto punta verso il basso e dunque e' negativa); le pareti sinistra e
destra hanno come normale l'asse x (cioe' la larghezza della stanza;
ovviamente la normale della destra, puntando verso sinistra, e' negativa) e le
pareti dietro di noi ed avanti a noi hanno come normale l'asse z (stesso
discorso, quella che vediamo davanti ha normale negativa perche` viene dallo
schermo verso di noi).

Il "corridoio infinito" infatti si traccia usando i quattro piani delle pareti
laterali e di soffitto e pavimento, per esempio:

    plane { x, +50   texture { xxx } }    //  parete destra
    plane { x, -50   texture { xxx } }    //  parete sinistra
    plane { y, +50   texture { xxx } }    //  soffitto
    plane { y, -50   texture { xxx } }    //  pavimento

Il mio famoso PALLINE.POV ne fa appunto uso solenne, con l'indelicatezza di
avere pareti argentate con caratteristiche spaventose (brillanza alta e
riflessione quasi a specchio). Quattro piani e cinque sfere in tutto, eppure
il tempo per il calcolo e' parecchio a causa di riflessioni e rifrazioni
pressoche` dappertutto. L'immagine in output e' luminosissima, probabilmente
per capirci qualcosa dovrete abbassare l'intensita' del colore del monitor.

   #include "colors.inc"    // PALLINE.POV, by alfmar@fantozzy
   #include "shapes.inc"    // <-- credo sia inutile
   #include "textures.inc"  // <-- credo sia inutile

   camera
   {
     location  <0, 0, 0>
     look_at   <0, 0, 9>
   }

   plane
   {
     y, 50
     pigment { color Silver }
     finish  { metallic
               ambient    0.2
               diffuse    0.1
               brilliance 8
               reflection 0.9
               phong      0.75
               phong_size 85
             }
   }

   plane
   {
     y, -50
     pigment { color Silver }
     finish  { metallic
               ambient    0.1
               diffuse    0.2
               brilliance 5
               reflection 0.7
               phong      0.75
               phong_size 30
             }
   }

   plane
   {
     x, 50
     pigment { color Silver }
     finish  { metallic
               ambient    0.3
               diffuse    0.3
               brilliance 7
               reflection 0.8
               phong      0.55
               phong_size 35
             }
   }

   plane
   {
     x, -50
     pigment { color Silver }
     finish  { metallic
               ambient    0.3
               diffuse    0.3
               brilliance 7
               reflection 0.8
               phong      0.55
               phong_size 35
             }
   }

   sphere
   {
     <0,0,10>, 3
     pigment { color Pink filter 0.4 }
     finish  { ambient    0.3
               diffuse    0.2
               reflection 0.5
               refraction 0.85
               ior        3.5
               phong      0.3
               phong_size 60
             }
   }

   sphere
   {
     <-6,-4,15>, 3
     pigment { color Pink filter 0.4 }
     finish  { ambient    0.3
               diffuse    0.2
               reflection 0.5
               refraction 0.85
               ior        3.5
               phong      0.3
               phong_size 60
             }
   }

   sphere
   {
     <6,-4,15>, 3
     pigment { color Pink filter 0.4 }
     finish  { ambient    0.3
               diffuse    0.2
               reflection 0.5
               refraction 0.85
               ior        3.5
               phong      0.3
               phong_size 60
             }
   }

   sphere
   {
     <-6,4,15>, 3
     pigment { color Pink filter 0.4 }
     finish  { ambient    0.3
               diffuse    0.2
               reflection 0.5
               refraction 0.85
               ior        3.5
               phong      0.3
               phong_size 60
             }
   }

   sphere
   {
     <6,4,15>, 3
     pigment { color Pink filter 0.4 }
     finish  { ambient    0.3
               diffuse    0.2
               reflection 0.5
               refraction 0.85
               ior        3.5
               phong      0.3
               phong_size 60
             }
   }

   sphere
   {
     <0,0,20>, 3
     pigment { color Pink filter 0.4 }
     finish  { ambient    0.3
               diffuse    0.2
               reflection 0.5
               refraction 0.85
               ior        3.5
               phong      0.3
               phong_size 60
             }
   }

   light_source { <0, -5, 30> color White  }
   light_source { <0, +5, 30> color Yellow }


// (fine --- PALLINE.POV)
Vediamo un attimo le novita' di oggi... ho definito i piani piu' o meno cosi':
   plane
   {
     y, -50
     pigment { color Silver }
     finish  { metallic
               ambient    0.1
               diffuse    0.2
               brilliance 5
               reflection 0.7
               phong      0.75
               phong_size 30
             }
   }

Anziche` una texture predefinita, ho creato una mia texture di colore argento
e di finitura "metallic". C'e' un 10% ("0.1") di luce d'ambiente gia' sopra -
luce bianca su tutto il piano, indipendentemente dalle light_source definite
piu' avanti; normalmente il comando ambient serve a dare appunto quel po' di
autoilluminazione agli oggetti per rendere piu' realistica la scena. Nel
nostro caso sarebbe addirittura superflua, dato che ho definito due
light_source e per giunta le pareti sono quasi a specchio.

Quindi c'e' il 20% di diffuse - significa che il 20% della luce che si vede
sull'oggetto (nel nostro caso il piano), viene direttamente dalle sorgenti
(light_source).

Il parametro di brillanza (che va in genere da 1 a 10) serve per variare
l'angolo di incidenza della luce. Il valore di default e' 1; le textures
metalliche in genere usano un valore 6, e piu' alto e' tale valore piu'
"brillante" sembra l'oggetto (occhio: dipende sempre da quanto le luci
riescono ad arrivarci sopra).

Infine la caratteristica finitura Phong, per cui l'oggetto assume una forma
plasticoide per cui la luce fa l'effetto "hai studiato troppo" (nel senso di:
provate, di sera, a togliervi gli occhiali e a guardare la lampada sullo
scrittoio come riflette sulle lenti... le macchioline ben precise di luce
forte, una per lente, sono lo stesso effetto che si ottiene col Phong).

Vediamo ora una delle sfere:
   sphere
   {
     <6,4,15>, 3
     pigment { color Pink filter 0.4 }
     finish  { ambient    0.3
               diffuse    0.2
               reflection 0.5
               refraction 0.85
               ior        3.5
               phong      0.3
               phong_size 60
             }
   }

Anche qui una texture "personalizzata". Il colore e' rosa, e "filtra" il 40%
della luce che gli arriva addosso. Il valore di "filter" per i colori va da 0
a 1, dove 0 significa completamente opaco e 1 significa totalmente
trasparente. Nel nostro caso meno della meta' della luce riesce a "trapassare"
l'oggetto ed andare oltre, dunque significa che ci potremo vedere attraverso.

I parametri di riflessione (effetto "specchio") e rifrazione (effetto "lente")
sono definiti in maniera barbara: riflessione al 50% (praticamente a meta'
strada tra un oggetto opaco che non riflette ed uno specchio perfetto, visto
che questo significano i valori 0 e 1 per la riflessione) e rifrazione all'85%
(ovvero l'85% della luce che va a cozzare sull'oggetto, in qualche modo
rifrange attraverso l'interno). L'indice di rifrazione (ior) e' 3.5, dunque
l'oggetto e' estremamente "denso" (ricordiamo, come da "ior.inc", che l'aria
e' 1.00003, l'acqua e' 1.33, il vetro e il diamante vanno tra 1.5 e 2.5).
Anche alle sfere ho piazzato l'effetto Phong.

Bene: cosa succedera' al rendering?

Le pareti hanno una certa brillanza; sono "a specchio" per un buon 70%
(reflection 0.7); le sfere sono un po' trasparenti (filter 0.4), specchiano
per un po' (reflection 0.5) e rifrangono parecchio la luce che le attraversa
(refraction 0.5), questo significa che a seconda dell'angolo cui vengono
colpite dalla luce, rifletteranno o rifrangeranno - in pratica su parti della
loro superficie si comporteranno come specchi (riflettendo le immagini delle
altre sfere) e su altre parti si comporteranno come se fossero di vetro (ma di
un vetro estremamente "denso", visto che ho fissato ior 3.5).

L'effetto "scalata" delle pareti credo sia dovuto all'eccessivo numero di
iterazioni richieste per la loro riflettenza; sulle sfere si vede
effettivamente qualche fascia luminosissima (tutti i punti in cui va a Phong),
le immagini di tutte le sfere (anche di quella "dietro" la sfera centrale, ma
di quella si vede soltanto una vaga "ombratura" al centro dell'immagine), e
l'effetto "guarda un po' cosa c'e' dietro" - le sfere sono talmente dense che
guardandole verso il loro centro, il centro della stanza appare esageratamente
scostato dal "vero" centro (sempre un effetto della rifrazione e della
densita').

Le altre volte avevamo utilizzato Bronze_Texture, vediamo in dettaglio come
viene definita in textures.inc:

 pigment
  {color red 0.55 green 0.47 blue 0.14
  }
 finish
  {metallic
   ambient 0.2
   diffuse 0.7
   brilliance 6
   reflection 0.25
   phong 0.75
   phong_size 80
  }

Un oggetto sara' "bronzeo" se e' colorato con 55/100 di rosso, 47/100 di verde
e 14% di blu, con finitura "metallica", 20% di luce ambientale "in arrivo",
70% di luce diffusa "in partenza", brillanza 6, 25% di riflessione (beh, i
metalli in genere non sono tanto "specchianti"), ed effetto Phong a 0.75 e di
dimensione 80 (non chiedetemi come si puo' giocare con i parametri del Phong
perche` ve lo scrivero' io quando lo capiro' :-).

Non e' ovviamente specificata rifrazione, perche` gli oggetti di metallo...
non rifrangono la luce. In particolare proprio ora nel manuale noto che si
consiglia di usare solo "refraction 0" e "refraction 1", perche` tutti i
valori intermedi non corrispondono a caratteristiche fisiche di nessun oggetto
- in effetti le sfere sopracitate, che in qualche punto hanno delle grosse
bombe di luce riflessa (Phong), in qualche altro riflettono le altre sfere, in
tutto il resto rifrangono e traspariscono, non riesco proprio ad immaginarle
(plexigass con una passatina di vernice trasparente? o una pallina di gomma
trasparente con del vetro intorno?).

Per finire, la curiosita' del giorno: vediamo cos'altro si puo' fare con il
blocco "pigment" della texture.

Se disegnate un piano, potete aggiungerci la "pavimentazione" a scacchiera o a
piastrelle esagonali; basta semplicemente scrivere:

    plane
    {
      y, 0
      pigment { checker color Red color Blue }
    }

Se volete le esagonali basta usare:
      pigment { hexagon color Red color Green color Blue }.

Il pigment e' dunque formato da una "quadrettatura" (checker) di due colori,
nel nostro caso i soliti predefiniti Red e Blue. Non abbiamo ancora fissato la
finitura, quindi possiamo ancora sbizzarrirci... provate infatti a
renderizzare un'immagine come questa:

    #include "colors.inc"
    #include "textures.inc"

    plane {   y, -15
              pigment { checker color BrightGold color Silver }
              finish  { Metal }                                       }

    sphere {   <0,0,0>, 5   texture { Bronze_Texture }   }

    light_source {   <8,8,0>    color Yellow   }
    light_source {   <-8,8,0>   color Magenta  }

    camera {   location <0, +3, -16>  look_at <0,0,0>   }


Il trucchetto sta nel fatto che la texture Gold_Texture e' definita come
   texture {   pigment { color BrightGold }   finish { Metal }   }

mentre la Silver_Texture e':
   texture {   pigment { color Silver }   finish { Metal }   }

dunque a parita' di finitura, l'effetto scacchiera meta' oro e meta' argento
e' perfetto. Sulla pallina di bronzo agiscono un paio di luci, una da "in alto
a destra" ed una da "in alto a sinistra", non troppo in profondita' altrimenti
le ombre non si vedono,mentre la telecamera e' "un po' piu' su" (+3) per poter
guardare la pallina leggermente dal basso verso l'alto.

Ora ne lancio il rendering, speriamo di non aver commesso errori grossolani
(l'ho scritto di getto un attimo prima di salvare questo messaggio).

Buon divertimento!

----------------------------------------------------------------------------

 > se staro' qui fino al 29 di luglio); penasa che sto anche facendo i
 > "compiti". Stanno uscendo cose sfiziosissime!!!

E il bello deve ancora venire...:-)

Avevo scelto per i preview la risoluzione 128x96 assumendo che li visualizzate
col Cshow (che "moltiplica" i pixel e pertanto, sia pure "a quadrettoni", ve
la fa vedere a tutto schermo). In effetti, se avete una macchina abbastanza
potente e la pazienza di aspettare qualche minuto in piu' (per le immagini
molto complesse), e' meglio provare almeno a 320x200. A 128x96 infatti si
ha uno "sgranamento" odioso dei piani con checker ed hexagon proprio a causa
della risoluzione tremendamente bassa...

A proposito di checker ed hexagon (che negli scorsi messaggi avevo applicato
solo ai piani, ma in effetti li possiamo mettere in qualsiasi pigment):
non esistono purtroppo altre alternative: o colore solido, o due colori con
il checker o tre colori con l'hexagon. La texture deve essere unica per
tutti (cioe' una volta definito il pigment si da' una riflessione per tutti
e tre i colori, una diffuse per tutti, etc). Si possono introdurre variazioni
gustose ai colori con la keyword "turbulence" seguita dal solito parametro da
0 a 1 o da un vettore che indica la direzione dove "soffia il vento"; per
esempio, renderizzate questo:

   sphere { <0,0,0>, 5
            texture { pigment { checker  color red 1  color green 1
                                turbulence 0.15                             }
                      finish  { metallic        ambient 0.9  reflection 0.8
                                refraction 0.5  diffuse 0.2                 }
                    }
          }

   camera { location <0,0,-15>  look_at <0,0,0> }

   light_source { <-10,3,-2>  color red 1 green 1 blue 1 }

In effetti il risultato con una scacchiera rossa e verde e' bruttino; con dei
colori molto vicini si dovrebbe ottenere un risultato migliore (specie se poi
"scaliamo" il colore per far diventare piu' piccola la grigliatura della
scacchiera) - nb: per colori vicini intendo intensita' vicine, cioe' per
esempio il Gray60 (grigio 60%) e il Gray65 (65%) definiti in "colors.inc".

Vediamo appunto il comando scale e qualche altro comodo comando applicabile
pressoche` a tutti gli oggetti.

plane { y,-4  pigment { checker color Red color Blue }  scale 15.5 }

La quadrettatura del piano risultera' 15.5 volte piu' grande del normale.
Con un valore inferiore a 1 si "rimpicciolisce" (nel caso sopra citato
basterebbe, a naso, circa un decimo; per esempio "scale 0.12"). Occhio:
scale in genere cambia la grandezza dell'oggetto; il piano e' infinito e
pertanto si vede "rimpicciolita" solo la quadrettatura...

Poi c'e' il comodo comando rotate:

box { <-2,-2,-2>, <2,2,2>  texture { Gold_Texture }  rotate <15,0,3> }

Significa che la box viene ruotata di 15 gradi intorno all'asse delle x
(quindi la vediamo ruotare intorno alla base del monitor), 0 gradi intorno
all'asse delle y (cioe' non ruota intorno all'altezza del monitor) e 3 gradi
sull'asse delle z (cioe' ruota intorno all'asse che va dal nostro occhio
al centro del monitor, in senso orario perche` l'angolo e' positivo).

Poi c'e' il mefitico translate:

box { <-2,-2,-2>, <2,2,2>  texture { Gold_Texture }  translate <50, 34, -15> }

Nell'esempio ho definito comodamente un cubo di lato 4, centrato sull'origine,
e poi l'ho spostato alle coordinate <50,34,15> (queste saranno le coordinate
del nuovo centro). La comodita' sta nel fatto che volendo evitare il translate
avrei dovuto scrivere, equivalentemente (ma meno comprensibilmente):

box { <48, 32, -17>, <52, 36, -13>  texture { Gold_Texture } }

Abbiamo visto fino ad oggi un po' di caratteristiche di POV:
- oggetti predefiniti (cylinder, plane...), telecamera e luci
- colorazioni (pigment e textures) e loro caratteristiche (filter, ambient...)
- altri comandi (translate, rotate...).

Vediamo ora come "comporre" nuovi oggetti utilizzando quelli predefiniti.

La prima cosa che vogliamo fare e' un cubo con un cilindro proprio al centro.
Cominciate il render di questo:

  #include "colors.inc"
  #include "textures.inc"

  plane        { z, 18
                 pigment { hexagon color Red color Green color Blue }
                 finish  { ambient 0.5  diffuse 0.5  reflection 0.7 }
               }

  intersection                         // ta-da!!!
  {
    box        { <-5,-5,-5>, <5,5,5>
                 pigment { checker color Cyan color Magenta }
                 finish  { ambient 0.2  diffuse 0.7  reflection 0.6 }
               }
    cylinder   { <0,0,-5.5>, <0,0,5.5>, 3   texture { Gold_Texture } }
  }

  camera       { location <1,-2,-17>  look_at <0,0,6>  }

  light_source { <-12,8,-5> color Yellow }

L'intersezione tra quei due oggetti significa in questo caso "togli dal primo
tutti i punti che sono nel secondo, e somma al primo cio' che rimane": cioe'
togliere dal cubo tutti i punti che formano un cilindro di raggio 3. Notate
che gli estremi del cilindro sono fuori del cubo perche` altrimenti POV si
confonderebbe (i calcoli in virgola mobile, per punti "troppo vicini" o
addirittura "uno sull'altro", sono un po' delicati; non basterebbe un Cray
a risolvere il problema). I "tappi" che avanzano, li vedremo incollati al
cubo.

Possiamo anche fare qualcosa di piu' complesso: andiamo a "sforacchiare" il
cubo, sostituendo il blocco intersection di cui sopra con:

  difference
  {
    box        { <-5,-5,-5>, <5,5,5>
                 pigment { checker color Cyan color Magenta }
                 finish  { ambient 0.2  diffuse 0.7  reflection 0.6 }
               }
    cylinder   { <-3,-3,-5.5>, <-3,-3,+5.5>, 1   texture { Mirror } }
    cylinder   { <-3,+3,-5.5>, <-3,+3,+5.5>, 1   texture { Mirror } }
    cylinder   { <+0,+0,-5.5>, <+0,+0,+5.5>, 1   texture { Mirror } }
    cylinder   { <+3,-3,-5.5>, <+3,-3,+5.5>, 1   texture { Mirror } }
    cylinder   { <+3,+3,-5.5>, <+3,+3,+5.5>, 1   texture { Mirror } }
  }

La differenza fra intersection e difference e' ovviamente nel fatto che la
prima "conserva" i punti (col criterio di: se il punto non andiamo a sottrarlo
all'oggetto, allora dev'essere comunque visualizzabile); la difference invece
va a togliere tutto e comunque. Notate che "5.5" e' un po' un sovradimensionare
il problema, sempre per il fatto che non sapremmo come andra' a finire con i
calcoli in virgola mobile... se proprio ci tenete a vedere l'effettaccio,
sostituite i 5.5 con 5 (che e' proprio la mezza grandezza del cubo) e guardate
i puntolini neri sparsi qua e la' apparentemente a casaccio.

Ah, non sarebbe male aggiungere un bel  rotate <0,0,45>  alla telecamera...
(avremmo fatto pendere la testa a sinistra, in diagonale di 45 gradi con
la colonna vertebrale :-).

Ad intersection e difference non poteva mancare come compagna l'operazione di
union (unione tra piu' oggetti). Lanciamo il render di questo:

  #include "colors.inc"
  #include "textures.inc"

  union
  {
    cylinder { <0,0,0>,     <0,4,0>,  5   }
    cone     { <0,4,0>,  5, <0,10,0>, 3   }
    cone     { <0,10,0>, 3, <0,12,0>, 4.5 }
    cylinder { <0,12,0>,    <0,14,0>, 4.5 }
    difference
    {
      sphere     { <0, 7.38562184, 0>,     8                  }
      cylinder   { <0, 14, 0>, <0, -2, 0>, 8                  }
      bounded_by { cylinder { <0, 14, 0>, <0, 15.4, 0>, 4.5 } }
    }
    bounded_by   { cylinder { <0, 0, 0>,  <0, 15.4, 0>, 5   } }
    texture      { Gold_Texture }
  }

  plane { y, -7
          pigment { hexagon color Gray45 color Gray50 color Gray55 }
          finish  { Metal }
        }

  light_source { <20,20,-10>  color White }
  light_source { <-20,10,8>   color White }

  camera { location <19,18,17> look_at <0,8,0> }

Vi confesso che l'ho prima disegnato a mano su carta quadrettata e poi sono
risalito dalle misure agli oggetti che lo compongono. Per la "difference"
citata c'e' voluta la calcolatrice - mi serviva una "fetta" della sfera che
andasse a "posarsi" proprio sopra quell'ultimo cylinder (di raggio 4.5), fetta
di una sfera che io voglio di raggio uguale a 8.

Dovevo dunque generare una sfera di raggio R=8, e da questa "tagliarci" tutta
la parte al di sotto di una circonferenza di raggio r=4.5: mi serve dunque
l'altezza della parte di sopra, che e' banalmente h=R-(R*cos(x)) dove x e'
l'angolo tale che r=R*sin(x). Risolvendo (com'e' lontano il liceo!) otteniamo:

x = arcsin(r/R)  = arcsin(4.5 / 8) = arcsin(0.5625) = "circa 34.2'"
h = R*(1-cos(x)) = 8 * (1-cos("circa 34.2'")) = "circa 1.38562184"

(la mia calcolatrice e' una Canon F-44 acquistata proprio ai primi tempi
del liceo, dunque non protestate per la scarsa precisione.

Bene, so che la fettina e' alta 1.38 e devo centrare la base a <0,14,0>, cioe'
devo mettere il centro della sfera a <0, 14+1.38...-8, 0>, cioe' a

    sphere { <0, 7.38562184, 0>,  8  }

Da qui ci devo tagliare tutta la parte sottostante alla circonferenza centrata
in <0,14,0> e di raggio almeno uguale al raggio della sfera grande, dunque ho
usato:

    difference {  sphere     { <0, 7.38562184, 0>,  8                 }
                  cylinder   { <0, 14, 0>, <0, -2, 0>, 8              }
                  texture    { Gold_Texture                           }  }

Scorrendo il manuale ho notato che e' presente un'opzione per risparmiare un
po' di tempo nei calcoli: e' la bounded_by, che serve per specificare a POV
di non preoccuparsi di fare i calcoli su tutto il gruppo di oggetti, ma solo
su uno, molto piu' semplice.

In effetti la differenza tra sfera e cilindro e' qualcosa largo al piu' quanto
la circonferenza alla base ed alto poco piu' di 1.38 in totale. Se indichiamo
a POV di controllare, durante il raytracing, solo un cilindretto alto 1.4,
risparmieremo tutti i calcoli tu tutto il resto dei punti della sfera (che
ha raggio 8, cioe' diametro 16, non dimentichiamolo!).

Questo si specifica con un blocco bounded_by:

    bounded_by { cylinder { <0,14,0>, <0,15.4,0>, 4.5 } }

che io ho messo prima della texture. Da 14 a 15.4 sono 1.4 unita' di misura,
che e' di un soffio maggiore del necessario. Il cilindro ha raggio 4.5, come
il cerchio che forma la base dello spicchio. Nel manuale di POV si suggerisce
di usare box e sphere perche` sono le primitive piu' ottimizzate; il cylinder
e' sicuramente piu' complesso di loro (ma non troppo, a dire il vero), pero'
e' pur sempre piu' semplice un cilindretto alto 1.4 che ricalcolare, per ogni
raggio che parte da ogni pixel, se va a cozzare contro la sfera, contro il
cylinder (quello grande, non quello bounding) e dunque contro la loro
difference...

Nulla ci impedisce di "boundare" anche l'unione degli oggetti, tutti
assorbibili all'interno di un cilindro di raggio 5 (che e' la massima
larghezza) e di massima altezza 15.4...

Sotto c'e' il solito pavimento metallico, sopra le solite due luci e infine
l'immancabile telecamera, tutti non troppo vicini all'oggetto per fargli fare
il gioco di luci.

Buon divertimento!

----------------------------------------------------------------------------

Ogni volta che mi preparo per l'ipotetica "ultima lezione" del corso, vengono
fuori cosucce nuove per cui rinvio l'"ultima lezione" a piu' tardi...

La domanda cruciale di oggi e': come si fa a tracciare qualche oggetto che
non sia il solito cubo o la solita sfera?

POV mette a disposizione l'utilissimo operatore "triangle": dati tre vertici,
disegnera' un triangolo nello spazio. Cosi' possiamo comporre una piramide a
base quadrata (altezza = 3, lato della base = 2) cosi':

union
{
  triangle { <0,0,0>, <2,0,0>, <1,3,1> }
  triangle { <0,0,0>, <0,0,2>, <1,3,1> }
  triangle { <2,0,2>, <0,0,2>, <1,3,1> }
  triangle { <2,0,2>, <2,0,0>, <1,3,1> }
  triangle { <0,0,0>, <0,0,2>, <2,0,2> }
  triangle { <0,0,0>, <2,0,0>, <2,0,2> }
  texture  { Gold_Texture              }
}

La base si estende da <0,0,0> a <2,0,2> (ricordate che l'asse z e' quello che
dal vostro occhio va verso l'interno dello schermo, e l'asse y e' l'altezza
dell'oggetto) - la base e' quadrata quindi bastano due triangoli a formarla
(sono gli ultimi due; i primi 4 sono le 4 facciate laterali). Il vertice e'
ovviamente <1,3,1>, cioe' proprio al centro della base (2/2=1) e ad altezza 3.
Ho usato una union per evitare di dare la texture a tutti e sei i triangoli;
l'ho data alla fine e quindi viene presa per tutti i triangoli precedenti.

Un'altra deliziosa feature e' la possibilita', da parte di POV, di aggiungere
"nebbia" all'immagine. Purtroppo non ho ancora capito con che logica si puo'
dare un'aspetto "nebbioso" all'immagine; nei miei esperimenti ho appurato che
la nebbiolina dovrebbe essere di colore sempre prossimo al grigio; una nebbia
rossa non ha in effetti molto significato.

Bastano colore e distanza:    fog { color Gray20  distance 1500 }

Significa che a distanza 1500 la nebbia sara' talmente fitta da vedere come
solo colore solido il Gray20 (grigio 20%, cioe' red 0.2, green 0.2, blue 0.2).
Dunque dal nostro occhio fino a distanza 1500 gli oggetti della scena saranno
visibili e saranno sempre piu' "annebbiati" man mano che ci si allontana dalla
telecamera.

Un altro trucchetto che ho usato spesso nei miei lavoretti e' questo: volendo
definire una stanza "finita" con meno fatica possibile, quanti plane devo
mettere in intersezione? Risposta: non c'e' bisogno di intersecare cinque o
sei plane per avere una stanza quadrata, guardate questa geniale idea, presa
pari pari da uno dei miei POV:

intersection
{
  box     { <-110, -110, -110>, <110, 110, 110> }
  box     { <-100, -100, -100>, <100, 100, 100> }
  texture { Gold_Texture }
}

Cosa ho fatto: ho definito un cubo di lato 220, centrato nell'origine, e poi
ci ho "intagliato" (tolto) dall'interno un cubo di lato 200. Cosi', piazzando
la telecamera all'interno del secondo cubo, mi ritrovero' con una stanza con
le sei pareti d'oro (che bello :-) con tutte le riflessioni del caso; basta
una luce piazzata da qualche parte e gli oggetti che piazzeremo dentro
avranno effetti deliziosi (specie se rifrangono, cioe' si fanno attraversare
dalla luce e la mandano in qualche altra direzione).

In effetti l'intersezione di sopra definisce una scatola vuota che ha come
spessore per le pareti 10 (110-100=10). Allo stesso mod si puo' fare con una
sphere: si interseca per esempio una sfera di raggio 100 con una di raggio 110
(centrate ovviamente nello stesso punto) e si da' loro la texture della stanza
(che e' circolare per cui puo' far pensare al cielo).

La volta scorsa abbiamo visto come si compongono gli oggetti a furia di union,
difference ed intersection. Ora ne costruiamo uno con tanto di bounded_by (che
in tutta onesta' pare che veramente riduca i tempi di calcolo di una buona
percentuale): il modello e' la colonna dorica illustrata a pagina 29 del libro
di Argan "Storia dell'arte italiana" (Sansoni, vol. 1); se ci fate caso, le
misure che ho usato corrispondono alle misure in millimetri della figura 27
(si', ho usato proprio la squadretta; non sono stato estremamente preciso ma
mi pare di esserci andato abbastanza vicino):

union
{
//colonna:
  cone { <0, 0, 0>, 5.5,   <0, 54.5, 0>,  4       texture { PinkAlabaster } }

//echino:
  cone { <0, 54.5, 0>,   4,   <0, 56, 0>,  5.5    texture { Red_Marble }    }
  cone { <0, 56, 0>,   5.5,   <0, 57, 0>,  5.2    texture { Red_Marble }    }

//abaco:
  box  { <-6, 57, -6>,  <6, 59, 6>                texture { White_Marble }  }

  bounded_by { box { <-6,0,-6>, <6, 59, 6> } }
}

La colonna dorica e' rastremata (cioe' va restringendosi verso l'alto
affinche` sia piu' evidente il punto dove la spinta si contrappone al peso),
per cui anziche` usare cylinder ho usato cone. Per evitare calcoli troppo
complessi (anche calcoli miei con la calcolatrice) ho evitato di aggiungerci
le scanalature; allo stesso modo l'echino non e' arrotondato come nella
realta' (in compenso l'abaco non e' circolare come appare dalla figura 27
sopracitata ma e' ben visibile nella foto 28 a pagina 31).

La base maggiore e' centrata nel punto <0,0,0>; il bounding da' un'idea esatta
delle dimensioni della colonna. Nell'esempio ho scelto tre textures senza
preoccuparmi troppo dell'effetto; con la prima versione di POV circolavano
i tre files TEXTURE*.POV che cerchero' di presentarvi i prossimi giorni (devo
riadattarli alla nuova sintassi di POV 2.2).

Inutile dire che ha funzionato tutto e subito; da qui a crearvi un colonnato
il passo e' breve, ed e' addirittura banale aggiungerci pavimento e tetto.
In particolare il tetto ha la forma di quelle vecchie case di campagna (pare
un cuneo molto schiacciato sulla base), per cui a furia di triangle si puo'
realizzare troppa fatica; in particolare ho spostato i due vertici piu' verso
l'interno in modo da avere un "tetto" piu' "casalingo" e piu' realistico (lo
vedremo dalle ombre che fara').

Ultimo passo indispensabile: per evitare di riscrivere ogni volta la colonna,
abbiamo bisogno di qualcosa che riassuma l'intera union. In effetti POV non ha
a disposizione uno strumento particolarmente potente, anche se nel nostro caso
ci ridurra' di parecchio la fatica: e' la direttiva #declare.

Questa dichiarazione:

#declare Biglia = sphere { <0,0,0>, 1  texture { Silver_Texture } }

ci permettera' di scrivere:

object { Biglia  translate <15,10,10> }  // una serie di biglie a partire
object { Biglia  translate <20,10,10> }  //   dalle coordinate <15,10,10>...
object { Biglia  translate <25,10,10> }
...

risparmandoci di riscrivere ogni volta l'intera sphere. Se l'oggetto da
definire e' alquanto complesso (come la union sopracitata), il risparmio e'
davvero notevole.

La #declare permette anche di definire texture, colori, etc, e ogni volta che
usiamo un oggetto #dichiarato possiamo sempre alterarne le caratteristiche,
ma questo lo vedremo la prossima volta.

Vediamo piuttosto com'e' venuto il tempio greco, anche con le textures di
"pietra" trovate nel chilometrico "stones.inc"...


//
//      tempio20.pov
//      25-07-95
//      alfmar@fantozzy
//

#include "colors.inc"
#include "textures.inc"
#include "stones.inc"

#declare Colonna = union                  // colonna dorica senza scanalature
{
//colonna:
  cone { <0, 0, 0>, 5.5,   <0, 54.5, 0>,  4       texture { PinkAlabaster } }

//echino:
  cone { <0, 54.5, 0>,   4,   <0, 56, 0>,  5.5    texture { Stone9 }        }
  cone { <0, 56, 0>,   5.5,   <0, 57, 0>,  5.2    texture { Stone9 }        }

//abaco:
  box  { <-6, 57, -6>,  <6, 59, 6>                texture { Stone1 }        }

  bounded_by { box { <-6,0,-6>, <6, 59, 6> } }
}

//---il tempio---------------------------------------------------------------

//stilobate:
box { <0,0,0>, <200,2,200>    texture { Stone6 } }

//architrave e trabeazione:
box { <0,61,0>, <200,69,200>  texture { Stone7 } }

//timpano:
union
{
  triangle { <0,69,0>,     <100,90,30>,  <100,69,0>   }
  triangle { <100,69,0>,   <200,69,0>,   <100,90,30>  }
  triangle { <0,69,0>,     <0,69,200>,   <100,90,30>  }
  triangle { <0,69,200>,   <100,90,170>, <100,90,30>  }
  triangle { <100,90,30>,  <100,90,170>, <200,69,0>   }
  triangle { <100,90,30>,  <200,69,200>, <200,69,0>   }
  triangle { <0,69,200>,   <100,69,200>, <100,90,170> }
  triangle { <100,69,200>, <100,90,170>, <200,69,200> }
  texture  { Red_Marble }
}

//colonnato frontale
object { Colonna  translate <010,2,010> }
object { Colonna  translate <046,2,010> }
object { Colonna  translate <082,2,010> }
object { Colonna  translate <118,2,010> }
object { Colonna  translate <154,2,010> }
object { Colonna  translate <190,2,010> }

//colonnato dietro
object { Colonna  translate <010,2,190> }
object { Colonna  translate <046,2,190> }
object { Colonna  translate <082,2,190> }
object { Colonna  translate <118,2,190> }
object { Colonna  translate <154,2,190> }
object { Colonna  translate <190,2,190> }

//colonnati laterali
object { Colonna  translate <010,2,046> }
object { Colonna  translate <190,2,046> }
object { Colonna  translate <010,2,082> }
object { Colonna  translate <190,2,082> }
object { Colonna  translate <010,2,118> }
object { Colonna  translate <190,2,118> }
object { Colonna  translate <010,2,154> }
object { Colonna  translate <190,2,154> }

//cielo
difference
{
  sphere  { <100,100,50>, 900 }
  sphere  { <100,100,50>, 800 }
  texture {
            pigment { Apocalypse }
            finish  { ambient 0.7  diffuse 0  crand 0.08 }
            scale <51,61,41>
          }
}

//lampadari, nebbia e telecamera
light_source    { <100, 50, 50>   color White                        }
light_source    { <135, 175, 20>  color DarkGreen                    }
light_source    { <85, 240, -70>  color DarkTurquoise                }
fog             { color red 0.02 green 0.03 blue 0.12  distance 2500 }
camera          { location <-50, 70, -86.66>  look_at <100,20,90>
                  rotate   <-2, 0, 5.5>                              }

---
 * Origin: All'anm'ro'nguacchiat'... sguall'riat'... chiattoooo'!!!! (91:1/1)


Particolare del rubinetto con qualche luce in più.

Ray Tracing index - send e-mail - continua (next page)