Magic eye

Graphical effect


Non mi assumo nessuna responsabilita' per danneggiamenti, perdita di dati o danni personali come risultato diretto o indiretto dell'uso delle informazioni contenute in queste pagine. Questo materiale e' fornito cosi' com'e' senza nessuna garanzia implicita o esplicita.


Home
Hardware
Software

Il codice
Download

Non chiedetemi perche', probabilmente non saprei rispondere, ma sono stato sempre attirato e affascinato da quegli effetti di settori circolari che ruotano attorno ad un centro comune, solitamente a velocita' diverse. Si trovano in diversi film di fantascienza: la prima apparizione, anche se in una forma leggermente diversa, e' stata in guerre stellari, un oggetto del genere si vede anche in lost in space (il film), nella sigla di alcuni telegiornali ed in vari video game; spesso rappresentano dei mirini o semplicemente sono simbolo della CPU che calcola. Non sono riuscito a trovare il loro nome ufficiale, cosi' ho deciso di battezzarli magic-eye.

Il magic-eye, in Italiano occhio magico, era una particolare valvola termoionica che veniva utilizzata nei circuiti di ricezione radio come indicatore di livello del segnale captato. Hanno preso questo nome perche' una parte della valvola si illumina, solitamente la parte illuminata ha un aspetto circolare o semicircolare, cosi' da ricordare un occhio o qualcosa di molto simile. L'apertura dell'occhio era proporzionale al livello del segnale ricevuto, cosi' da poter sintonizzare la radio in modo che l'occhio fosse il piu' aperto possibile. Col tempo sono stati sostituiti prima dagli indici analogici e in seguito da un chip del tipo: faccio tutto io, tu non ti devi preoccupare di niente.

Quindi colto dal sacro furore programmatorio ho creato il mio magic-eye; il segreto del magic-eye non risiede tanto nell'effetto grafico finale, che potrebbe essere migliorato con l'applicazione di ulteriori filtri, quanto nella sua natura: il magic-eye e' la proiezione di un array bidimensionale di pixel, ciascun pixel originale diventa uno spicchietto di settore circolare. Lo spessore della corona circolare non dipende dai pixel di partenza, ma solo dalla trasformazione, e' una proprieta' della corona stessa: ciascuna corona circolare e' la proiezione di una sola riga di pixel qualunque sia il suo spessore finale.

L'immagine sullo sfondo non deve per forza di cose essere un occhio umano, all'inizio doveva essere un'astronave; di fatto serve solo ad esaltare l'effetto scenico.

La proiezione

Il magic-eye e' basato su di una pixel map fatta di M colonne ed N righe; questa piccola bitmap viene proiettata in uno spazio curvo in cui ogni riga corrisponde ad una corona circolare divisa in M settori. Avremo quindi N corone circolari ciascuna suddivisa in M spicchi, ciascuno spicchio assume il colore del pixel originale nella pixel map. I diametri interno ed esterno e lo spessore delle corone circolari non dipendono dalla pixel map, ma solo dalle proprieta' del magic-eye stesso.

L'immagine sottostante cerca di illustrare la proiezione: le coordinate (u, v) individuano un punto nella pixel map, u rappresenta la coordinata curva lungo la corona circolare ruotando in senso orario, v individua la corona circolare, cioe' la riga nella pixel map.

projection image

La trasformazione, cioe' il magic-eye stesso, e' definita da una serie di costanti che vengono calcolate off-line, questo permette di velocizzare al massimo il processo di rendering, che in pratica non richiede calcoli matematici, anche su macchine poco performanti. Il magic-eye ha visto le prime luci su un microcontrollore, non in un personal computer. Per contro non e' possibile modificare la geometria del magic-eye run-time, ma questo, a parer mio, non e' un problema.

Il magic eye finale viene realizzato all'interno di una SDL_Surface, questo permette diversi utilizzi del magic eye stesso che potrebbe diventare ad esempio uno sprite e vagare libero per la finestra.

