Questo programma simula la dinamica di un fluido non comprimibile. Nel Fluido agiscono delle forze di velocità (implementate da un campo di flusso) che alimentano delle correnti interne al fluido. Tali forze possono essere generate dall'utente muovendo il mouse nel fluido o da degli emettitori che possono essere aggiunti a piacere dall'utente.
Il simulatore, (ancora in pre beta e verrà aggiornato) mostra l'effetto che le correnti hanno su un colorante che l'utente può aggiungere nel fluido e vederlo diluirsi e spostarsi nel fluido in funzione della densità, della viscosità e di altre caratteristiche.
Ho scritto sia il codice della simulazione che traduce il modello matematico (i link ai modelli matematici e agli articoli scientifici usati sono in coda a questo post) in un algoritmo funzionante scritto in Java e eseguibile anche direttamente sul web (vedi seguito per usare il simulatore direttamente nel browser)
Ho implementato anche il codice per consentire all'utente di interaggire con la simulazione usando sia il mouse che comandi testuali. A tal scopo ho creato una classe apposita che implementa una console testuale che può essere anche usata in altri progetti (in seguito farò un post solo per la console).
Ho inoltre implementato anche diversi dipi di renderizzatori, usando il polimorfismo del linguaggio Java ho progettato una interfaccia RenderizzatoreFluido che le classi che vogliono renderizzare il fluido devono implementare (vale lo stesso anche per i ModificatoriFluido). Quelle che ho creato consentono di disegnare:
1) il colorante che si diluisce nel fluido animandosi seguendo le correnti generate sia dall'utente che da emettitori draggabbili
2)le correnti stesse sotto forma di vettori orientati nel verso della velocità del campi di fluisso che governa il fluido
2.5)le correnti visualizzate in modo raster dove il colore giallo è il massimo della velocita, e miscelazioni di colore particolari rendono graficamente l'effetto delle onde di propagazione delle forze nel fluido
3)un renderizzatore artistico mostra il colorante sotto forma di retino
Il programma è scritto in Java e di seguito potete usarne una versione per il web e in coda trovate il listato completo.
Clicca nella immaggine sottostante per fare il focus al programma.
USO:
- Muovi il mouse tenendo premuto il tasto destro per aggiungere colorante.
- Muovi il mouse tenendo premuto il tasto sinistro per aggiungere velocita e miscelare il colorante nel fluido.
Premi c Per aprire la console testuale
I comandi della console sono i seguenti:
man (apre la guida) close man (la chiude)
dens //disenga le densità del colorante
vel vet //disegna le velocità come vettori di direzione
vel sfum //disegna le velocità come sfumature di colore
ret //disegna un retino artistico
color //aggiunge un emettitore colore in posizione casuale
force //aggiunge un emettitore di forza basata sul perlinNoise
vortice //aggiunge un emettitore circolare per creare un vortice
author //mostra informazioni sull'autore
close console //chiude la console
esempio per visualizzare le velocità come vettori digita:
vel vet
e poi premi INVIO
Per disattivare il renderizzatore ridigita vel vet
NOTA: i renderizzatori vengono applicati in pila uno sull'altro quindi se ad esempio hai digitato dens e poi vel sfum il renderizzatore dens non si vedra perché starà sotto. L'ordine ideale per i renderizzatori è il seguente: dens poi vel sfum e sopra a tutti vel vet
Guida sugli emettiroti colore (comando: color), velocità (comando: force) e vortice (comando: vortice).
Questi emettitori possono essere manipolati con il mouse dopo essere stati aggiunti. Potete spostarli con il mouse usando il pulsante sinistro e potete ridimensionarli usando il pulsante destro (decrementa)<----->(incrementa).
L'emettitore colore incorpora già un emettitore forza lineare che viene abilitato se fai click sul colore e poi orienti il getto in una direzione.
L'emettitore forza usa il PerlinNoise per creare una movimento non lineare delle correnti emesse.
L'emettitore vortice crea una emettitore di forze circolari orientate verso il centro dell'emettitore che generano un effetto vortice, puoi ridimensionalro con il mouse e maggiore è il raggio maggiore è la forza attrattiva.
Alcuni ritagli schermata del programma.
Guarda un video tutorial su come si usa il simulatore: Avvia Video
Codice Sorgente:
FluidSimulation:
public class FluidSimulation implements Gi_ConsoleObserver{
public Fluido f;
Console console;
int iterazioni;
public ArrayList<DisegnatoreFluido> disegnatori=new ArrayList<DisegnatoreFluido>();
public ArrayList<AggiornatoreFluido> aggiornatori=new ArrayList<AggiornatoreFluido>();
DisegnatoreDensitaFluido disegnatoreDensita;
DisegnatoreRetinoFluido disegnatoreRetino;
DisegnatoreVelocitaFluido disegnatoreVelocitaVettoriali;
DisegnatoreVelocitaSfumateFluido disegnatoreVelocitaSfumate;
public ArrayList<String> log=new ArrayList<String>();
boolean apriGuida=false;
public FluidSimulation(float dt,float diffusione,float viscosita,int size,int scala,int iterazioni){
f=new Fluido( dt, diffusione, viscosita, size,scala);
this.iterazioni=iterazioni;
disegnatori.add((disegnatoreDensita=new DisegnatoreDensitaFluido()));
aggiornatori.add(new MousePaint());
aggiornatori.add(new EmettitoreColorante((size*scala)/2,(size*scala)/2));
aggiornatori.add(new EmettitoreForza((size*scala)/2,(size*scala)/2));
disegnatoreRetino=new DisegnatoreRetinoFluido();
disegnatoreVelocitaVettoriali=new DisegnatoreVelocitaFluido();
disegnatoreVelocitaSfumate=new DisegnatoreVelocitaSfumateFluido();
console=new Console(10,size*scala-12*13,12,10);
console.addObserver(this);
}
public void nextStep(){
f.step(iterazioni);
}
public String getName(){
return "Simulation";
}
public void disegna(){
for(DisegnatoreFluido d : disegnatori){
f.disegna(d);
}
for(AggiornatoreFluido a : aggiornatori){
f.aggiorna(a);
}
this.nextStep();
drawHelp();
}
public String analizzaComando(String command){
String messageForUser=null;
if(command.equals("ret")){
//esegui il codice del comando localmente
if(disegnatori.contains(disegnatoreRetino)){
disegnatori.remove(disegnatoreRetino);
messageForUser="render retino rimosso retype ret per aggiungerlo";
}else{
disegnatori.add(disegnatoreRetino);
messageForUser="render retino aggiunto retype ret per rimuoverlo";
}
}else if(command.equals("vel vet")){
//esegui il codice del comando localmente
if(disegnatori.contains(disegnatoreVelocitaVettoriali)){
disegnatori.remove(disegnatoreVelocitaVettoriali);
messageForUser="render velocità rimosso retype vel per aggiungerlo";
}else{
disegnatori.add(disegnatoreVelocitaVettoriali);
messageForUser="render velocità aggiunto retype vel per rimuoverlo";
}
}else if(command.equals("vel sfum")){
//esegui il codice del comando localmente
if(disegnatori.contains(disegnatoreVelocitaSfumate)){
disegnatori.remove(disegnatoreVelocitaSfumate);
messageForUser="render velocità rimosso retype vel sfum per aggiungerlo";
}else{
disegnatori.add(disegnatoreVelocitaSfumate);
messageForUser="render velocità aggiunto retype vel sfum per rimuoverlo";
}
}else if(command.equals("dens")){
//esegui il codice del comando localmente
if(disegnatori.contains(disegnatoreDensita)){
disegnatori.remove(disegnatoreDensita);
messageForUser="render densità rimosso retype dens per aggiungerlo";
}else{
disegnatori.add(disegnatoreDensita);
messageForUser="render densità aggiunto retype dens per rimuoverlo";
}
}else if(command.equals("color")){
int x=int(random(1,width-1));
int y=int(random(1,height-1));
messageForUser="Emettitore aggiunto in pos("+x+":"+y+") usa il mouse per spostarlo/ridimensionarlo/orientarlo";
//esegui il codice del comando localmente
aggiornatori.add(new EmettitoreColorante(x,y));
}else if(command.equals("force")){
int x=int(random(1,width-1));
int y=int(random(1,height-1));
messageForUser="Emettitore aggiunto in pos("+x+":"+y+") usa il mouse per spostarlo";
//esegui il codice del comando localmente
aggiornatori.add(new EmettitoreForza(x,y));
}else if(command.equals("close console")){
messageForUser="command ok. Console closing.";
//esegui il codice del comando localmente
console.deactivate();
apriGuida=false;
}else if(command.equals("man")){
messageForUser="Guida aperta. type close man per chiuderla";
//esegui il codice del comando localmente
//console.deactivate();
apriGuida=true;
//drawHelp(apriGuida);
}else if(command.equals("close man")){
messageForUser="command ok. Guida chiusa";
//esegui il codice del comando localmente
//console.deactivate();
apriGuida=false;
//drawHelp(apriGuida);
}
return messageForUser;
}
public void elabKey(char key,int keyCode){
console.elabKey(key,keyCode);
}
public void drawHelp(){
int x=1;
int y=10;
int alt=16;
pushStyle();
fill(0,0,0);
text("press c for open console and type: man for open manual",x,y);
if(key=='c'){
console.activate();
}
if(apriGuida){
pushStyle();
noStroke();
fill(0,0,255,100);
rect(x,y,500,alt*12,5,5,5,5);
fill(255,255,255);
text("Manuale Comandi Simulazione:",x,y+=alt);
text("Usa Mouse: trascina con PULSANTE DESTRO per aggiungere COLORE nel fluido",x,y+=alt);
text("Usa Mouse: trascina con PULSANTE SINISTRO per aggiungere FORZA nel fluido",x,y+=alt);
text("COMANDI TESTUALI:",x,y+=alt);
text("> close man [INVIO] chiudi la guida",x,y+=alt);
text("> close console [INVIO] chiudi console",x,y+=alt);
text("> vel vet [INVIO] abilita/disabilita renderizzatore velocità vettoriali",x,y+=alt);
text("> vel sfum [INVIO] abilita/disabilita renderizzatore velocità raster",x,y+=alt);
text("> dens [INVIO] abilita/disabilita renderizzatore densità colorante",x,y+=alt);
text("> ret [INVIO] abilita/disabilita renderizzatore artistico tipo retino",x,y+=alt);
text("> color [INVIO] aggiunge un emettitore di colori",x,y+=alt);
text("> force [INVIO] aggiunge un amettitore di forza",x,y+=alt);
text("Programmato da: GiuseppeGi < www.giuseppegi.it >",x,y+=alt);
popStyle();
}
popStyle();
console.display();
}
}
Altre classi che ho scritto il cui codice è disponibile su richiesta contattandomi:
Gi.Console
Gi.ConsoleOBserver
Gi.MouseGUI
Gi.MousePaint
Gi.EmettitoreColorante
Gi.EmettitoreForza
Gi.Fluido
Gi.DisegnatoreVelocitaSfumateFluido
Gi.DisegnatoreDensitaFluido
Gi.DisegnatoreRetinoFluido
Gi.Main
Modelli Matematici e riferimenti e riconoscimenti per lavori di ricerca su cui si basa la mia implementazione
Navier–Stokes equations
https://en.wikipedia.org/wiki/Navier%E2%80%93Stokes_equations
Jos Stam, "Fluidi stabili", SIGGRAPH 1999: Atti di conferenza di
Navier-Stokes
http://www.karlsims.com/fluid-flow.html
https://www.mikeash.com/thesis/
Comments powered by CComment