Back to shaders
Shader test bench
Dilate.fs
runnable fragment
Complete GLSL fragment shader. Stronghold runs it directly when the browser can compile it.
Code
uniform sampler2D inputImage;
uniform float intensity;
uniform float radius;
precision mediump float;
/*{
"CATEGORIES": [
"Blur"
],
"CREDIT": "by VIDVOX",
"INPUTS": [
{
"NAME": "inputImage",
"TYPE": "image"
},
{
"DEFAULT": 0,
"MAX": 1,
"MIN": 0,
"NAME": "intensity",
"TYPE": "float"
},
{
"DEFAULT": 2,
"MAX": 15,
"MIN": 1,
"NAME": "radius",
"TYPE": "float"
}
],
"ISFVSN": "2",
"PASSES": [
{
"TARGET": "firstPass"
},
{
}
]
}
*/
vec3 rgb2hsv(vec3 c);
void main()
{
// generally speaking, sample a bunch of pixels, for each sample convert color val to HSV, if luma is greater than max luma, that's the new color
vec2 tmpCoord;
float maxLuma;
vec4 maxLumaRGBColor = vec4(0.0);
vec4 sampleColorRGB;
vec4 sampleColorHSV;
if (PASSINDEX==0) {
// 5 samples on either side + the source pixel = 11 total samples
for (float i=0.; i<=float(int(radius)); ++i) {
tmpCoord = vec2(clamp(gl_FragCoord.x+i,0.,u_resolution.x), gl_FragCoord.y);
sampleColorRGB = texture2D(inputImage, (tmpCoord) / u_resolution.xy);
// if this is the first sample for this fragment, don't bother comparing- just set the max luma stuff
if (i == 0.) {
maxLuma = rgb2hsv(sampleColorRGB.rgb).b;
maxLumaRGBColor = sampleColorRGB;
}
// else this isn't the first sample...
else {
// compare, determine if it's the max luma
sampleColorRGB = mix(maxLumaRGBColor, sampleColorRGB, 1.*intensity/i);
sampleColorHSV.rgb = rgb2hsv(sampleColorRGB.rgb);
if (sampleColorHSV.b < maxLuma) {
maxLuma = sampleColorHSV.b;
maxLumaRGBColor = sampleColorRGB;
}
// do another sample for the negative coordinate
tmpCoord = vec2(clamp(gl_FragCoord.x-i,0.,u_resolution.x), gl_FragCoord.y);
sampleColorRGB = texture2D(inputImage, (tmpCoord) / u_resolution.xy);
sampleColorRGB = mix(maxLumaRGBColor, sampleColorRGB, 1.*intensity/i);
sampleColorHSV.rgb = rgb2hsv(sampleColorRGB.rgb);
if (sampleColorHSV.b < maxLuma) {
maxLuma = sampleColorHSV.b;
maxLumaRGBColor = sampleColorRGB;
}
}
}
gl_FragColor = maxLumaRGBColor;
}
else if (PASSINDEX==1) {
// 5 samples up and down + the source pixel = 11 total samples
for (float i=0.; i<=float(int(radius)); ++i) {
tmpCoord = vec2(gl_FragCoord.x, clamp(gl_FragCoord.y+i,0.,u_resolution.y));
sampleColorRGB = texture2D(firstPass, (tmpCoord) / u_resolution.xy);
// if this is the first sample for this fragment, don't bother comparing- just set the max luma stuff
if (i == 0.) {
maxLuma = rgb2hsv(sampleColorRGB.rgb).b;
maxLumaRGBColor = sampleColorRGB;
}
// else this isn't the first sample...
else {
// compare, determine if it's the max luma
sampleColorRGB = mix(maxLumaRGBColor, sampleColorRGB, 1.*intensity/i);
sampleColorHSV.rgb = rgb2hsv(sampleColorRGB.rgb);
if (sampleColorHSV.b < maxLuma) {
maxLuma = sampleColorHSV.b;
maxLumaRGBColor = sampleColorRGB;
}
// do another sample for the negative coordinate
tmpCoord = vec2(gl_FragCoord.x, clamp(gl_FragCoord.y-i,0.,u_resolution.y));
sampleColorRGB = texture2D(firstPass, (tmpCoord) / u_resolution.xy);
sampleColorRGB = mix(maxLumaRGBColor, sampleColorRGB, 1.*intensity/i);
sampleColorHSV.rgb = rgb2hsv(sampleColorRGB.rgb);
if (sampleColorHSV.b < maxLuma) {
maxLuma = sampleColorHSV.b;
maxLumaRGBColor = sampleColorRGB;
}
}
}
gl_FragColor = maxLumaRGBColor;
}
}
vec3 rgb2hsv(vec3 c) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
//vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
//vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy);
vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx);
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}