Tutorial sugli effetti speciali ed i frattali in Visual Basic

Prefazione

Allora… eccoci giunti al tutorial dei frattali e degli effetti speciali. Innanzitutto, premetto che ho deciso di scrivere questo tutorial perché le richieste su come produrre effetti speciali in VB, e/o frattali sono veramente numerose sulle mailing list, per cui… perché non aggiungere anche un tutorial su di essi nel sito dei programmatori? Ebbene, i comandi che troverete di seguito, saranno spiegati passo passo, in modo da far capire al lettore o al newbie di come possa essere facile produrre effetti speciali con circa 9 righe di codice e modellabili al punto da produrre effetti ipnotici!!! :) Ovviamente scherzo. Senza perderci in chiacchiere adesso arriviamo al dunque, sennò si fa notte (se non lo è già).

Codice modellabile

La definizione esatta di codice modellabile (da non confondere con “codice polimorfico”) è:

Per codice modellabile si intende una sequenza di istruzioni con cui si possono ottenere diversi effetti, senza aggiungere o rimuovere le istruzioni che sono in essa contenute. Ad esempio:

se io scrivo:

5 x 2 + 3 = 13

modellando così, questa operazione si ottiene:

3 x 2 + 5 = 11
oppure:

3 x 5 + 2 = 17

Questo vuol dire modellare un’istruzione. E abbiamo ottenuto 3 risultati diversi con lo scambio di 3 elementi. Nella sequenza di istruzioni che andremo ad esaminare (e che ho scoperto per caso e successivamente approfondito) potremo modellare le istruzioni in modo incredibile, perché avremo ben 9 elementi, cioè una combinazione molto ampia di risultati diversi. E’ come dire:

3 x 5 + 2 : 7 – 1 x 4 : 6 – 8 + 9 = 15.67 circa

pensate a quante soluzioni si potrebbero avere cambiando di posizione i numeri!!! La stessa cosa avviene esattamente con i frattali (io li chiamo così, ma non sono veri e propri frattali, ma effetti particolari).

Istruzioni, cicli e spiegazione dei comandi

Adesso quindi introduciamo le tanto attese istruzioni, in modo da renderci conto della loro banalità e arrivare dunque alla spiegazione dei comandi, dopo di ché andremo a vedere le modifiche possibili.

Immaginiamo di disegnare un effetto speciale su una PictureBox larga (width) 600 pixel e alta (height) 300; le istruzioni da cui sono partito sono le seguenti:

Dim i, h As Integer

For i = 0 To Picture1.Width

i = i + 14

For h = 0 To Picture1.Height

h = h + 10

Picture1.ForeColor = Picture1.ForeColor + 10

Picture1.Line (i, h) - (i, h)

Next

Next

 

Naturalmente io sono pignolo (e lo faccio anche per i newbie) e quindi non seguo il detto “le istruzioni… parlano da sole”. Prima riga:

Dim i, h As Integer

Serve a dichiarare le variabili ‘i’ e ‘h’ come ‘Integer’, ovvero come interi, che serviranno poi nel ciclo FOR -> NEXT.

For i = 0 To Picture1.Width

questo fa si che le istruzioni che succederanno questo ciclo dovranno essere ripetute tante volte quanto è il numero della lunghezza in pixel della PictureBox, che è 600 pixel, per cui le istruzioni che la seguiranno saranno ripetute 600 volte.

For h = 0 To Picture1.Height

questa è un altro ciclo FOR, e fa si che le istruzioni che lo succederanno saranno ripetute tante volte quanto è il numero dell’altezza della PictureBox, che ribadisco, è in questo esempio di 300 pixel. Le istruzioni successive saranno ripetute ben 300 volte. E questi due cicli, ovvero:

For i = 0 To Picture1.Width

For h = 0 To Picture1.Height

sono detti ‘cicli annidati’, perché sono concatenati, e alla fine, le istruzione contenute in essi saranno esattamente il prodotto tra il fattore massimo del primo ciclo e il fattore massimo del secondo. In pratica, abbiamo detto che le istruzioni che seguiranno il 1° ciclo saranno ripetute 600 volte (perché la lunghezza è 600 pixel) e le istruzioni che seguiranno il 2° ciclo saranno ripetute ben 300 volte (l’altezza è 300 pixel), quindi moltiplicando:

600 * 300 = 180.000

e quindi le istruzioni comprese in questi due cicli saranno ripetute ben 180.000 volte, che guarda caso corrispondono ai pixel totali della PictureBox. Ogni istruzione For termina quando davanti si trova l’istruzione NEXT. In questo esempio, il 1° NEXT che incontriamo, blocca il ciclo più interno, ovvero il 2° ciclo, mentre il 2° NEXT blocca il 1° ciclo. In pratica la traduzione è:

