How to retain full quality on a rotated textured quad?

So, I'm rendering a textured quad via Graphics.DrawMesh, on an orthographic camera, for windows/mac standalone, in the latest unity 3 beta. All is well when there are no rotations, I have absolutely pixel-perfect crisp graphics.

However, when I rotate the textured quads, it quickly starts to look rather horrible in terms of quality. In SlimDX, running over top of the Direct3DX sprite extensions, it pretty much handled this for me -- there were some artifacts, but they were minor to the point of only being noticeable as the rotation angle changed.

On the Unity side, I've tried:

  1. Using Bilinear filtering for the Texture2Ds that are rotated (normally it is Point for maximum correctness/quality when not rotated), but that makes the entire texture look fuzzy, despite the fact that the edges look better.
  2. Trilinear, which does the same as Bilinear.
  3. Adjusting overall quality settings, including forcing on aniso, 8x multisampling (from 16x, that's the highest my card will go) -- and none of that has any effect whatsoever.

I've been all through the Unity documentation a gazillion times for this -- first for my game Tidalis back four or five months ago, and now for my other game AI War, which I'm now porting to Unity.

Surely there's something I'm just missing...?

SlimDX image Unity 3D image

First Edit:

Here's the direct image I'm using as the texture on the textured quad, if anyone else wants to check out what is happening:

alt text

Second Edit:

Here's an image that it might be easier to see the general bilinear distortion on, because of better contrast:

alt text

This is the sort of quality drop I'm seeing, and I'm seeing it in your image, too:

alt text

See how that one starship, which has been rotated with bilnear filtering applied, looks all blurry while the non-rotated point-filtered sprites all look perfectly clear? That's the crux of the issue I'm running into here. Aside from the rotated starship looking pretty blurry in general, worst of all that pink border is incredibly blurry, which makes it stand out like a sore thumb near its un-rotated-point-based peers.

Certainly that can be bypassed by making everything bilinear filtered, but that looks pretty wretched, too. Here's an example of the quality differences in general between bilinear and non-bilinear for non-rotated sprites:

Nice and crisp, no bilinear filtering except on the rotated missiles: alt text

Unfortunately blurry, with bilinear filtering on everything: alt text

This is really quite a challenge!

Are you sure the comparison with the DirectX implementation is more or less 1-to-1? That is, are the textures, texture resolutions, and apparent sizes on screen the same or similar?

–

Yep, I'm 100% sure it's 1:1. These are being displayed in screen coordinates, so basically pixel-for-pixel when not rotated. When not rotated, as I noted, this looks absolutely perfect. But, when rotated but with no other changes, the quality drops.

–

I don't have any additional ideas off the top of my head, but maybe someone else will be able to suggest something. (If there's any way you could make a screenshot or example project available, that might make it easier to guess at what might be causing the problem.)

–

Ok -- thanks for the comments, anyway. I've added two images, one of SlimDX and the other of Unity 3D. Hopefully that will make it more clear. Unfortunately the sample product is nearly a hundred lines of code, it's not something I can post publicly -- and it's something I've tried every which way, so it must be something global enough that others would see. Simply rotating any textured quad produces this result in my experience with unity so far (since March). Hope the images help!

–

Oh, and one thing to clarify -- if the unity 3D ones look slightly smaller than the slimdx ones, that's just part of the issue I'm talking about -- it's blurring out their edges, which makes them look rough as well as slightly smaller, but they are definitely both being drawn at 1:1 screen space scale, and the rotations here are identical between the two screenshots.

–

1 Answer

1

Here's my test in Unity. When not rotated, I can't see any difference between point and bilinear filtering, so there doesn't seem to be any reason to use point filtering here, which can never work well for rotated sprites. I'm not sure what rotations you used, so I went with 22. It's a bit hard to tell with such tiny images, but maybe it looks better than what you're getting?

sprite

As for what doesn't work:

Trilinear filtering: this blends between mip levels, which you don't need for 2D, so it will have no effect.

Anisotropic filtering: this reduces blurriness of far textures when viewed at oblique angles, which again will have zero effect in a 2D game.

FSAA: this antialiases edges of polygons, so it can never have any effect on texture quality, no matter how high you set it.

If my image is better than what you're getting, make sure:

The orthographic camera and quad positioning is set up properly, so you don't have texture pixels disappearing "in between" the pixel grid.

You're using RGBA uncompressed textures, not DXT5.

Edit: There really isn't any difference between point and bilinear when the sprite is positioned correctly. I took screenshots of the bigger sprite and blew it up 300%; they are identical. Then I took screenshots of the quad when positioned at (.5, .5) so that the texture pixels are halfway between the pixel grid. Clearly, the only way to get a true pixel-perfect display is when texture pixels are exactly aligned to the pixel grid. Bilinear is blurry; point is clearer, but still not perfect (some of the pixels are doubled). You can get nice sub-pixel movement with bilinear though, at the cost of blurriness when between the pixel grid.

The artifacts when rotated are simply the result of working with pixels instead of vector images. There's no way to do it perfectly...the bottom row is rotated at 45 when using Photoshop, then bilinear filtering, then point. I'd say bilinear actually gets the best results here.

sprite2

Okay, this was extremely helpful. I thought it solved everything, but actually I do still have some problems. One challenge is that the bilinear is NOT identical without rotation. Perhaps a more expressive sprite image would make that clear, I'll post shortly. It's really quite puzzling.

–

Nuts... I'm still having sour results, and honestly I think your image is also having the same issue -- look at the color shift in the pink border on your bilinear example when rotated. It's just hard to judge out of context, so I provided some more images above to show better context. Very good to know about the FSAA, Ansio, and so forth -- thanks for that.

–

As far as the orthographic camera goes, I have to assume that it's right given that the problem only shows up in specific circumstances (rotation, bilinear), and is showing up the same in your example. And, I've tried it with both ARGB32 and DXT5, with no difference I can see.

–

@x4000: there's a substantial difference between ARGB32 and DXT5 with the sprite image I used. DXT is lossy compression after all. Look at whether the editor says "not compressed yet", because if it's not, it will look the same. Also, I updated my answer with more stuff.

–

Anyway, thanks again -- this solves my longest-standing problem with unity, and the solution was deceptively simple! I knew I must be missing something simple, but couldn't find it for the life of me. Thanks a million.

–