Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Esempi pratici con Adobe Pixel Bender

Dopo l'articolo introduttivo, vediamo, grazie a qualche esempio, l'uso del nuovo Adobe Pixel Bender in pratica
Dopo l'articolo introduttivo, vediamo, grazie a qualche esempio, l'uso del nuovo Adobe Pixel Bender in pratica
Link copiato negli appunti

Dopo aver introdotto alla tecnologia Pixel Bender e al relativo Toolkit offerto da Adobe, vediamo come sia possibile realizzare filtri, riempimenti e dei metodi di fusione e caricarli poi all'interno del Flash Player.

Ricordiamo che Pixel Bender prevede anche la creazione di filtri per After Effects, per cui non tutti i suoi comandi sono compatibili con il Flash Player 10, tuttavia si tratta di limitazioni non particolarmente restrittive e con i comandi a disposizone sarà comunque possibile creare una vasta quantità di filtri ed effetti perfettamente funzionanti con il Flash Player. E' bene comunque ricordare ad esempio che, all'interno del Flash Player, Pixel Bender non supporta funzioni personalizzate, array o cicli.

Nel corso dell'articolo vedremo quale sia la struttura di un effetto creato con Pixel Bender, analizzeremo alcuni comandi per la modifica dei pixel di un'immagine e creeremo alcuni semplici effetti utili a fare pratica con questo nuovo strumento.

Struttura di un filtro

Prima di analizzare un file già pronto vediamo comunque la struttura "base" di un effetto in Pixel Bender: apriamo il Pixel Bender Toolkit e dal menu File scegliamo l'opzione New kernel filter (kernel è il nome con cui viene definito ogni file creato in Pixel Bender).

Figura 1. Creazione di un nuovo kernel
Menu file del programma

Una volta scelta l'opzione vedremo che l'area dedicata al codice verrà popolata in questo modo:

<languageVersion : 1.0;>

kernel NewFilter
<namespace : "Your Namespace";
vendor : "Your Vendor";
version : 1;
description : "your description";>
{
  input image4 src;
  output pixel4 dst;

  void evaluatePixel(){
    dst = sampleNearest(src,outCoord());
  }
}

