10
\$\begingroup\$

The image below shows two sprites rendered with point sampling on top of a background:

enter image description here

  • The left skull has no rotation/scaling applied to it, so every pixel matches perfectly with the background.
  • The right skull is rotated/scaled, and this results in larger pixels that are no longer axis aligned.

How could I develop a pixel shader that would render the transformed sprite on the right with axis aligned pixels of the same size as the rest of the scene?

This might be related to how sprite scaling was implemented in old games such as Monkey Island, because that's the effect I'm trying to achieve, but with rotation added.


Edit

As per kaoD's suggestions, I tried to address the problem as a post-process. The easiest approach was to render to a separate render target first (downsampled to match the desired pixel size) and then upscale it when rendering a second time. It did address my requirements above.

First I tried doing it Linear -> Point and the result was this:

enter image description here

There's no distortion but the result looks blurred and it loses most of the highlights colors. In my opinion it breaks the retro look I needed.

The second time I tried Point -> Point and the result was this:

enter image description here

Despite the distortion, I think that might be good enough for my needs, although it does look better as a still image than in motion.

To demonstrate, here's a video of the effect, although YouTube filtered the pixels out of it:

http://youtu.be/hqokk58KFmI

However, I'll leave the question open for a few more days in case someone comes up with a better sampling solution that maintains the crisp look while decreasing the amount of distortion when moving.

\$\endgroup\$
6
  • \$\begingroup\$ That's supposed to be a skull...? \$\endgroup\$
    – DeadMG
    Apr 7, 2012 at 15:48
  • \$\begingroup\$ @DeadMG An ox skull, I guess? \$\endgroup\$ Apr 7, 2012 at 15:54
  • \$\begingroup\$ Nice effect, looks better than I thought it'd look (I tried it on EXTREMELY low res and palette, 40x30 EGA.) That's pretty much the look you'll get making your own postfx shader. BTW, I doubt there's a better sampling solution that keeps the effect as you intend. NN is pretty much what gives that crisp look, any other sampling will blur the final image (just guessing anyways.) \$\endgroup\$
    – kaoD
    Apr 7, 2012 at 16:45
  • \$\begingroup\$ @kaoD But remember that I'm applying two passes. The second pass which upsamples the image will still be nearest neighbor to preserve the retro feel. But I think there might be some benefit in trying different sampling techniques for the first pass. I'm currently looking into Scale2x! \$\endgroup\$ Apr 7, 2012 at 17:00
  • \$\begingroup\$ @kaoD Nah, I give up. Changing shader parameters between each sprite call with SpriteBatch requires me to use Immediate mode, so it's not worth the trouble. I'll go with this :) \$\endgroup\$ Apr 7, 2012 at 18:07

1 Answer 1

3
\$\begingroup\$

You should apply your shader AFTER your sprite has been rotated.

If the whole scene has not been shaded yet and your sprites are actually pixelated, what you need is some kind of post-FX filter for your whole scene. Averaging regions of pixels will work ok. It's not exactly what you intend (it'll look kinda dithered when moving/rotating) but it might do the trick.

The only way to keep that retro look truthful to what you want is to actually draw your sprite rotations yourself. It has nothing to do with how scaling was implemented: the resolution was actually poor, speaking of which, did you try with extremely low resolutions? It might also do the trick and will look more natural since, well, it's actually what caused the effect you're looking after. And it's cheap! VERY cheap! In fact it'll be cheaper than what you already have (less fragment shader executions.)

The effect is ruined in your sample image because your resolution is high compared to your sprites, so it lets you see the real pixels on the scene.

\$\endgroup\$
3
  • \$\begingroup\$ Yes, I'm not using any shaders yet. It's just regular sprites with very low resolution textures, rendered with XNA's default SpriteBatch with point sampling turned on. But a post-fx might really work out. For starters, I'll try rendering with linear sampling to a render target, and then render the entire render target to the backbuffer with point sampling. \$\endgroup\$ Apr 7, 2012 at 15:06
  • \$\begingroup\$ @DavidGouveia don't miss the opportunity of undergrading your resolution. If you really want to achieve the original effect it's your best shot. If you need your high resolution (if a portion of your GFX is hi-res or you want to match native resolutions) you can still render to a low-res off-screen buffer and then paint it in your high resolution framebuffer as a full-screen quad with filtering turned off. Keep in mind you need to match aspect ratios to avoid rectangular pixels, of course. \$\endgroup\$
    – kaoD
    Apr 7, 2012 at 15:08
  • \$\begingroup\$ Check my edit :) I think it solved most of the problem, although I'm still curious if there is a better sampling solution that nearest neighbor for this problem. I'll let the question run for a while longer. \$\endgroup\$ Apr 7, 2012 at 15:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .