2016-03-23 4 views
5

Я хочу, чтобы сделать эффект волны деформации, как это:Как сделать эффект волновой деформации в шейдере?

wave1

Но я могу только создать нормальную синусоиду.

Вот мой пиксельный шейдер:

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; 
} 

и результат:

wave2

Таким образом, вопрос в том, как деформировать волну на определенном направлении?

спасибо.

здесь происхождение текстуры: origin texture


обновление: Я искажают ось х, когда вычислить у, но результат кажется не правильно.

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. вы должны также добавить неискаженную входную текстуру для тестирования. 2. вам нужно исказить также ось 'x', которую вы вычисляете: y = sin (w * p.x + t) * A; 'поэтому попробуйте исказить также' x' как 'x = sin (w * p.y + t) * A; 'и может быть немного бит с константами (с отдельными константами для' x' и для 'y'). – Spektre

+0

спасибо за ответ, я пытаюсь исказить x asix и применять v_texCoord.y как фактор. но результат кажется неправильным. – thrillerist

ответ

8

OK Я пытался воссоздать свой эффект, так что я использовал это в качестве текстуры:

texture

я взял изображение и изменить его размер, чтобы 512x512 поэтому мощность 2 заполните границу черным. Поскольку вы не используете шейдер Vertex, я создал свой собственный. GL представляет собой однокамерный квадрат <-1,+1> без текстурных координат или матриц glVertex2f() с одним 2D текстура, привязанная к единице 0. Я немного переписываю фрагмент, чтобы он соответствовал выходу. Также я добавил tx,ty формы, чтобы легко анимировать эффект с позицией мыши <0,1> Вот шейдер первой вершины:

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

И тогда фрагмент:

// 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)); 
    } 

Это выход для tx=0.3477,ty=0.7812, который визуально более или менее матчи ваш пример:

output

Как вы можете см. Я добавил несколько терминов в грешные волны, чтобы получить искаженное искажение.

Если у вас есть v_texCoord уже в диапазоне <0,1> затем игнорировать

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

или переписать его (так усадку и коэффициенты остаться как должны)

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

Если вы используете другую текстуру (не мой), тогда вам нужно перемасштабировать все коэффициенты.

[edit1] коэффициенты означая

первым я начал с вашими:

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

волна амплитуда 0.15 есть что кажется слишком большой, так что я опускаю его 0.05. Тогда 10.0 - это частота, которая больше, чем больше волн вдоль оси. Чистым испытанием & ошибка. Я определяю, что они должны быть 30.0 для оси y и 25.0 для оси x, поэтому количество волн соответствует вашему желаемому выходу.

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

После этого я заметил, что волны должны быть немного смещены, чтобы добавить зависимость от другой оси тоже после некоторые настройки выяснили это уравнение:

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; 

, где оба коэффициента одинаковы в между осями (странно, но работая, я ожидал, что мне нужно будет иметь разные коэффициенты между осями). После того, как это просто вопрос о нахождении правильного фазы для каждой оси, так что я добавить сдвиг фазы контролируемую положение мыши (tx,ty) <0.0,1.0> таким образом я получил окончательный:

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; 

Тогда я играю с мышью (печать свою позицию), пока я не получил достаточно близко, чтобы они соответствовали вашему желаемому результату, который был когда tx=0.3477,ty=0.7812 так что вы можете жестко закодировать

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

это выглядит довольно хорошо! можете ли вы объяснить некоторую математику об алгоритме? зачем использовать эти коэффициенты – thrillerist

+0

@thrillerist добавлен ** [edit1] ** с описанием – Spektre

+0

спасибо за помощь :) кстати, какие рамки вы используете, можете ли вы контролировать коэффициенты в реальном времени? – thrillerist

Смежные вопросы