2016-03-23 47 views
5

Voglio fare un effetto onda ordito in questo modo:Come creare un effetto di deformazione dell'onda nello shader?

wave1

ma posso solo creare l'onda sinusoidale normale.

Ecco il mio frammento di shader:

precision mediump float; 
varying vec2 v_texCoord; 
uniform sampler2D s_baseMap; 

vec2 SineWave(vec2 p){ 
    float pi = 3.14159; 
    float A = 0.15; 
    float w = 10.0 * pi; 
    float t = 30.0*pi/180.0; 
    float y = sin(w*p.x + t) * A; 
    return vec2(p.x, p.y+y);  
} 
void main(){ 
    vec2 p = v_texCoord; 
    vec2 uv = SineWave(p); 
    vec4 tcolor = texture2D(s_baseMap, uv); 
    gl_FragColor = tcolor; 
} 

e il risultato è il seguente:

wave2

Quindi la domanda è come deformare l'onda su una direzione specifica?

grazie.

ecco la trama origine: origin texture


aggiornamento: I distorcere asse x quando y calcolo, ma il risultato non sembra giusto.

float x = p.x + p.y*tan(-0.5); 
float y = sin(w*x + t) * A; 
return vec2(p.x, p.y+y); 

distort x axis

+0

1. si dovrebbe aggiungere anche la texture di ingresso non distorta per il test. 2. devi distorcere anche l'asse 'x' che stai calcolando' y = sin (w * p.x + t) * A; 'quindi prova a distorcere anche' x' come 'x = sin (w * p.y + t) * A; 'e può essere giocato un po 'con le costanti (con costanti separate per' x' e per 'y'). – Spektre

+0

grazie per la risposta, provo a distorcere x asix e applicare v_texCoord.y come fattore. ma il risultato non sembra giusto. – thrillerist

risposta

8

OK Ho cercato di ricreare l'effetto quindi ho usato questo come struttura:

texture

ho preso l'immagine e ridimensionarla a 512x512 quindi è potenza di 2 riempire il bordo con il nero. Siccome non condividi Vertex shader, ho creato il mio. Il GL esegue il rendering di un singolo quadrupolo <-1,+1> senza coordinate di trama o matrici solo glVertex2f() con singola 2D trama vincolata all'unità 0. Riscrivo leggermente il tuo frammento per adattarlo all'output. Inoltre ho aggiunto tx,ty uniformi per animare facilmente l'effetto con posizione del mouse <0,1> Questi sono gli shaders primo vertice:

// Vertex 
varying vec2 v_texCoord; 
void main() 
    { 
    v_texCoord=gl_Vertex.xy; 
    gl_Position=gl_Vertex; 
    } 

E poi frammento:

// Fragment 
varying vec2 v_texCoord;  // holds the Vertex position <-1,+1> !!! 
uniform sampler2D s_baseMap; // used texture unit 
uniform float tx,ty;   // x,y waves phase 

vec2 SineWave(vec2 p) 
    { 
    // convert Vertex position <-1,+1> to texture coordinate <0,1> and some shrinking so the effect dont overlap screen 
    p.x=(0.55*p.x)+0.5; 
    p.y=(-0.55*p.y)+0.5; 
    // wave distortion 
    float x = sin(25.0*p.y + 30.0*p.x + 6.28*tx) * 0.05; 
    float y = sin(25.0*p.y + 30.0*p.x + 6.28*ty) * 0.05; 
    return vec2(p.x+x, p.y+y); 
    } 

void main() 
    { 
    gl_FragColor = texture2D(s_baseMap,SineWave(v_texCoord)); 
    } 

Questo è uscita per tx=0.3477,ty=0.7812 che visivamente più o meno corrispondenze il tuo esempio:

output

come si può vedi ho aggiunto alcuni termini nelle onde sin così da ottenere anche una distorsione distorta.

Se avete la v_texCoord già nella gamma <0,1> poi ignorare il

p.x=(0.55*p.x)+0.5; 
    p.y=(-0.55*p.y)+0.5; 

o riscrivere per (in modo che lo strizzacervelli e coefficienti di rimanere come dovrebbe)

p.x=(1.1*p.x)-0.05; 
    p.y=(1.1*p.y)-0.05; 

Se si utilizza diversa consistenza (non mio), quindi è necessario ridimensionare tutti i coefficienti.

[edit1] coefficienti significato

prima ho iniziato con la vostra:

float x = sin(10.0*p.y) * 0.15; 
float y = sin(10.0*p.x) * 0.15; 

Il 0.15 è ampiezza dell'onda che sembra essere troppo grande quindi abbassarlo 0.05. Quindi 10.0 è la frequenza, maggiore è il numero più saranno le onde lungo l'asse. Per puro errore di prova & determino che dovrebbero essere 30.0 per asse ye 25.0 per asse x in modo che il numero di onde corrisponda all'output desiderato.

float x = sin(25.0*p.y) * 0.05; 
float y = sin(30.0*p.x) * 0.05; 

Dopo questo ho notato che le onde dovrebbero essere un po 'falsati quindi aggiungo dipendere sull'altro asse anche dopo qualche ritocco scoperto questa equazione:

float x = sin(25.0*p.y + 30.0*p.x) * 0.05; 
float y = sin(25.0*p.y + 30.0*p.x) * 0.05; 

dove entrambi i coefficienti sono uguali a tra gli assi (strano ma funzionante mi aspettavo che avrei bisogno di avere coefficienti diversi tra gli assi). Dopo questo è solo una questione di trovare la fase corretta per ogni asse in modo aggiungo sfasamento controllato dalla posizione del mouse (tx,ty) <0.0,1.0> così ho preso la finale:

float x = sin(25.0*p.y + 30.0*p.x + 6.28*tx) * 0.05; 
float y = sin(25.0*p.y + 30.0*p.x + 6.28*ty) * 0.05; 

Poi io gioco con il mouse (stampa la sua posizione) finché non ho avuto abbastanza vicino per abbinare l'output desiderato, che è stato quando tx=0.3477,ty=0.7812 in modo da poter codificare

float x = sin(25.0*p.y + 30.0*p.x + 6.28*0.3477) * 0.05; 
float y = sin(25.0*p.y + 30.0*p.x + 6.28*0.7812) * 0.05; 
+0

sembra abbastanza buono! puoi spiegare un po 'di matematica sull'algoritmo? perché usare questi coeffienti – thrillerist

+0

@thrillerist aggiunto ** [edit1] ** con la descrizione – Spektre

+0

grazie per l'aiuto :) a proposito, che struttura usi, puoi controllare i coefficienti in tempo reale? – thrillerist