Non mi dilunghero' come al solito sulla demo perche' e' veramente semplice, le uniche dipendenze da soddisfare sono: la libsdl ed sdl_image.

  $ tar -zxvf sdleye-x.yy.tar.gz
  $ cd sdlete-x.yy
  $ make
  $ ./demo
      

Potete provare anche:

  $ ./demo -a 180
      

Modificare il magic eye

Il magic-eye e' definito da una serie di costanti che descrive una trasformazione da uno spazio retto ad uno spazio curvo. Sarebbe oltremodo scomodo dichiarare a mano tutto l'insieme di variabili, liste, puntatori, etc, che descrivono la trasformazione, per questo ho creato una piccola utility che genera automaticamente il magic-eye: eyemake.

  $ cd magiceye/eyemake
  $ ./eyemake -U 128 -r 60,20 -r 38,10 -r 27,4 FirstEye > ../eyemap.c
      

Questo esempio crea un magic eye chiamato FirstEye composto da 3 anelli, il primo di raggio esterno 60 pixel e spesso 20, il secondo di raggio esterno 38 pixel e spessore 10, il terzo di raggio 27 pixel e spesso 4 pixel. Non e' obbligatorio ordinare gli anelli dal piu' grande al piu' piccolo come in questo esempio, ma serve ricordare che l'ordine di dichiarazione degli anelli corrisponde all'ordine delle righe nella pixel map. Il file target deve chiamarsi eyemap.c e il file magiceye.c deve essere ricompilato dopo l'esecuzione di eyemake.

Temporizzazione e movimento

  if((SerialTimer=SDL_AddTimer(ReadInterval,TimerCallback,NULL))==NULL)
    fprintf(stderr,"SDL_AddTimer: %s\n",SDL_GetError());
      

Le righe qui sopra creano un timer che ogni ReadInterval millisecondi chiama la funzione TimerCallback(), ovviamente quest'ultima si occupera' di spostare e ridisegnare gli anelli del magic eye. Normalmente l'intervallo viene impostato a 50ms.

Dopo aver modificato opportunamente l'array lineare, l'aggiornamento del magic eye si ottiene chiamando la funzione:

  MagicEye_Update(&FirstEye ,Rotate);      
      

ATTENZIONE! La funzione MagicEye_Update() non aggiorna la finestra, aggiorna il magic-eye; questi due concetti sono ben diversi: una volta aggiornato il magic-eye (all'interno delle propria SDL_Surface) questo dovra' essere copiato all'interno della finestra. In realta', essendo lui stesso una SDL_Surface, si potrebbe pensare di manipolarlo con: filtri, effetti, trasparenze, etc, prima di visualizzarlo.

Se il magic-eye altro non e' se non la proiezione di un array lineare di pixel, allora la cosa e' semplice: per ottenere un movimento degli anelli basta produrre un movimento dei pixel. In realta' c'e' un altra possibilita' che rende il movimento degli anelli ancora piu' semplice: il secondo argomento della funzione MagicEye_Update(). Questo e' un array di interi, uno per ogni anello del magic eye, ogni intero esprime una rotazione in senso orario dell'anello corrispondente. Questa tecnica permette di ottenere movimenti solidi (senza la defomazione dell'anello stesso) senza dover manipolare la pixel map.

Per finire vi faccio notare alcuni trucchi che ho inserito in questa demo: il movimento degli enalli principali e' fluido ed abbastanza naturale, e' ottenuto attraverso un filtro ditale che smussa un segnale a gradini. Questo permette di ottenre un andamento naturale governato da concetti come l'accelerazione, lo smorzamento, la risonanza, etc. Chi fosse interessato alla descrizione di questo filtro, trova tutto il materiale qui. Inoltre ell'interno della demo e' presente un sequencer: verrebe essere uno strumento per semplificare la costruzione di sequenze di azioni non lineari, onestamente non e' semplicissimo da usare, per ora e' un esperimento...

Download

sdleye-0.02.tar.gz online documentation
sdleye-0.05.tar.gz online documentation
Fluid-0.02 online documentation

Questo sito e' stato realizzato interamente con vim.
Grazie a tutta la comunita' open source, alla free software foundation e chiunque scriva software libero.