Questa è la struttura di base da cui si può partire per creare un qualsiasi effetto: la prima parte del codice indica informazioni descrittive (nome del filtro, namespace, nome dell'autore del filtro, versione e descrizione) mentre dopo la prima parentesi graffa comincia il codice vero e proprio e per prima cosa vengono dichiarate due variabili: src, di tipo image4 e dst di tipo pixel4.

Il numero 4 indica che lavoriamo con immagini e pixel a 4 canali e tali canali sono Red (Rosso), Green (Verde) Blue (Blu) e Alpha (trasparenza); come vedremo in seguito è possibile agire singolarmente su ognuno di questi canali.

Nel codice possiamo notare che mentre in Actionscript il tipo di variabile viene dichiarato così:

var nome_variabile:tipo_variabile

In Pixel Bender abbiamo questa sintassi:

tipo_variabile nome_variabile

L'ultima parte del codice è composta dalla funzione evaluatePixel: questa funzione è il "cuore" del filtro, poichè si occupa di analizzare uno per uno i pixel dell'immagine ed è all'interno di essa che possiamo modificare il pixel attualmente in esame in modo tale che l'immagine completa risulti modificata.

Il codice presente di default non fa altro che restituire il pixel in output (dst) senza alcuna modifica dato che tramite sampleNearest(src, outCoord()) ricava il pixel dall'immagine originale e lo associa direttamente alla variabile dst senza eseguirvi alcuna modifica; possiamo verificarlo caricando un'immagine (File -> Load Image 1) e premendo po' il tasto Run: vedremo che l'immagine rimarrà esattamente uguale.

Modificare i colori di un pixel

Utilizzare un filtro per lasciare l'immagine esattamente uguale non è una grande idea, per cui vediamo come sia possibile modificare un pixel prima di inviarlo all'immagine in output. Ricordiamo che agiremo sempre all'interno della funzione evaluatePixel; una nota per la stesura del codice: il punto e virgola alla fine di ogni riga è obbligatorio (differentemente da Actionscript dove invece è facoltativo).

Abbiamo visto che il comando per ricavare un pixel è sampleNearest: invece di associare il valore alla variabile dst (ovvero il pixel dell'immagine finale), associamolo ad un'altra variabile, in questo modo

pixel4 pixel = sampleNearest(src,outCoord());

A questo punto abbiamo memorizzato il pixel originale ricavato dall'immagine all'interno della variabile pixel, che è tipo pixel4. Ora è semplicissimo modificare il colore del pixel, possiamo infatti utilizzare le proprietà rgba (red, green, blue, alpha) per modificare uno o più valori. Supponiamo per esempio di voler rimuovere tutti i colori del canale rosso, basterà questo codice:

pixel.r = 0.0
dst = pixel

Da notare che abbiamo usato un numero con decimali (0.0): questo perchè tutti i numeri in Pixel Bender vanno inseriti come float, ovvero con decimali. Se inserissimo un valore senza cifre decimali Pixel Bender ci restituirebbe un errore in quanto non supporta valori di tipo int (interi) e non esegue alcuna conversione in automatico (ovvero non convertirà 1 in 1.0, ma richiede che il valore sia già dichiarato correttamente).

Figura 2. Rimozione del canale rosso da un'immagine
Esempio di effetto

Una possibilità molto interessante è l'inversione di uno o più canali, che viene resa particolarmente semplice in Pixel Bender: possiamo per esempio invertire i canali blu e verde con questo codice:

pixel.rgba = pixel.rbga

Questo codice altro non fa che associare ai canali r g b a di pixel i valori r b g a della stessa variabile (notare l'inversione tra b, blu e g, verde). Il risultato è facilmente immaginabile:

Figura 3. Inversione tra i canali verde e blu
Esempio di effetto

È anche possibile eseguire operazioni aritmetiche su uno o più canali contemporaneamente, ecco alcuni esempi:

pixel.rb = pixel.rb / 0.5 // divide i canali rosso e blu per 0.5
pixel = pixel / 0.5 // divide tutti i canali per 0.5
pixel.a /= 0.8 // divide la trasparenza per 0.8

Fondere pixel di diverse immagini

Finora abbiamo visto come eseguire operazioni sui colori dei pixel di una immagine, ma è anche possibile utilizzare due immagini per dare così vita a un filtro di fusione, così detto appunto perchè "fonde" i pixel di due immagini: partendo infatti da due foto distinte avremo come risulato un'unica immagine il cui aspetto può variare in base alle operazioni che andremo ad eseguire sui pixel delle due fonti.

Un metodo di fusione semplicissimo da creare è il Multiply, solitamente presente in tutti i programmi di grafica: tale metodo semplicemente moltiplica i pixel delle due immagini sovrapposte; ecco come possiamo ricrearlo in Pixel Bender:

<languageVersion : 1.0;>

kernel MultiplyBlend
<namespace : "com.adobe.example";
vendor : "Adobe Sytems Inc.";
version : 1;
description : "A simple multiply blend";>{
  input image4 foreground;
  input image4 background;
  output pixel4 result;
  
  void evaluatePixel(){
    pixel4 a = sampleNearest( foreground, outCoord() );
    pixel4 b = sampleNearest( background, outCoord() );
    result = a * b;
  }
}

Notiamo subito la presenza di due immagini di input, foreground e background, mentre all'interno della funzione evaluatePixel il codice è semplicissimo: viene preso un pixel da ogni immagine (a e b) e il pixel di output è il risultato della moltiplicazione tra i due. Possiamo testare un metodo di fusione nel toolkit caricando due immagini.

Figura 4. Applicazione della fusione
Esempio di effetto

Ovviamente prima di applicare la fusione possiamo modificare i pixel di una delle due immagini come abbiamo visto in precedenza, così da modificare l'effetto finale.

È possibile eseguire anche delle serie di operazioni, ad esempio è possibile ricreare il metodo di fusione Screen, che inverte i colori, li moltiplica e quindi inverte il risultato, dando quindi un risultato finale esattamente opposto al multiply.

<languageVersion : 1.0;>

kernel ScreenBlend
<namespace : "com.adobe.example";
vendor : "Adobe Systems Inc.";
version : 1;
description : "Screen blend";>
{
  input image4 foreground;
  input image4 background;
  output pixel4 result;
  
  void evaluatePixel(){
    pixel4 a = sampleNearest( background, outCoord() );
    pixel4 b = sampleNearest( foreground, outCoord() );
    result = 1.0 - (1.0 - a) * (1.0 - b);
  }
}

Figura 5. Applicazione della fusione
Esempio di effetto

Pixel Bender supporta l'uso di condizioni, è quindi possibile ottenere dei pixel diversi in base al risultato di alcune operazioni e confronti. Ad esempio possiamo controllare il valore del canale di un pixel e se questo è maggiore di un certo valore eseguire una modifica, altrimenti eseguirne un'altra. Ne è un esempio il metodo di fusione Hard Light, ricreabile con il seguente codice:

<languageVersion : 1.0;>
kernel HardLightBlend
<namespace : "com.adobe.example";
vendor : "Adobe Systems Inc.";
version : 1;
description : "Hard light blend";>
{
  input image4 foreground;
  input image4 background;
  output pixel4 result;
  void evaluatePixel(){
    pixel4 a = sampleNearest( background, outCoord() );
    pixel4 b = sampleNearest( foreground, outCoord() );
    
    float grey = (b.r + b.g + b.b)/3.0;
    
    if( grey < 0.5 ){
      result = 2.0 * a * b;
    }else{
      result = 1.0 - 2.0 * (1.0 - a) * (1.0 - b);
    }
  }
}

Come possiamo notare, dopo aver ricavato il pixel dalle due immagini viene creata la variabile grey, con valore corrispondente alla somma divisa per 3 dei canali rosso, blu e verde dell'immagine foreground; a questo punto, se tale somma è minore di 0.5, il pixel finale è dato dal risultato di pixel a* pixel b*2, altrimenti sarà dato dal risultato di 1.0 - 2.0*(1.0 - pixel a) * (1.0 - pixel b).

Usando gli if potremmo quindi rimuovere un colore dall'immagine solo quando è inferiore ad una certa soglia, ad esempio così:

pixel4 pixel = sampleNearest(src,outCoord());
if(pixel.g < .4){
  pixel.g = 0.0;
}
dst = pixel;

Utilizzare uno o più parametri

Negli esempi fatti finora abbiamo sempre operato con dei valori numerici fissi: uno degli aspetti più interessanti di un effetto solitamente è la possibilità di applicarlo in maniera più o meno "massiccia", andando ad aumentare o diminuire determinati valori.

Basandoci proprio sull'ultimo esempio, il filtro sarebbe decisamente più utile se permettesse di impostare la soglia limite sotto cui azzerare il canale verde: vediamo allora come Pixel Bender permetta di inserire dei parametri per rendere più potenti e versatili i propri effeti.

La sintassi è molto semplice:

parameter tipo nome
<
  defaultValue : tipo (valore) di default;
  minValue : tipo (valore) minimi;
  maxValue : tipo (valore) massimi;
  description : "Descrizione"
>;

Nel nostro caso possiamo impostare un parametro di questo tipo:

parameter float soglia
<
  defaultValue : float (0.3);
  minValue : float (0.0);
  maxValue : float (1.0);
  description : "Soglia sotto cui eliminare il canale";
>;

Il filtro completo avrebbe quindi questo codice

<languageVersion : 1.0;>
kernel NewFilter
<
  namespace : "it.html";
  vendor : "Html.it";
  version : 1;
  description : "Filtro di prova";
>
{
  parameter float soglia
  <
    defaultValue : float (0.3);
    minValue : float (0.0);
    maxValue : float (1.0);
    description : "Soglia sotto cui eliminare il canale";
  >;
  input image4 src;
  output pixel4 dst;
  
  void
  evaluatePixel(){
    pixel4 pixel = sampleNearest(src,outCoord());
    if(pixel.g < soglia){
      pixel.g = 0.0;
    }
    dst = pixel;
  }
}

Testando il filtro nel Toolkit noteremo come nella colonna a destra appaia il parametro soglia, con la possibilità di modificarne il valore che come abbiamo specificato avrà un range da 0.0 a 1.0.

Figura 6. Parametro all'interno del toolkit
Parametro del filtro

È possibile specificare anche più parametri, ad esempio potremmo voler impostare il valore a cui mandare il canale nel caso fosse inferiore alla soglia, basterà allora aggiungere un secondo parametro

parameter float valore
<
  defaultValue : float (0.0);
  minValue : float (0.0);
  maxValue : float (1.0);
  description : "Valore a cui mandare il canale";
>;

Figura 7. Presenza di due parametri
Parametri del filtro

Ovviamente entrambi i parametri potranno poi essere modificati e gestiti all'interno del Flash Player.

Caricare un filtro in Flash

Dopo questa breve panoramica sulle principali operazioni eseguibili con Pixel Bender, vediamo come caricare un filtro in Flash. Il filtro che useremo per il nostro test è simile a quello appena visto, ma ampliato anche ai canali rosso e blu (quindi con un totale di 6 parametri).

Una volta che un filtro soddisfa le nostre esigenze, scegliamo l'opzione Export kernel filter for Flash Player dal menu File.

Figura 8. Esportazione per il Flash Player
Esportazione del filtro

Se il nostro filtro presentasse comandi non supportati dal Flash Player verremo avvisati, altrimenti potremo salvare un file che sarà in formato pbj. Questo file dovrà essere caricato all'interno del nostro swf, operazione che possiamo eseguire o tramite il tag Embed (novità in Flash CS4, ma già presente ad esmepio in Flex) oppure tramite la classe URLLoader.

In entrambi i casi, una volta caricato il filtro potremo crearne un'istanza grazie alle nuovi classi Shader e ShaderFilter, impostarne gli eventuali parametri e associarlo ai movieclip su cui vogliamo applicarlo usando la proprietà filters.

Ecco un esempio di codice caricando il filtro tramite Embed:

// caricamento del filtro dentro all'swf
[Embed(source="FiltroTest.pbj", mimeType="application/octet-stream")]
var FiltroTestKernel:Class;
// creazione dello shader
var filtro:Shader = new Shader(new FiltroTestKernel() );
// personalizzazione dei parametri
filtro.data.sogliaRed.value = [0.3]
filtro.data.sogliaGreen.value = [1.0]
filtro.data.sogliaBlue.value = [0.5]
filtro.data.valoreRed.value = [1.0]
filtro.data.valoreGreen.value = [1.0]
filtro.data.valoreBlue.value = [1.0]
// creazione del shaderFilter
var shaderFiltro:ShaderFilter = new ShaderFilter( filtro );
// applicazione del shaderFilter al movieclip
mc.filters = [ shaderFiltro ];

Ecco invece come ottenere lo stesso risultato usando però la classe URLLoader:

// caricamento del filtro dentro all'swf
var urlRequest:URLRequest = new URLRequest( "FiltroTest.pbj" );
var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener( Event.COMPLETE, applicaFiltro );
urlLoader.load( urlRequest );

function applicaFiltro( event:Event ):void{
  urlLoader.removeEventListener( Event.COMPLETE, applicaFiltro );
  // creazione dello shader
  var filtro:Shader = new Shader(event.target.data);
  // personalizzazione dei parametri
  filtro.data.sogliaRed.value = [0.3]
  filtro.data.sogliaGreen.value = [1.0]
  filtro.data.sogliaBlue.value = [0.5]
  filtro.data.valoreRed.value = [1.0]
  filtro.data.valoreGreen.value = [1.0]
  filtro.data.valoreBlue.value = [1.0]
  // creazione del shaderFilter
  var shaderFiltro:ShaderFilter = new ShaderFilter( filtro );
  // applicazione del shaderFilter al movieclip
  mc.filters = [ shaderFiltro ];
}

Da notare che usando la sintassi con Embed, alla prima esportazione potrebbe venirci richiesto il percorso del Flex SDK: Flash CS4 lo installa di default nella cartella C:/Programmi/Adobe/Adobe Flash CS4/Common/Configuration/Actionscript 3.0/libs/, in alternativa è possibile indicare un SDK specifico.

Come detto il vantaggio dei parametri è la possibilità di variare semplicemente l'effetto: con il codice seguente ad esempio impostiamo dei parametri random per ogni volta che si fa click sullo stage.

var urlRequest:URLRequest = new URLRequest( "FiltroTest.pbj" );
var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener( Event.COMPLETE, applicaFiltro );
urlLoader.load( urlRequest );
var filtro:Shader
var shaderFiltro:ShaderFilter
function applicaFiltro( event:Event ):void{
  urlLoader.removeEventListener( Event.COMPLETE, applicaFiltro );
  filtro = new Shader(event.target.data);
  filtro.data.sogliaRed.value = [0.3]
  filtro.data.sogliaGreen.value = [1.0]
  filtro.data.sogliaBlue.value = [0.5]
  filtro.data.valoreRed.value = [1.0]
  filtro.data.valoreGreen.value = [1.0]
  filtro.data.valoreBlue.value = [1.0]
  shaderFiltro = new ShaderFilter( filtro );
  mc.filters = [ shaderFiltro ];
}

stage.addEventListener(MouseEvent.CLICK,cliccato)
function cliccato(evt:MouseEvent){
  filtro.data.sogliaRed.value = [Math.random()]
  filtro.data.sogliaGreen.value = [Math.random()]
  filtro.data.sogliaBlue.value = [Math.random()]
  filtro.data.valoreRed.value = [Math.random()]
  filtro.data.valoreGreen.value = [Math.random()]
  filtro.data.valoreBlue.value = [Math.random()]
  shaderFiltro = new ShaderFilter( filtro );
  mc.filters = [ shaderFiltro ];
}

Applicazione del filtro con parametri casuali al click del mouse

Qualora non volessimo applicare un filtro ma un effetto di fusione, non è necessario usare uno shaderFilter ma è sufficiente l'uso dello Shader, mentre per il movieclip va utilizzata la proprietà blendShader invece di filters, ecco un esempio:

[Embed(source="multiplyblend.pbj", mimeType="application/octet-stream")]
var MultiplyBlendKernel:Class;
var shader:Shader = new Shader( new MultiplyBlendKernel() );
mc.blendShader = shader;

Ti consigliamo anche