Skip to main content
gamedev.net
🔒 Locked

Text Texturing Artifacts

Started by Mindowindow 9 replies 1.1k views
Original Post
Mindowindow
Mindowindow
I've finally got my text sprites to render great, but there are some artifacts showing up...sometimes, and "randomly." I'm simply rendering the text strings as textured quads in a row, like ID3DXFont does. Yesterday one time I ran the program I got this: Artifacts - Bad Today I ran it, but have not even recompiled: Artifacts - None Then I recompiled and changed the texture size, got artifacts, changed back to the size of those two images and ran again getting different and minimal artifacts: Artifacts - Some I really don't know what could be the problem, but I think the weird repeated "randomness" is because of texture caching, or some resource that stays in video memory? When I dump the textures to a file they are fine, so its during the render pipeline somewhere. I can explain/post my rendering code in more detail but has anyone ever come across artifacts like these and if so is there a general fix I should be aware of?
ViLiO
ViLiO
I personally think it looks like texture bleeding as a result of linear filtering (which is commonly seen in lightmaps). One cheap way to tackle it would be to shift your uv coords in by half a texel. Another (arguably better) way would be to pad each character with a one-pixel-wide border (keeping the uv coords as they are).

All the best,
ViLiO
Richard 'ViLiO' Thomasv.net | Twitter | YouTube
Mindowindow
Mindowindow
Hm, I could pad the textures with a border (which would be ironic since the earlier problem with my text system was unwanted padding). The weird, or maybe not so weird, thing is that all the non-text sprite textures don't have artifacts at all and they use the exact same rendering pipeline. The sprite textures are base2 squares however, so would the "non-sqarity" of the character textures increase the chances of this linear filter bleeding?

I don't really want to do a uv offset, but are there any other possible solutions besides a border padding?
griffin2000
griffin2000
Firstly I'd make sure the wrap mode in the texture sampling state is set to clamp.
ViLiO
ViLiO
This msdn entry should give you a better idea of why it happens (assuming of course it definitely is a result of bleeding).

Essentially though, the only other way I can think of to avoid it would be to not filter (i.e. using point filtering). This would make the fonts look very aliased if/when you scale them, so my vote is still with a bit of padding [smile]

Btw, you are storing all your characters in a font sheet and not an individual texture for each character right? If you have a texture for each character you can kiss goodbye to performance [lol] If you are using an individual texture for each character then clamp addressing would actually solve this but seriously don't consider it as that many texture changes would just kill your app [smile]

Clamp will do nothing for a font sheet though as it only clamps any uv coords less than 0 and greater than 1 (and you won't be going outside that range anyway so it would only help for characters on the edge of the font sheet).

Regards,
ViLiO
Richard 'ViLiO' Thomasv.net | Twitter | YouTube
Mindowindow
Mindowindow
Damnit, that seems to have been the problem, but I had thought that Clamp was the default value for AddressU/V. I guess never assume default values. Is the default Wrap then? I hadn't thought of it because the UV cordinates are always 0.0f and 1.0f on the single quad that renders everything. I suppose that since the character textures are not square that their more complex scaling matrices caused floating point errors that boggled the uv coordinates slightly.

Thanks for the help, greatly appreciated.

[Edit]
Actually, I am using individual textures. I wasn't aware that it would cause much of an issue and I haven't noticed any performance hit yet (of course I only have one text object on the screen right now). How would it be possible to put all the characters in one texture if the font size is large the texture would be thousands of pixels wide, and I thought that would be a greater performance problem, would it though?
ViLiO
ViLiO
Quote:
Original post by Gondolin
Actually, I am using individual textures. I wasn't aware that it would cause much of an issue and I haven't noticed any performance hit yet (of course I only have one text object on the screen right now). How would it be possible to put all the characters in one texture if the font size is large the texture would be thousands of pixels wide, and I thought that would be a greater performance problem, would it though?

Changing texture is quite expensive and most 3D apps/games will sort by texture (and other things) before rendering (and if they dont ...they should [wink])

For a decent tool on packing your characters into a font sheet check out The AngelCode Bitmap Font Generator

All the best,
ViLiO
Richard 'ViLiO' Thomasv.net | Twitter | YouTube
Mindowindow
Mindowindow
Crap, you're right, when I put up around 30+ text objects, my fps plummets from 60+ (this is Windowed mode) to 30-.

I've looked into bitmap font generators like that one but my design demands a flexiple, run-time font creation, like the ID3DXFont interface (which I'd use if I could pump the actual rendering through my shaders), so loading external bitmaps is not possible. I could however, code something that would pack the textures I load from the Windows GDI glyphs into one or more large textures with indexed uv coordinates saved for each character look up. My question is would this be more efficient? My guess would be that for rendering just a few strings per frame, my current method would be more efficient since loading a huge texture could actually make it slower. But when you have a lot of text objects the payoff of loading the large texture(s) would easily be faster than having lots of small texture changes. Is this correct?

I was also planning to implement texture sorting eventually, but I'm just laying down the basic render pipe currently.
ViLiO
ViLiO
Quote:
Original post by Gondolin
I could however, code something that would pack the textures I load from the Windows GDI glyphs into one or more large textures with indexed uv coordinates saved for each character look up. My question is would this be more efficient? My guess would be that for rendering just a few strings per frame, my current method would be more efficient since loading a huge texture could actually make it slower. But when you have a lot of text objects the payoff of loading the large texture(s) would easily be faster than having lots of small texture changes. Is this correct?

I would be very surprised, if having one large texture will all your characters in it, ran slower than keeping those characters as separate textures and making huge amounts of unnecessary DrawPrimitive calls (some profiling on your part wouldn't hurt though [wink])

Graphics cards are designed to cope with large textures (a GeForce 2 can handle textures that are 2048x2048) so performance is not going to take a dive when you pack sprites or bitmap font characters together [cool]

Regards,
ViLiO
Richard 'ViLiO' Thomasv.net | Twitter | YouTube
Mindowindow
Mindowindow
All right, I'll try and implement a packing algorithm. I think I'll divide a font set into as many 2048 textures as needed, or 1024 if it will fit. I don't see how this would cut down on DrawPrimitive() calls though. It will dramatically reduce texture change calls, but I would still need to draw each character on its own quad...?

I have built a profiler into my engine, so I when I finish I'll post some results and comparisons. I don't doubt that the bigger textures will greatly improve performance, I was just pondering about situations with limited text rendering.
Mindowindow
Mindowindow
Alright, after a long and arduous task of implementing a runtime texture batching packer here's just another testimonial for texture batching, though I know people already know its worth.

Without texture batching:
Text Objects | FPS
1 | 68
30 | 46
60 | 20

With texture batching:
Text Objects | FPS
1 | 68
30 | 66
60 | 65

The values are approximations and may have partially depended on how long I ran the test since the average FPS factors in the app initialization time, and takes a while to settle on the true realtime value (which I could fix, but I don't really care since the results are usually clear enough).

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.