1° For i = 0 To Picture1.Width -> Per i = 0 fino al numero 600 che è la lunghezza della PictureBox

2° For h = 0 To Picture1.Height -> Per h = 0 fino al numero 300 che è l'altezza della PictureBox

quindi le istruzioni che seguono il 2° ciclo sarano ripetute 300 volte, e l’istruzione del 1° ciclo, farà in modo che quella ripetizione di 300 volte delle istruzioni che seguono il 2° ciclo, saranno ripetute 600 volte. Se non avete ancora capito… bè vi consiglio una sana cura di fosforo e di imparare ad accendere il PC :)

Dopo aver spiegato a cosa servono i cicli, osserviamo che prima del 2° ciclo, c’è un’altra istruzione, che è:

i = i + 14

A cosa servirà mai??? Dunque questo è un incremento della variabile stessa che si ripeterà fin quando ‘i’ sarà uguale a 600. Quindi è un incremento della variabile stessa del ciclo. Ad esempio:

i = 1

i = i + 14 -> 1 = (1 + 14) -> 15 ................... 15 = 15 + 14 = 29 etc. etc.

Ho inserito questa istruzione perché la ‘frattalizzazione’ o creazione dell’immagine non risultasse lenta e/o inutile, quindi ho stabilito che lo standard che non compromette l’immagine è un incremento di 14. Ma capirete dopo cosa intendo per ‘compromettere’. Passiamo avanti:

h = h + 10

è un ulteriore incremento che serve anch’esso per velocizzare la renderizzazione; è questo è un 2° standard però questo forse è più flessibile del primo.

Picture1.ForeColor = Picture1.ForeColor + 10

ed eccoci finalmente alla prima parte modellabile e che riguarda i colori dell’immagine. Questa istruzione, che definirei ‘di base’ è l’incremento del colore stesso. Voi in VB trovate colori tipo:

&H00FF8000&

Se provate a copiare la sigla del colore (esadecimale) ove voi scrivete il codice in Visual Basic, ma in una riga vuota e poi scendete sotto con il cursore, il programma ve lo traduce in numero normale, che è in questo caso il numero:

16744448

quindi a quanto avete capito, ogni colore in VB è espresso in esadecimale, e può essere considerato, in esadecimale stesso, come un numero intero in un qualsiasi ciclo, poiché il VB lo traduce. Per cui se la PictureBox ha questo colore ForeColor (da non confondere con l’opzione BackColor) a disposizione per disegnare, la PictureBox disegnerà le nostre linee e i nostri punti con questo colore (ma no!). Da notare che se il ForeColor della PictureBox, ad esempio è azzurro, e noi disegnamo una linea, se cambiamo il colore in verde e disegnamo un’altra linea, la prima linea che abbiamo disegnato, resta azzurra. Quindi tornando al discorso precedente, il colore in esadecimale è considerato come un numero normale e quindi, se assegnato ad una variabile, può essere incrementato:

Picture1.ForeColor = Picture1.ForeColor + 10 -> 16744448 = 16744448 + 10 -> 16744458 |

16744458 = 16744458 + 10 -> 16744468 <-

 

Successivamente viene l’istruzione più modellabile in assoluto e che costituisce l’istruzione principale:

Picture1.Line(i, h) - (i, h)

Voi vi chiederete… ma perché utilizzare una linea anzicché dei punti? A questa domanda vi rispondo dicendovi che innanzitutto un punto può dare solo 2 istruzioni modellabili, quindi solo 2 soluzioni (per quanto riguarda l’istruzione del punto), mentre una linea, avendo 4 punti modellabili, può avere circa 7 istruzioni modellabili diversamente e può produrre effetti speciali veramente suggestivi, e poi un punto si può rapprensentare con una linea, inserendo le stesse coordinate di X1 e Y1 al posto di X2 e Y2, perché il comando Line vi chiederà:

Picture1.Line (X1 As Single, Y1 As Single) - (X2 As Single, Y2 As Single)

Quindi se sopra c’è scritto:

Picture1.Line (i, h) - (i, h)

significa che io disegno un punto, perché X1 e X2 hanno come valore comune ‘i’ mentre Y1 e Y2 hanno ‘h’ come valore comune. Quindi da questa linea si disegna un punto.

N.d.R. = Sulla guida di VB c’è scritto che il parametro Line, che sia di un Form o di una PictureBox richiede:

(Flags As Integer, X1 As Single, Y1 As Single, X2 As Single, Y2 As Single, Color As Long)

Non so per quale motivo, ma la sintassi giusta è quella che vi ho riportato sopra, quindi quella della guida è errata.

Effetti prodotti: parte pratica

Dopo la spiegazione dei comandi, eccoci giunti alla parte pratica (che per un programmatore esperto forse era la parte più attesa). L’effetto che dovrebbe produrre è questo:

per ogni punto orizzontale della PictureBox (For i = 0 To Picture1.Width) vengono descritte delle ‘linee’ verticali da dei ‘punti’, quindi linee lunghe quanto l’altezza della PictureBox (For h = 0 To Picture1.Height), e ogni punto che descrive la linea ha un colore crescente a quello, dato, cioè se è azzurro, diventa azzurro più chiaro… poi più chiaro e infine sfocia rapidamente in un nero che volge pian piano al rosso (Picture1.ForeColor = Picture1.ForeColor + 10) e alla fine avremo un bel disegnino (se non ci arrivate con la creatività scaricatevi l’esempio che ho preparato per voi… tutto è fatto sottoforma di una funzione). Ciò che ho fatto nell’esempio che ho costruito è soltanto una piccola parte, altrimenti se mi sarei dovuto mettere di impegno, avrei fatto una ricerca mooooolto più approfondita e con questo, vi faccio una promessa, che è quella di aggiornare il tutorial ogni qualvolta scopro qualcosa di interessante e utile sull’argomento. Immaginate l’utilizzo di questi effetti… cioè… appena si apre un Form possiamo renderizzare gli effetti stessi sul form stesso (i controlli appaiono dopo la renderizzazione, tranne per le PictureBox) e poi per cancellare tutto e per evitare quindi effetti sgradevoli, possiamo benissimo fare un Refresh… il codice sarebbe questo:

Private Sub Form1_Paint()

Dim i, h As Integer

For i = 0 To Form1.Height

i = i + 14

For h = 0 To Form1.Width

Form1.ForeColor = Form1.ForeColor + 10

Form1.Line (h, i) - (i, 0)

h = h + 10

Next

Next

Form1.Refresh

End Sub

 

N.B. = L’istruzione sarà ripetuta ogni qualvolta si clicca su un pulsante del Form o ogni volta che una finestra si sovrappone al form e la renderizzazione viene ripetuta continuamente e la cosa può risultare lenta e sgradevole, per cui vale la pena operare sulla seleziona binaria (if…then…else) e quindi inserire una variabile ‘globale’ in modo che il ciclo sia eseguito solo all’avvio:

Dim a As Byte 'As Byte per occupare meno memoria

Private Sub Form1_Paint()

Dim i, h As Integer

If a = 0 Then

For i = 0 To Form1.Height

i = i + 14

For h = 0 To Form1.Width

Form1.ForeColor = Form1.ForeColor + 10

Form1.Line (h, i) - (i, 0)

h = h + 10

Next

Next

Form1.Refresh

a = 1

End If

End Sub

 

Provare per credere.

N.d.A. = Un Form e una PictureBox hanno gli stessi comandi, ossia:

Line

Circle

Point

Cls

Move

PaintPicture

PSet

Refresh

etc. etc.

Modellare le istruzioni

In questa sezione, vedremo come è possibile modellare le istruzioni che abbiamo commentato finora. Allora, la prima cosa che possiamo modellare sono proprio le variabili che passiamo all’istruzione ‘Line’. Infatti modellando quelle si sconvolge completamente l’immagine. Proviamo a commentare l’esempio precedente, cioè quello che ho consigliato per l’apertura del Form, naturalmente escludendo la precedente selezione binaria:

For i = 0 To Form1.Height

i = i + 14

For h = 0 To Form1.Width

Form1.ForeColor = Form1.ForeColor + 10

Form1.Line (h, i) - (i, 0)

h = h + 10

Next

Next

come avrete sicuramente notato, i parametri non sono più:

(i, h) - (i, h)

ma:

(h, i) - (i, 0)

e questo cambia totalmente l’immagine, anzi… crea un effetto realmente ipnotico se è ‘h’ e ‘i’ sono grandezze tipo l’intero schermo o etc… sono effetti oserei dire… magici. In pratica le linee hanno 4 coordinate:

X1, X2, Y1, Y2

Siccome ogni ‘segmento’ (non parliamo di retta), ha due estremi, X1 controlla il movimento orizzontale del 1° estremo e X2 il movimento orizzontale del 2°. Stessa cosa per Y1 che controlla il movimento verticale del 1° estremo e per Y2 che controlla il movimento verticale del 2°.

C’è da notare anche in questo esempio, che ho invertito anche le condizioni dei cicli, ovvero, ‘prima’ era:

For i = 0 To Picture1.Width

For h = 0 To Picture1.Height

Adesso invece ho scambiato Height con Width e viceversa, producendo un effetto verticale. É naturale che se io voglio ottenere effetti verticali, non solo devo invertire questi, ma anche le assegnazioni al parametro Line, e invece di passare:

(i, h) - (i, h)

passerò:

(h, i) - (h, i)

