Monthly Archives: April 2014

Rendering UI transitions on mobile

I was implementing a kind of defocus blur transition effect between two UI screens and came up with the following shader:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/// viewport resolution (in pixels) in .xy and inverse resolution in .zw
uniform vec4  u_Resolution;      
/// 0...1
uniform float u_TransitionValue; 
/// virtual pixel size
uniform float u_PixelSize;       
uniform sampler2D Texture0;     
uniform sampler2D Texture1;     
out vec4 out_FragColor;
void main(void)
{
    float T = u_TransitionValue;
    float S0 = 1.0;
    float S1 = u_PixelSize;
    float S2 = 1.0;
    // 2 segments, 1/2 each
    float Half = 0.5;
    float PixelSize = ( T < Half ) ? mix( S0, S1, T / Half ) : mix( S1, S2, (T-Half) / Half );
    vec2 D = PixelSize * u_Resolution.zw;
    vec2 UV = (gl_FragCoord.xy * u_Resolution.zw);
    // 12-tap Poisson disk coefficients:
    const int NumTaps = 12;
    vec2 Disk[NumTaps];
    Disk[0] = vec2(-.326,-.406);
    Disk[1] = vec2(-.840,-.074);
    Disk[2] = vec2(-.696, .457);
    Disk[3] = vec2(-.203, .621);
    Disk[4] = vec2( .962,-.195);
    Disk[5] = vec2( .473,-.480);
    Disk[6] = vec2( .519, .767);
    Disk[7] = vec2( .185,-.893);
    Disk[8] = vec2( .507, .064);
    Disk[9] = vec2( .896, .412);
    Disk[10] = vec2(-.322,-.933);
    Disk[11] = vec2(-.792,-.598);
    vec4 C0 = texture( Texture0, UV );
    vec4 C1 = texture( Texture1, UV );
    for ( int i = 0; i != NumTaps; i++ )
    {
        C0 += texture( Texture0, Disk[i] * D + UV );
        C1 += texture( Texture1, Disk[i] * D + UV );
    }
    C0 /= float(NumTaps+1);
    C1 /= float(NumTaps+1);
    out_FragColor = mix( C0, C1, T );
}

I get wrong results with this fragment shader on some mobile GPUs. For example, Andreno 330 on LG Nexus 5 gives just a series of shifted images instead of blur. Google Nexus 10 runs it just fine. Anyway, I will have to investigate it a bit later.