How to (efficiently) make an image pixelated?

I’m trying to write a “Retro Filter” image effect.

Basically I have two steps for now.

  1. Make the image pixelated
  2. Reduce the amount of different colors in the image

For step 2 I’m using a simple shader I wrote that shrinks down the amount of possible colors But step 1 doesn’t work. You know how a picture gets very pixelated and “blocky” when you scale it down and up again in an image editing program (Photoshop, Gimp, Paint, etc.)?
That’s exactly what I was looking for. So, I decided to scale the Image down and up again in OnRenderImage. The code for that looks like this:

RenderTexture scaleBuffer = RenderTexture.GetTemporary(source.width / DownscaleFactor, source.height / DownscaleFactor);

accumTexture.MarkRestoreExpected();
Graphics.Blit(accumTexture, scaleBuffer);
Graphics.Blit(scaleBuffer, accumTexture);
RenderTexture.ReleaseTemporary(scaleBuffer);

I assumed that would exactly do what I want. But instead of feeling blocky, it looks very washed out. Here you can see it with DownscaleFactor set to 8:
Result with factor 8

"Ok, that looks a bit washed out but it surely will get better if I scale it down even more and then back up again! At least that’s what i was thinking. But this is what happens when I set DownscaleFactor to 32: Result with factor 32

I have no Idea why this is happening. I tried turning AA off everywhere I could, including setting the AA level of the RenderTexture objects to 1.

I’d be ever so grateful if someone could tell me why this is happening, what I can do about it or what else would work to get the picture all blocky. I’m sure a shader might work but the shader I wrote for reducing the colors was my first shader ever and I’m just about to learn the basics. I have no idea how to go about writing a “pixeling” shader and the down- and upscale approach felt very intuitive to me.

Thank you very much for your help!

3 Answers

3

Your problem is the filtermode of your texture. You should set it to “point”.

Correct, I just started up Unity to check my answer and it's indeed the Point filter mode.

@cherno - so please mark this as the correct answer.

Don’t think I’ve ever done this, but could you have the shader round the texture coords to the nearest 1/100th? Something like: IN.uv.x = (frac(IN.uv.x/100)*100; (same for y, unless frac is a vector operation.)

Then get fancy and have the 100 be a uniform var, if that works.

Thanks for this idea! Now that I read it, it fells so simple and obvious it almost makes me want to bang my head against my desk. How could I not see this? I was way overthinking it. Even though I got it working now, I'll also try out your idea out of curiosity and to get some more practice with shaders. Also, I'll upvote you as soon as I have enough karma to do so. Sadly, I can't at the moment even though your idea's great.

I think it’s not about the AA, but about the Anisotropic Filtering that is on by default and can’t be disabled as far as I know, at least not for normal model textures.

Edit: I confused AF with Bilninear Filtering, my bad.

[Anisotropic Filtering][1] is just a special kind of mip-mapping which only applies when viewing a surface at a low angle. Since he's blotting the textures the angle will always be 0. So AF has no effect here. [1]: http://en.wikipedia.org/wiki/Anisotropic_filtering

Correct, I mixed it up with Bilinear Filtering, thanks for the note :)