capito il concetto? E cambiando un solo parametro, dandogli 0 o un qualsiasi altro numero diverso da ‘h’ o ‘i’ potete creare effetti da angolazioni, linee impazzite, effetti ottici e molto altro.

N.B. = L’operazione di Render impedisce di cliccare su pulsanti o altri oggetti del Form, ovvero si blocca il form durante il rendering e solo quando termina il rendering potete accedere agli oggetti del form, che si stia usando PictureBox o meno.

Modellare i colori e conseguenze degli effetti

Dopo aver capito come è possibile modellare le variabili e quindi come ottenere effetti diversi e di vario tipo, passiamo ai colori, che sono la parte che caratterizzano di più gli effetti. Ora andiamo ad esaminare un effetto che non tanto attrae per la sua incredibilità, ma per la sua stranezza. Questo è il codice che andremo ad esaminare:

Dim i, h As Integer

For i = 0 To Picture1.Width

i = i + 14

For h = 0 To Picture1.Height

Randomize Timer

h = h + 10

Picture1.ForeColor = Rnd (16700000)

Picture1.Line (i, h) - (i, h)

Next

Next

e qui prepariamoci con il manuale del bravo programmatore. Dunque la prima istruzione questa volta… lasciatemelo dire… ‘si commenta da sola’, come d’altronde le altre, meno che la 5ª e la 7ª.

La prima serve a scegliere combinazioni casuali di sequenze di numeri casuali. A questo punto prendetevi un’aspirina e sedetevi cari newbie, perché il discorso è un pò complicato. Dunque iniziamo dall’inizio e procediamo per gradi. Noi sappiamo che l’operatore RANDOM indicato in Visual Basic con ‘Rnd’ serve a scegliere una sequenza di numeri casuali, cioè, se io scrivo:

a = Rnd (5)

‘a’ potrè essere 4, come potrà essere 2 o ancora 1 o 3 o 5… l’operatore Rnd sceglie un numero casuale minore o uguale al numero che noi gli passiamo. Ebbene, nonostante questo operatore scelga numeri casuali, li sceglie secondo un criterio ben definito. La sequenza che scieglierà ‘ad esempio’ può essere:

3 - 2 - 4 - 5 - 1

ma dopo aver terminato la sequenza, dopo l’1, continuerà allo stesso modo cioè:

3 - 2 - 4 - 5 - 1 .......... 3 - 2 - 4 - 5 - 1 etc. etc....

così però rischiamo di scegliere una serie semi-casuale di colori che si ripeterà. Per ovviare a questo inconveniente noi inseriamo appunto l’istruzione:

Randomize Timer

che sceglie sequenze casuali per il random. Capito il concetto, non è difficile interpretare la 7ª istruzione:

Picture1.ForeColor = Rnd (16700000)

ciò significa che il ForeColor della PictureBox sarà scelto a caso tra 16 milioni e 7 di colori e ogni pixel avrà un colore diverso o anche uguale in questo caso. Perché dico in questo caso? Perché vi spiego subito:

se inserissimo solo:

Rnd (16700000)

allora se la PictureBox ha 16700000 pixel (cosa impossibile in quanto uno schermo dovrebbe avere una risoluzione di circa 4086 x 4086 pixel… quindi un utente con un oculista miliardario), e la sequenza ha già scelto ad esempio il colore:

12

non lo risceglierà fin quando non avrà finito tutto il ciclo, quindi fin quando non avrà assegnato tutti i 16700000 milioni di colori, cosa impossibile, quindi ogni pixel avrà un colore diverso, seppur possa sembrare qulcuno uguale all’altro per l’impercettibile variazione cromatica. Mentre se io inserisco:

Randomize Timer

ogni volta che viene eseguito, la sequenza del Random cambia e ciò non toglie che nella sequenza che andrà ad eseguire successivamente possa entrarre nuovamente lo stesso colore. Quindi il Randomize Timer l’ho inserito in questo esempio per farvi capire appunto la differenza, l’uso e la funzionalità. Naturalmente se volete creare un’immagine quadrata di 16700001 pixel frattalizzata con un programma che supporta form più grandi dello schermo, e comparare i colori, potete farlo, ma… il mio pronostico l’ho fatto già… un solo pixel sarà uguale ad un altro utilzzando soltanto il Random e senza utilizzare il Randomize Timer.

Dopo aver appreso tutte le funzioni non è difficile capire che l’immagine che vi apparirà sarà come quella che vedete davanti al televisore quando bestemmiate perché non si prende il canale del film che stavate aspettando da una settimana, in prima visione TV, belli comodi sul vostro divano di casa vostra. A differenza di quello però invece di vedere come colori solo il grigio e il nero, vedrete tanti bei colori tipo il vestito di arlecchino ma ogni colore è piccolissimo… perché è un pixel.

Both comments and pings are currently closed.

Comments are closed.