13 #include <OpenGL/CGLMacro.h>
18 "title" :
"VuoImageBlur",
56 return (erf((x+.5)*width) - erf((x-.5)*width))/2;
72 if (shape == VuoBlurShape_Gaussian)
77 const double width = 1. / (radius * sqrt(2));
78 const double threshold = .1 / 255.;
95 pixelFloats = (
float *)malloc(
sizeof(
float) * pixelsWide);
96 for (
int i = 0; i < pixelsWide; ++i)
97 pixelFloats[i] = pixels[i];
99 else if (shape == VuoBlurShape_Linear)
107 pixelsWide = ceil(radius + 1);
112 pixelFloats = (
float *)malloc(
sizeof(
float) * pixelsWide);
113 for (
int i = 0; i < pixelsWide; ++i)
114 pixelFloats[i] = 1 - (
float)i/(radius + 1);
122 pixelsWide = ceil(radius + 1);
127 pixelFloats = (
float *)malloc(
sizeof(
float) * pixelsWide);
128 for (
int i = 0; i < pixelsWide - 1; ++i)
131 float lastPixel = radius - floor(radius);
132 if (lastPixel == 0) lastPixel = 1;
133 pixelFloats[pixelsWide - 1] = lastPixel;
136 return VuoImage_makeFromBuffer(pixelFloats, GL_LUMINANCE, pixelsWide, 1, VuoImageColorDepth_32, ^(
void *buffer){ free(pixelFloats); });
148 \n#include
"VuoGlslAlpha.glsl"
149 \n#include
"VuoGlslRandom.glsl"
150 \n#include
"VuoGlslHsl.glsl"
152 varying vec2 fragmentTextureCoordinate;
154 uniform sampler2D texture;
155 uniform sampler2D gaussianWeights;
156 uniform
float aspectRatio;
158 uniform sampler2D mask;
159 uniform
bool hasMask;
162 uniform
float height;
164 uniform
int gaussianWeightCount;
165 uniform
float quality;
167 uniform
int symmetry;
170 uniform vec2 direction;
172 float gaussianWeight(
int x)
174 return texture2D(gaussianWeights, vec2((x + .5)/
float(gaussianWeightCount), .5)).r;
177 vec4 sampleInset(vec2 uv)
181 if (uv.x < 0. || uv.y < 0. || uv.x > 1. || uv.y > 1.)
184 return VuoGlsl_sample(texture, uv);
189 vec2 uv = fragmentTextureCoordinate;
192 uv.x = (uv.x - inset/width) * width/(width -inset*2.);
193 uv.y = (uv.y - inset/height) * height/(height-inset*2.);
195 vec2 dir = direction;
202 vec4 maskColor = VuoGlsl_sample(mask, uv);
207 scale = VuoGlsl_rgbToHsl(maskColor.rgb).z;
211 int iterations = int(ceil(
float(gaussianWeightCount) * quality));
213 vec2 fuzz = vec2(0.);
216 fuzz = VuoGlsl_random2D2D(uv);
221 else if (symmetry == 2)
222 fuzz -= vec2(.5, .5);
224 fuzz *= dir * float(gaussianWeightCount) * 2. / float(1 + iterations);
227 float mixSum = gaussianWeight(0);
228 vec4 colorSum = sampleInset(uv + fuzz) * mixSum;
231 vec2 n = uv - center;
233 float dist = distance(uv, center) * direction.x * scale;
234 for (
int i = 1; i < iterations; i++)
236 int is = int(
float(i) / quality);
237 float gw = gaussianWeight(is);
241 float c = cos(
float(is)*dist);
242 float s = sin(
float(is)*dist);
243 vec2 v = vec2(n.x*c - n.y*s,
246 colorSum += sampleInset(v + center + fuzz) * gw;
252 float c = cos(-
float(is)*dist);
253 float s = sin(-
float(is)*dist);
254 vec2 v = vec2(n.x*c - n.y*s,
257 colorSum += sampleInset(v + center + fuzz) * gw;
264 for (
int i = 1; i < iterations; i++)
266 int is = int(
float(i) / quality);
267 float gw = gaussianWeight(is);
271 colorSum += sampleInset(uv + dir *
float(is) + fuzz) * gw;
277 colorSum += sampleInset(uv - dir *
float(is) + fuzz) * gw;
283 gl_FragColor = colorSum / mixSum;
292 \n#include
"VuoGlslAlpha.glsl"
293 \n#include
"VuoGlslRandom.glsl"
294 \n#include
"VuoGlslHsl.glsl"
296 varying vec2 fragmentTextureCoordinate;
298 uniform sampler2D texture;
299 uniform sampler2D gaussianWeights;
300 uniform
float aspectRatio;
302 uniform sampler2D mask;
303 uniform
bool hasMask;
306 uniform
float height;
308 uniform
float radius;
309 uniform
float quality;
311 vec4 sampleInset(vec2 uv)
315 if (uv.x < 0. || uv.y < 0. || uv.x > 1. || uv.y > 1.)
318 return VuoGlsl_sample(texture, uv);
323 vec2 uv = fragmentTextureCoordinate;
324 float delta = fwidth(uv.x) * width/2.;
327 uv.x = (uv.x - inset/width) * width/(width -inset*2.);
328 uv.y = (uv.y - inset/height) * height/(height-inset*2.);
330 float maskedRadius = radius;
333 vec4 maskColor = VuoGlsl_sample(mask, uv);
338 float maskAmount = VuoGlsl_rgbToHsl(maskColor.rgb).z;
340 maskedRadius *= maskAmount;
343 vec2 fuzz = vec2(0.);
345 fuzz = (VuoGlsl_random2D2D(uv) - vec2(.5,.5)) * (.75 - quality) * maskedRadius / vec2(width, height) / .75;
347 int pixelRadius = int(ceil(maskedRadius*quality));
348 vec4 colorSum = vec4(0.);
350 for (
int x = 0; x <= pixelRadius; ++x)
351 for (
int y = 0; y <= pixelRadius; ++y)
353 float dist = length(vec2(x,y) / quality);
354 float f =
smoothstep(maskedRadius + delta, maskedRadius - delta, dist);
356 float sx = (float(x) / quality)/width;
357 float sy = (float(y) / quality)/height;
361 s += sampleInset(uv + vec2( sx, sy) + fuzz); mixSum += f;
362 if (x > 0) { s += sampleInset(uv + vec2(-sx, sy) + fuzz); mixSum += f; }
363 if (y > 0) { s += sampleInset(uv + vec2( sx,-sy) + fuzz); mixSum += f; }
364 if (x > 0 && y > 0) { s += sampleInset(uv + vec2(-sx,-sy) + fuzz); mixSum += f; }
368 gl_FragColor = colorSum / mixSum;
396 radius *= image->scaleFactor;
403 int inset = expandBounds ? gaussianWeights->pixelsWide-1 : 0;
405 int w = image->pixelsWide + inset*2;
406 int h = image->pixelsHigh + inset*2;
408 if (shape == VuoBlurShape_Disc)
458 return bothPassesImage;
466 VuoImage VuoImage_blur(
VuoImage image,
VuoReal radius) __attribute__ ((deprecated(
"VuoImage_blur is deprecated, please use VuoImageBlur_* instead.")));
471 return VuoImageBlur_blur(ib, image, NULL, VuoBlurShape_Gaussian, radius, 1,
false);
489 radius *= image->scaleFactor;
496 int inset = expandBounds ? gaussianWeights->pixelsWide-1 : 0;
498 int w = image->pixelsWide + inset*2;
499 int h = image->pixelsHigh + inset*2;
515 cos(angle*M_PI/180) / image->pixelsWide,
516 sin(angle*M_PI/180) / image->pixelsHigh,
542 radius *= image->scaleFactor;
547 if (dispersion == VuoDispersion_Radial)
553 int inset = expandBounds ? gaussianWeights->pixelsWide-1 : 0;
555 int w = image->pixelsWide + inset*2;
556 int h = image->pixelsHigh + inset*2;