]> git.sesse.net Git - movit/blob - blur_effect.cpp
Fix the blur so it is much prettier, by not sampling from a mipmap in the second...
[movit] / blur_effect.cpp
1 #define GL_GLEXT_PROTOTYPES 1
2
3 #include <math.h>
4 #include <GL/gl.h>
5 #include <GL/glext.h>
6 #include <assert.h>
7
8 #include "blur_effect.h"
9 #include "util.h"
10
11 BlurEffect::BlurEffect()
12         : radius(3.0f),
13           direction(HORIZONTAL)
14 {
15         register_float("radius", (float *)&radius);
16         register_int("direction", (int *)&direction);
17 }
18
19 std::string BlurEffect::output_fragment_shader()
20 {
21         return read_file("blur_effect.frag");
22 }
23
24 void BlurEffect::set_uniforms(GLuint glsl_program_num, const std::string &prefix, unsigned *sampler_num)
25 {
26         Effect::set_uniforms(glsl_program_num, prefix, sampler_num);
27
28         // We only have 15 taps to work with, and we want that to reach out to about 2.5*sigma.
29         // Bump up the mipmap levels (giving us box blurs) until we have what we need.
30         unsigned base_mipmap_level = 0;
31         float adjusted_radius = radius;
32         float pixel_size = 1.0f;
33         while (adjusted_radius * 2.5f > 7.0f) {
34                 ++base_mipmap_level;
35                 adjusted_radius *= 0.5f;
36                 pixel_size *= 2.0f;
37         }       
38
39         // In the second pass, we do the same, but don't sample from a mipmap;
40         // that would re-blur the other direction in an ugly fashion, and we already
41         // have the vertical box blur we need from that pass.
42         //
43         // TODO: We really need to present horizontal+vertical as a unit;
44         // currently, there's really no guarantee vertical blur is the second pass.
45         if (direction == VERTICAL) {
46                 base_mipmap_level = 0;
47         }
48
49         glActiveTexture(GL_TEXTURE0);
50         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, base_mipmap_level);
51         check_error();
52
53         // FIXME
54         if (direction == HORIZONTAL) {
55                 float ps[] = { pixel_size / 1280.0f, 0.0f };
56                 set_uniform_vec2(glsl_program_num, prefix, "pixel_offset", ps);
57         } else if (direction == VERTICAL) {
58                 float ps[] = { 0.0f, pixel_size / 720.0f };
59                 set_uniform_vec2(glsl_program_num, prefix, "pixel_offset", ps);
60         } else {
61                 assert(false);
62         }
63
64         // Simple Gaussian weights for now.
65         float weight[15], total = 0.0f;
66         for (unsigned i = 0; i < 15; ++i) {
67                 float z = (i - 7.0f) / adjusted_radius;
68                 weight[i] = exp(-(z*z));
69                 total += weight[i];
70         }
71         printf("[mip level %d] ", base_mipmap_level);
72         for (unsigned i = 0; i < 15; ++i) {
73                 weight[i] /= total;
74                 printf("%f ", weight[i]);
75         }
76         printf("\n");
77         set_uniform_float_array(glsl_program_num, prefix, "weight", weight, 15);
78 }