Sign in to follow this  
_Flecko

Pixel-perfect scaling

Recommended Posts

_Flecko    196
I'm working on the finer details of my 2D library (http://www.flecko.net/trans2d) and one of them is getting pixel-perfect display of textures on screen for when it really matters - it might not be that important in-game, but for UI sharp imagery matters. I've read on mapping texels to pixels, and (thanks to a suggestion from someone who was using the library) have implemented an elegant solution to that problem by offsetting texture coordinates on all vertices by (0.5,0.5). I've encountered another similar problem, though: pixel-perfect scaling. My library uses textured quads, and generally you put lots of different textures in a single image file so that you can render a ton of distinct objects all in one shot. A common thing to do in something like UI systems would be to take a very tiny texture, perhaps only a pixel high or wide, for something like an edge to a window or the middle of a button and scale it out to produce the final image. As an example, consider this texture: the dot might be the edge of a window, and we stretch it out to make a line (obviously in a real app it would be something more intricate that actually requires a texture, but the idea is the same). So, given the coordinates of the corners of the dot in terms of actual pixels on the image, I compute the u,v coords by dividing by the image's dimension. Those coords are assigned to vertices - with the 0.5,0.5 offset, but I've tried it without and it looks even worse, the same problem applies. When I scale it out, what I get is this: That's with texture filtering turned on. Turn it off, and the result is a solid block like I want, but it's a rather inelegant and inefficient solution to constantly have to change the sampler state, and it seems like there must be a better way. obviously, the surrounding image is bleeding in - Make the background in the texture blue, and it will fade to blue instead - so it would seem like an issue with the texture coords in use. Is it possible to get this image to scale perfectly with texture filtering on, or is that just not possible?

Share this post


Link to post
Share on other sites
Skeleton_V@T    512
Hi!
You seem to have been using D3DXSprite to render your object with texture, why not just make your own 2D rectangle filled with the texture ?, the problem will be much simpler.

And why do you have to expand each side to 0.5px ?. In order to draw the textured sprite correctly, it should be expanded 1px down and 1px right from the upper side and left side appropriately (that was a mistake in the DXDSK), try this for a better result than yours.

I recommend to make your own sprite 'cause you can - in some cases - 'distort' the object's shape the way you want, and it's faster, you have the total control of rendering the texture onto the object itself.

Share this post


Link to post
Share on other sites
_Flecko    196
-I am using a textured quad in orthographic projection, not sprites
-the 0.5px thing is explained here: http://blogs.msdn.com/jsteed/articles/209220.aspx

Share this post


Link to post
Share on other sites
Source    272
Unfortunately, altering the texture filtering method as you have already discovered is the appropriate method for producing sharp results.

In most graphics application, this blurring is prefered, giving a smoother result and maintaining the suspension of disbelief.

You simply do not want PCF filtering enabled, and so disabling it in the sampler settings is your only choice - either that or use a far greater resolution texture sample, therby reducing the texel to pixel ratio.

For greater efficiency you can group all polygons which require the state together, thereby reducing your state changing overhead. That said - this is not a state change which will load your application greatly (unlike for instance changing texture or shader).

Share this post


Link to post
Share on other sites
daVinci1980    122
Hi _Flecko-

The issue you're running into is that the texture coordinates you've chosen aren't quite the right ones. This is related to the offset by 0.5 issue that you've already run into.

Imagine the case of a single pixel image, as you are already looking at. In that case, if I want to scale the pixel from 1 pixel to 1x10 pixels, I should have a SS quad (you already do) that is 1x10, with texture coordinates that do not change, and are always centered on the dead center of the texel I want to sample from. (If it's not the dead center, you're still going to get filtering artifacts).

Your technique is only going to work for textures that are 1 pixel in the dimension you are scaling along though (ie, you cannot tile with the technique you are using). If this is something you're interested in doing, you will have to use geometry to emulate tiling.

If you give me more details about what you're ultimately trying to accomplish, I can almost certainly offer you some additional help in this area--I did low level 2-D renderers for several shipped titles.

Hope this helps,

daVinci


PS: Source: I'm not sure why you're suggesting that he's using percent closer filtering--he's definitely not. (Bilinear? Sure, Trilinear? Possibly. Aniso? Maybe. PCF? Not so much).

Share this post


Link to post
Share on other sites
Skeleton_V@T    512
Maybe you want to try this article:
Dissecting Sprites in Direct3D

But, in my experiences, I have no trouble stretching textures and apply it to the quads. The left and top side of image will have texture coordinates {0, 0}, regardless of how I distort my object, and no wonder about 0.5px stuff. The article is saying about D3DXSprite though.

Share this post


Link to post
Share on other sites
daVinci1980    122
Quote:
Original post by Skeleton_V@T
But, in my experiences, I have no trouble stretching textures and apply it to the quads. The left and top side of image will have texture coordinates {0, 0}, regardless of how I distort my object, and no wonder about 0.5px stuff. The article is saying about D3DXSprite though.


Hi Skeleton-

The issue wrt 0.5 pixel offsets is discussed here.

The problem is fundamentally that the way people typically think about drawing screen space (SS) quads is offset by one-half pixel (or texel) from the way that the hardware actually deals with them.

In general, people writing shipping code tend to avoid using D3DX because of the "black box" characteristics. It represents an unknown in terms of how much memory it's using, how many cycles it takes to do its thing, etc. Plus it is closed source, and so if there's a bug... You're hosed.

Share this post


Link to post
Share on other sites
MePHyst0    232
Hi _Flecko

Your doing right with offsetting the texture coordinates. Do not listen to the people who are saying that it lies behind your problems. This is a common issue of polygon texturing and this is the only way how to solve it.


To your initial problem. I assume that you drawing your HUD elements at the end own the render process, thus it needs just 2 render state changes to make the textures filter correctly. one(set D3DX_FILTER_NONE) at the beginnig of your HUD rendering process, and one at the end(set D3DX_FILTER_LINEAR or whatever you want to have there) of the rendering process. I think that 2 render state changes won't knock your performance on its knees, don't you? ;)

Hope this helps

Share this post


Link to post
Share on other sites
jollyjeffers    1570
One thing that hasn't been mentioned yet that you may not be familiar with is that the bilinear filtering algorithm (aka linear filtering) is only really supposed to work upto 2x scaling - after that it breaks down to usually being far too blurry/inaccurate to be useful. Seems from your diagram that you're using substantially more than a 2x scale [smile]

Disabling filtering might well be a better option, but if you're finding that you need some form of filtering, but the "stock" implementations aren't up-to-scratch then you could always consider implementing your own filtering in a pixel shader... I did this recently in order to get bilinear filtering for HDR render targets.

hth
Jack

Share this post


Link to post
Share on other sites
TDragon    679
Another thing that hasn't been mentioned yet is that, for GUIs, tiling is preferred over scaling.

I suspect it would solve your texture filtering problem.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this