2D background sub-pixel movement

Started by
6 comments, last by Canglong 11 years, 7 months ago
Hello, I'm currently making a 2d platformer with direct3d 9 and I have a method to create large backgrounds where I load large images as a surface in system memory and then create smaller 256x256 textures from the image and then create a grid of quads and each is set to the corresponding texture. This works very well, but I want to be able to parallax scroll these backgrounds at different speeds relating to the players movement and sometimes that means moving very slow, less than a pixel per frame for example. The problem is, that leads to filtering and this will create ugly lines in the border between the textured quads. So I have to place the quadgrid pixel-perfect.
Does anyone know of a good way to display large images in their native size and use them with subpixel scolling? The images I'm using are too large too load as a single texture.
Advertisement
How exactly do you mean that only slow movement leads to filtering?

The rasterizer always rounds to integer pixel coordinates and as long as quad vertices line up perfectly with neighboring quads, you shouldn't be able to see any artifacts between triangle borders.

Perhaps it's an issue with the filtering state of your texture samplers (repeat instead of clamping)?
So in this case you'll want to emulate the filtering that would happen if your 256x256 tiles were all part of the same large texture. With linear filtering enabled, for any pixel you rasterize the resulting texture value will be a linear combination of the 4 neighboring texels. The weighting used depends on how far the pixel value is from the neighboring texels. So if you start off with one texel exactly overlapping a pixel, that one texel will get a weight of one and the 3 other texels will get a weight of zero. If you were to slide the texel to the left by one tenth of a pixel, then the texel will overlap nine tenths of the pixel. So the texel will get a weight of 0.9 and the texel to the right will get a value of 0.1. Thus you'll get a blend of those two pixels, with the blend depending on how much they overlap the pixel.

What you'll want to happen is you'll want is for your edge pixels to weighted by how much they overlap when you output them. Then you'll want to sum the results of all tiles that overlap that pixel, so that the result is the same as the bilinear filtering case. I think the easiest way to accomplish this would be use additive blending (D3DRS_SRCBLEND = D3DBLEND_ONE and D3DRS_DESTBLEND = D3DBLEND_ONE), and enable BORDER texture filtering with a border color of 0. The border filtering will cause edge pixels to get attenuated when they partially overlap, and then the additive blending will cause adjacent tiles to sum their results.I *think* this should work, although I've never tried it myself so there might be a problem that I haven't thought of.

Another possible solution would be to create a render target texture that's equal to the size of your screen + 256. You could then render all of the tiles required for the screen to that texture, except you would do it so that they're perfectly aligned to pixels. Then when you draw for real, you would render that large texture to the back buffer but offset a bit based on your scrolling. This would allow it to scroll smoothly, since you'd be filtering one large texture.
Stupid question: is antialiasing enabled? Not sure how much this'd affect the output, but whatever.

And yeah, disable all filtering you can if you're going for pixel-perfect sprites. And you can always just round the vertex positions before actually drawing if you still have issues (I had to do this with the HTML5 2D canvas for this very reason).
Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.
eppo:
You were right, I set the samplerstates to clamp and know it works, thank you very much!
I didn't express the problem clearly enough, it was not just a problem with slow movement, I just needed to be able to place the quads between pixels (not pixelperfect) and achieve exactly what MJP described but clamp did the trick.

hedgehog: What I wanted here was not pixelperfect quads since then the scrolling would be less smooth.
MJP: I also tried your method with border filtering but I still got lines at the quadborders, thanks for the reply though
MJP is still right though. Perhaps less noticeable, but if you stitch together multiple quads using different textures, you can't properly filter between two adjacent quad's border rows of pixels. The filterer doesn't have that continuity information available.
Yeah that sounds right, but It's not noticeable at all, at least not to me. It looks exactly like one large quad with one texture.

This topic is closed to new replies.

Advertisement