mlaa_blend2.frag 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. uniform sampler2D edgesMap;
  2. uniform sampler2D areaMap;
  3. #define MAX_SEARCH_STEPS 8.0
  4. #define MAX_DISTANCE 33.0
  5. out vec4 FragColor;
  6. /**
  7. * This one just returns the first level of a mip map chain, which allow us to
  8. * avoid the nasty ddx/ddy warnings, even improving the performance a little
  9. * bit.
  10. */
  11. vec4 tex2Doffset(sampler2D map, vec2 texcoord, vec2 offset) {
  12. return textureLod(map, texcoord + offset / screen, 0.0);
  13. }
  14. float SearchXLeft(vec2 texcoord) {
  15. // We compare with 0.9 to prevent bilinear access precision problems.
  16. float i;
  17. float e = 0.0;
  18. for (i = -1.5; i > -2.0 * MAX_SEARCH_STEPS; i -= 2.0) {
  19. e = tex2Doffset(edgesMap, texcoord, vec2(i, 0.0)).g;
  20. if (e < 0.9) break;
  21. }
  22. return max(i + 1.5 - 2.0 * e, -2.0 * MAX_SEARCH_STEPS);
  23. }
  24. float SearchXRight(vec2 texcoord) {
  25. float i;
  26. float e = 0.0;
  27. for (i = 1.5; i < 2.0 * MAX_SEARCH_STEPS; i += 2.0) {
  28. e = tex2Doffset(edgesMap, texcoord, vec2(i, 0.0)).g;
  29. if (e < 0.9) break;
  30. }
  31. return min(i - 1.5 + 2.0 * e, 2.0 * MAX_SEARCH_STEPS);
  32. }
  33. float SearchYDown(vec2 texcoord) {
  34. float i;
  35. float e = 0.0;
  36. for (i = -1.5; i > -2.0 * MAX_SEARCH_STEPS; i -= 2.0) {
  37. e = tex2Doffset(edgesMap, texcoord, vec2(i, 0.0).yx).r;
  38. if (e < 0.9) break;
  39. }
  40. return max(i + 1.5 - 2.0 * e, -2.0 * MAX_SEARCH_STEPS);
  41. }
  42. float SearchYUp(vec2 texcoord) {
  43. float i;
  44. float e = 0.0;
  45. for (i = 1.5; i < 2.0 * MAX_SEARCH_STEPS; i += 2.0) {
  46. e = tex2Doffset(edgesMap, texcoord, vec2(i, 0.0).yx).r;
  47. if (e < 0.9) break;
  48. }
  49. return min(i - 1.5 + 2.0 * e, 2.0 * MAX_SEARCH_STEPS);
  50. }
  51. vec2 round(vec2 invec) {
  52. return vec2(floor(abs(invec) + vec2(0.5)) * sign(invec));
  53. }
  54. vec2 Area(vec2 distance, float e1, float e2) {
  55. // * By dividing by areaSize - 1.0 below we are implicitely offsetting to
  56. // always fall inside of a pixel
  57. // * Rounding prevents bilinear access precision problems
  58. float areaSize = MAX_DISTANCE * 5.0;
  59. vec2 pixcoord = MAX_DISTANCE * round(4.0 * vec2(e1, e2)) + distance;
  60. vec2 texcoord = pixcoord / (areaSize - 1.0);
  61. return textureLod(areaMap, texcoord, 0.0).ra;
  62. }
  63. void main() {
  64. vec4 areas = vec4(0.0);
  65. vec2 uv = gl_FragCoord.xy / screen;
  66. vec2 e = texture(edgesMap, uv).rg;
  67. if (e.g != 0.0) { // Edge at north
  68. // Search distances to the left and to the right:
  69. vec2 d = vec2(SearchXLeft(uv), SearchXRight(uv));
  70. // Now fetch the crossing edges. Instead of sampling between edgels, we
  71. // sample at 0.25, to be able to discern what value has each edgel:
  72. vec4 coords = vec4(d.x, 0.25, d.y + 1.0, 0.25) / screen.xyxy + uv.xyxy;
  73. float e1 = textureLod(edgesMap, coords.xy, 0.0).r;
  74. float e2 = textureLod(edgesMap, coords.zw, 0.0).r;
  75. // Ok, we know how this pattern looks like, now it is time for getting
  76. // the actual area:
  77. areas.rg = Area(abs(d), e1, e2);
  78. }
  79. if (e.r != 0.0) { // Edge at west
  80. // Search distances to the top and to the bottom:
  81. vec2 d = vec2(SearchYUp(uv), SearchYDown(uv));
  82. // Now fetch the crossing edges (yet again):
  83. vec4 coords = vec4(-0.25, d.x, -0.25, d.y - 1.0) / screen.xyxy + uv.xyxy;
  84. float e1 = textureLod(edgesMap, coords.xy, 0.0).g;
  85. float e2 = textureLod(edgesMap, coords.zw, 0.0).g;
  86. // Get the area for this direction:
  87. areas.ba = Area(abs(d), e1, e2);
  88. }
  89. FragColor = areas;
  90. }