Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

94 lines
4.5 KiB

  1. # Font character oversampling for rendering from atlas textures
  2. TL,DR: Run oversample.exe on a windows machine to see the
  3. benefits of oversampling. It will try to use arial.ttf from the
  4. Windows font directory unless you type the name of a .ttf file as
  5. a command-line argument.
  6. ## Benefits of oversampling
  7. Oversampling is a mechanism for improving subpixel rendering of characters.
  8. Improving subpixel has a few benefits:
  9. * With horizontal-oversampling, text can remain sharper while still being sub-pixel positioned for better kerning
  10. * Horizontally-oversampled text significantly reduces aliasing when text animates horizontally
  11. * Vertically-oversampled text significantly reduces aliasing when text animates vertically
  12. * Text oversampled in both directions significantly reduces aliasing when text rotates
  13. ## What text oversampling is
  14. A common strategy for rendering text is to cache character bitmaps
  15. and reuse them. For hinted characters, every instance of a given
  16. character is always identical, so this works fine. However, stb_truetype
  17. doesn't do hinting.
  18. For anti-aliased characters, you can actually position the characters
  19. with subpixel precision, and get different bitmaps based on that positioning
  20. if you re-render the vector data.
  21. However, if you simply cache a single version of the bitmap and
  22. draw it at different subpixel positions with a GPU, you will get
  23. either the exact same result (if you use point-sampling on the
  24. texture) or linear filtering. Linear filtering will cause a sub-pixel
  25. positioned bitmap to blur further, causing a visible de-sharpening
  26. of the character. (And, since the character wasn't hinted, it was
  27. already blurrier than a hinted one would be, and now it gets even
  28. more blurry.)
  29. You can avoid this by caching multiple variants of a character which
  30. were rendered independently from the vector data. For example, you
  31. might cache 3 versions of a char, at 0, 1/3, and 2/3rds of a pixel
  32. horizontal offset, and always require characters to fall on integer
  33. positions vertically.
  34. When creating a texture atlas for use on GPUs, which support bilinear
  35. filtering, there is a better approach than caching several independent
  36. positions, which is to allow lerping between the versions to allow
  37. finer subpixel positioning. You can achieve these by interleaving
  38. each of the cached bitmaps, but this turns out to be mathematically
  39. equivalent to a simpler operation: oversampling and prefiltering the
  40. characters.
  41. So, setting oversampling of 2x2 in stb_truetype is equivalent to caching
  42. each character in 4 different variations, 1 for each subpixel position
  43. in a 2x2 set.
  44. An advantage of this formulation is that no changes are required to
  45. the rendering code; the exact same quad-rendering code works, it just
  46. uses different texture coordinates. (Note this does potentially increase
  47. texture bandwidth for text rendering since we end up minifying the texture
  48. without using mipmapping, but you probably are not going to be fill-bound
  49. by your text rendering.)
  50. ## What about gamma?
  51. Gamma-correction for fonts just doesn't work. This doesn't seem to make
  52. much sense -- it's physically correct, it simulates what we'd see if you
  53. shrunk a font down really far, right?
  54. But you can play with it in the oversample.exe app. If you turn it on,
  55. white-on-black fonts become too thick (i.e. they become too bright), and
  56. black-on-white fonts become too thin (i.e. they are insufficiently dark). There is
  57. no way to adjust the font's inherent thickness (i.e. by switching to
  58. bold) to fix this for both; making the font thicker will make white
  59. text worse, and making the font thinner will make black text worse.
  60. Obviously you could use different fonts for light and dark cases, but
  61. this doesn't seem like a very good way for fonts to work.
  62. Multiple people who have experimented with this independently (me,
  63. Fabian Giesen,and Maxim Shemanarev of Anti-Grain Geometry) have all
  64. concluded that correct gamma-correction does not produce the best
  65. results for fonts. Font rendering just generally looks better without
  66. gamma correction (or possibly with some arbitrary power stuck in
  67. there, but it's not really correcting for gamma at that point). Maybe
  68. this is in part a product of how we're used to fonts being on screens
  69. which has changed how we expect them to look (e.g. perhaps hinting
  70. oversharpens them and prevents the real-world thinning you'd see in
  71. a black-on-white text).
  72. (AGG link on text rendering, including mention of gamma:
  73. http://www.antigrain.com/research/font_rasterization/ )
  74. Nevertheless, even if you turn on gamma-correction, you will find that
  75. oversampling still helps in many cases for small fonts.