2013-08-31 18 views
8

Uczę się OpenGL ES 2.0 i chciałbym stworzyć aplikację, aby lepiej zrozumieć, jak to działa. Aplikacja ma zestaw filtrów, które użytkownik może zastosować do obrazów (wiem, nic nowego: P).Obrazy i maska ​​w OpenGL ES 2.0

Jednym z tego filtra trwa dwa obrazy i maskę i miesza dwa obrazy przedstawiające ich przez maskę (tu obraz, aby lepiej wyjaśnić, co chcę uzyskać)

enter image description here

W tej chwili Jestem bardzo zdezorientowany i nie wiem, gdzie zacząć tworzyć ten efekt. Nie mogę zrozumieć, że mam do czynienia z wieloma teksturami i wieloma FrameBufferami lub po prostu mogę pracować z jednym shaderem.

Czy masz jakąś wskazówkę, aby pomóc mi w wykonaniu tego projektu?

EDIT --------

Znalazłem ten roztwór, ale kiedy używać jako linie maski zamiast kół wynik jest naprawdę „grungy”, zwłaszcza jeśli linie są obracane.

precision highp float; 

varying vec4 FragColor; 
varying highp vec2 TexCoordOut; 

uniform sampler2D textureA; 
uniform sampler2D textureB; 
uniform sampler2D mask; 

void main(void){ 
    vec4 mask_color = texture2D(mask, TexCoordOut); 

    if (mask_color.a > 0.0){ 
     gl_FragColor = texture2D(textureA, TexCoordOut); 
    }else { 
     gl_FragColor = texture2D(textureB, TexCoordOut); 
    } 
} 

Czy lepiej używać bufora szablonu lub mieszania?

+3

BTW, nie musisz używać kanału alfa ('mask_color.a') do maskowania. Możesz użyć dowolnego innego kanału 'r',' g', 'b' iw ten sposób zaoszczędzisz pamięć GPU używając tekstury maskującej bez kanału alfa. – keaukraine

+0

@MatterGoal Może odpowiedzieć na to pytanie: http://stackoverflow.com/questions/24486729/uiimage-masking-with-gesture –

Odpowiedz

12

można zastosować maskę w jednej linii bez użycia kosztownych if:

gl_FragColor = step(0.5, vMask.r) * vColor_1 + (1.0 - step(0.5, vMask.r)) * vColor_2; 

Albo, lepiej po prostu interpolacji pomiędzy dwoma kolorami:

gl_FragColor = mix(vColor_1, vColor_2, vMask.r); 

W tym przypadku maska ​​może być wygładzony (tj. z rozmyciem Gaussa) w celu uzyskania mniejszego aliasingu. Da to bardzo dobre wyniki w porównaniu z progowaniem z jedną wartością.

+0

Czy użyć wielozakresowego, aby utworzyć rozmytą maskę? Lub sugerujesz, aby utworzyć rozmycie za pomocą tego samego modułu cieniującego? – MatterGoal

+2

Możesz utworzyć rozmycie za pomocą tego samego modułu cieniującego, wykonując kilka (tj. 5) pobrań tekstury maski i uśredniając wynik. Następnie użyj tej średniej wartości zamiast 'vMask.r''. –

+2

Tutaj znajdziesz implementację rozmycia gaussowego w cieniu fragmentu: http://xissburg.com/faster-gaussian-blur-in-glsl/ –

1

Nie ma potrzeby stosowania wielu shaderów ani framebufferów, wystarczy kilka jednostek tekstur. Po prostu użyj 3 jednostek tekstur, które są indeksowane przez te same współrzędne tekstury i użyj tekstury Maska, aby wybrać między dwoma pozostałymi teksturami. Fragment shader będzie wyglądać następująco:

uniform sampler2D uTextureUnit_1; 
uniform sampler2D uTextureUnit_2; 
uniform sampler2D uTextureMask; 
varying vec2 vTextureCoordinates; 

void main() 
{ 
    vec4 vColor_1 = texture2D(uTextureUnit_1, vTextureCoordinates); 
    vec4 vColor_2 = texture2D(uTextureUnit_2, vTextureCoordinates); 
    vec4 vMask = texture2D(uTextureMask, vTextureCoordinates); 

    if (vMask.r > 0.5) 
     gl_FragColor = vColor_1; 
    else 
     gl_FragColor = vColor_2; 
} 

Widać, że stosując trzecią jednostkę tekstur prostu zrobić test binarny na Czerwonej kanału nie jest bardzo wydajny, więc byłoby lepiej kodować maskę do kanały alfa z tekstur 1 lub 2, ale powinno to zacząć.

+0

Sugerujesz zastosowanie konkretnych ustawień do sceny w celu uzyskania idealnego rezultatu? W przypadku niektórych "nieliniowych" masek mam fatalny efekt końcowy. – MatterGoal

+2

OpenGL w szczególności nie zapewnia doskonałych wyników w pikselach, ale można poprawić jakość, zwiększając wymiary tekstur. Dla glTexParameteri(), użyj GL_LINEAR dla MAG_FILTER i MIN_FILTER. MIP_MAP pomaga tylko przy zmniejszaniu skali. – ClayMontgomery