Hi, another newbie question, I’m afraid.
I’ve created a GLSL video effect by converting some code I wrote originally in Core Image Kernel Slang (an Apple-specific 2D-only subset of GLSL). The effect is essentially a kind of pixellation effect, but operates using polar, rather than cartesian coordinates. There are some screenshots of the effect in action in this post on my blog, Machines Don’t Care.
Here’s one of the screenshots, to save you looking at the site:
This is actually the CIKernel version- the GLSL conversion actually looks slightly different, as texture samples that overshoot the image dimensions are wrapped, rather than returning black (if anyone can tell me if this can be changed without adding hugely to the complexity of the code, let me know).
As you can see, aliasing is an issue. The effect is designed to operate in realtime on video material, potentially up to HD dimensions, so it has to be as fast and efficient as possible. I wonder if anyone could recommend the best approach to smoothing things out, or tell me if such a thing would be practicable, or even possible. Is it a matter of trying to smooth jaggies in a second pass, or can the code be modified to anti-alias as the pixellation effect is created, I wonder. Any advice gratefully accepted.
Here is the Fragment Shader code I used:
// Control inputs
uniform float Angle; // range 2pi / 100000.0 to 1.0 (rounded down), exponential
uniform float AngleMin; // range -3.2 to 3.2
uniform float AngleWidth; // range 0.0 to 6.4
uniform float Radius; // range -10000.0 to 1.0
uniform float RadiusMin; // range 0.0 to 2.0
uniform float RadiusWidth; // range 0.0 to 2.0
uniform vec2 Center; // range: -1.0 to 3.0 for both axes
uniform bool HideBg;
// Texture input
uniform sampler2D Texture;
void main()
{
bool bg = false;
// Normalised texture coords
vec2 texCoord = gl_TexCoord[0].xy;
// Shift origin to texture centre
vec2 normCoord;
normCoord.x = 2.0 * texCoord.x - Center.x;
normCoord.y = 2.0 * texCoord.y - Center.y;
// Convert Cartesian to Polar coords
float r = length(normCoord);
float theta = atan(normCoord.y, normCoord.x);
// THE ACTUAL EFFECT
if (r > RadiusMin && r < (RadiusMin + RadiusWidth)) {
r = ceil(r / Radius) * Radius;
} else {
r = r;
bg = true;
}
if (theta > AngleMin && theta < (AngleMin + AngleWidth)) {
theta = floor(theta / Angle) * Angle;
} else {
theta = theta;
bg = true;
}
// Convert Polar back to Cartesian coords
normCoord.x = r * cos(theta);
normCoord.y = r * sin(theta);
// Shift origin back to bottom-left
texCoord.x = normCoord.x / 2.0 + (Center.x / 2.0);
texCoord.y = normCoord.y / 2.0 + (Center.y / 2.0);
// Output
if(bg == true && HideBg == true) {
gl_FragColor = vec4(0.0,0.0,0.0,0.0);
} else {
gl_FragColor = texture2D(Texture, texCoord);
}
}
Obviously, there’s quite a lot of extra code in there associated with controls to tweak the effect, but the effect itself is quite simple. Any advice on how to further optimise things would be very gratefully taken on board too.
Cheers!
alx