[shader] Pixelation Filter

I created a simple post processing “Pixelation” filter effect. Here are the results of a pixelized town.zip demo (with the Sky Dome shader as well):

One could combine a Posterization filter with this to get an 8-bit/16-bit retro look actually ;p
Let me know if there’s anyway to improve upon this.

Um. So ya. Here:

Pixelation.frag:

[code]uniform sampler2D m_Texture; // 0 - final scene image

varying vec2 texCoord;

uniform float m_ResX;
uniform float m_ResY;

void main()
{
vec2 uv = texCoord.xy;
vec2 coord = vec2(m_ResX * floor(uv.x / m_ResX),
m_ResY * floor(uv.y / m_ResY));

vec3 tc = texture2D(m_Texture, coord).rgb;

gl_FragColor = vec4(tc, 1.0);

}[/code]

Pixelation15.frag

[code]#import “Common/ShaderLib/MultiSample.glsllib”

in vec2 texCoord;
out vec4 fragColor;

uniform COLORTEXTURE m_Texture;
uniform float m_ResX;
uniform float m_ResY;

void main()
{
vec2 uv = texCoord.xy;
vec2 coord = vec2(m_ResX * floor(uv.x / m_ResX),
m_ResY * floor(uv.y / m_ResY));

vec3 tc = texture2D(m_Texture, coord).rgb;

gl_FragColor = vec4(tc, 1.0);

}[/code]

Pixelation.j3md

[code]MaterialDef Pixelation {

MaterialParameters {
    Int NumSamples
    Texture2D Texture
    Float ResX
    Float ResY
}

Technique {
    VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
    FragmentShader GLSL150: Shaders/Pixelation/Pixelation15.frag

    WorldParameters {
        WorldViewProjectionMatrix
    }
}

Technique {
    VertexShader GLSL110:   Common/MatDefs/Post/Post.vert
    FragmentShader GLSL110: Shaders/Pixelation/Pixelation.frag

    WorldParameters {
        WorldViewProjectionMatrix
    }
}

}[/code]

PixelationFilter.java

[code]/**

*/
public class PixelationFilter extends Filter {

private float pixelWidth, pixelHeight;
private float screenWidth, screenHeight;
private float resX, resY;


public PixelationFilter() {
	super("PixelationFilter");
}


/**
 * @see com.jme3.post.Filter#initFilter(com.jme3.asset.AssetManager, com.jme3.renderer.RenderManager,
 *      com.jme3.renderer.ViewPort, int, int)
 */
@Override
protected void initFilter(final AssetManager manager, final RenderManager renderManager, final ViewPort vp, final int w, final int h) {
	material = new Material(manager, "Shaders/Pixelation/Pixelation.j3md");
	
	screenWidth = w;
	screenHeight = h;
	
	setPixelWidth(10);  // default- 10x10 pixelation
	setPixelHeight(10);
	
	material.setFloat("ResX", resX);
	material.setFloat("ResY", resY);
}


public float getPixelWidth() { return pixelWidth; }
public void setPixelWidth(float x) {
	pixelWidth = x;
	resX = pixelWidth / screenWidth;
}


public float getPixelHeight() { return pixelHeight; }
public void setPixelHeight(float y) {
	pixelHeight = y;
	resY = pixelHeight / screenHeight;
}


/**
 * @see com.jme3.post.Filter#getMaterial()
 */
@Override
protected Material getMaterial() {
	return material;
}

}[/code]

8 Likes

Nice! If one want pixelation enabled all the time another approach would be to render the scene into a small framebuffer and then upsample it with NearestNeighbour filtering =)

I was considering doing it the upsampling method, but I need to toggle the pixelation at will, and even skew the pixelation amount dynamically. dat flexibility ^.^

wicked!!! mind if we add it to the ShaderBlow plugin? @mifth has more details

https://wiki.jmonkeyengine.org/legacy/doku.php/sdk:plugin:shaderblow

Super cool shader!
Yeah, it would be cool to add this cool shader into ShaderBlow lib. As we need to store all cool shaders in one place.
@SG57 would you like to commit into JME-Contribution your shader?

Sure I don’t mind. I like the idea of having a central “cool shader” library heh.
I’ll get around to committing it later, unless one of you get around to it first.

@SG57 said: Sure I don't mind. I like the idea of having a central "cool shader" library heh. I'll get around to committing it later, unless one of you get around to it first.

This is great! I would like to join shaders in one place so that JME has become stronger!
Can you PM to @normen your google mail so that you get the commit access?

Our project is here: Google Code Archive - Long-term storage for Google Code Project Hosting.

Just checkout it and have a look how it works. There are many examples inside of it:
https://code.google.com/p/jmonkeyplatform-contributions/source/browse/#svn%2Ftrunk%2Fshaderblowlib%2FShaderBlow%2Ftest-src%2Fcom%2Fshaderblow%2Ftest

Thank you for your contribution a lot!

I committed this to shaderblowlib on Google Code. I made a small improvement to the java code as well.

Included is a demonstration where spacebar toggles the pixelation effect.

Cheers!

3 Likes
@SG57 said: I committed this to shaderblowlib on Google Code. I made a small improvement to the java code as well.

Included is a demonstration where spacebar toggles the pixelation effect.

Cheers!

Hey cool! Thank you a lot for your cool contribution!!

@SG57 , @wezrule I saw that @nehon did some changes to filters recently:
https://code.google.com/p/jmonkeyengine/source/detail?r=10750

Should we change our filters in the same way?

The change got rid of the parallel projection camera that was used to render the full screen quad, and renders it with the scene camera using some math tricks to project it full screen.
This means that all global uniforms (g_CameraPos, g_WhateverMatrix, etc…) are now coming from the scene and not from this placeholder camera.
Before you had to pass the matrices yourself to the shader and use a custom param, now you don’t need it anymore and can use the built in global uniforms. (that was done like this in the water filter for example).

It won’t make you filters faster or more shiny…but it will make the code a bit cleaner…

1 Like
@nehon said: The change got rid of the parallel projection camera that was used to render the full screen quad, and renders it with the scene camera using some math tricks to project it full screen. This means that all global uniforms (g_CameraPos, g_WhateverMatrix, etc..) are now coming from the scene and not from this placeholder camera. Before you had to pass the matrices yourself to the shader and use a custom param, now you don't need it anymore and can use the built in global uniforms. (that was done like this in the water filter for example).

It won’t make you filters faster or more shiny…but it will make the code a bit cleaner…

Ok, thanks for explanation!

Good afternoon everyone,
I tried the pixelation filter for my creation (a Retro-3D engine with 3th person fixed camera and pre-rendered backgrounds, like first Alone in the dark chapters).
Very cool the effect, but I just want to ask for a little question.
I’ve a player (a 3D animated model, done in blender, without textures, only colored texels with materials) and I forced the scene with Anti-aliasing disabled (because I want to obtain a retro effect), but I saw that if I apply the filter, a sort of anti-aliasing is automatically applied (there is not a clear separation between “zoomed” pixels of the player and background, but they seems smoothed, like if AA is applied).

There’s any way to force a Nearest Neightbor interpolation for the entire scene rendered? (bacground image and 3d models without textures?)
I tried in the init method of the filter to call the getRenderedTexture() and set MagFilter Nearest and MinFilter to NearestNoMipMaps, but nothing changes… do you know some tricks to solve this?

Thank you very much