MipSample.cginc 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /**
  2. * Samples the given mipmap-free texture as if it had a mipmap.
  3. * This is kind of expensive per fragment, especially if the texture is far from the camera,
  4. * but I imagine your using this because it's faster than the alternative.
  5. *
  6. * The {tex} and {uv} parameters do what you would expect. We will sample that texture
  7. * "at" the given uv coordinate by sampling and averaging a number of points in the vicinity.
  8. *
  9. * The averaging calculation assumes a linear color space and no premultiplied alpha.
  10. *
  11. * textureSize should be the size, in pixels, of {tex}. For a "sampler2D _MyTex" add a
  12. * "float4 _MyTex_TexelSize" which Unity will fill for you. Pass in _MyTex_TexelSize.zw
  13. *
  14. * maxLineSamples indicates the maximum number of times we can subsample per dimension. Worst case is
  15. * maxLineSamples*maxLineSamples samples.
  16. *
  17. * Pass 1 for sampleMultiplier for the default behavior. Pass less or more for fewer samples or more samples respectively.
  18. */
  19. fixed4 mipSample(
  20. sampler2D tex, float2 uv,
  21. float2 textureSize, int maxLineSamples, float sampleMultiplier
  22. ) {
  23. //Roughly, we need to sample more times if we are far than near.
  24. //Rather, we should sample about the same number of times, regardless
  25. //of if we fill the whole screen or only fill a hundredth.
  26. //how much uv changes when we go right a pixel
  27. float2 uvDx = ddx(uv);
  28. //how much uv changes when we go down a pixel
  29. float2 uvDy = ddy(uv);
  30. int xSamples = clamp(length(uvDx) * textureSize.x * sampleMultiplier, 1, maxLineSamples);
  31. int ySamples = clamp(length(uvDy) * textureSize.x * sampleMultiplier, 1, maxLineSamples);
  32. //Note: above we use using size.x for both, assuming a square texture. Don't use size.y as the texture xy won't always
  33. //line up with our xy. If we did that, we may end up looking different based on the camera/object rotation.
  34. //Determine base (origin) and step size
  35. //We'll pull our samples from a rectangle halfway left, right, above, and below our
  36. //"normal" target point
  37. float2 p = uv - uvDx / 2 - uvDy / 2;
  38. uvDx /= (float)xSamples;
  39. uvDy /= (float)ySamples;
  40. //Sample a bunch.
  41. float4 c = float4(0, 0, 0, 0);
  42. for (int x = 0; x < xSamples; ++x) {
  43. for (int y = 0; y < ySamples; ++y) {
  44. //nb: can't use tex2D directly here because the compiler wants to unroll this loop to get the gradients.
  45. //Instead, feed it the gradients outright.
  46. c += tex2Dgrad(tex, p + uvDx * x + uvDy * y, uvDx, uvDy);
  47. }
  48. }
  49. //Average the samples.
  50. //(assuming linear color space)
  51. //(assuming no premultiplied alpha)
  52. c /= xSamples * ySamples;
  53. //Uncomment to visualize sample cost:
  54. // if (xSamples * ySamples > 100) c.g = 1;
  55. // else if (xSamples * ySamples > 10) c.g = 0.6;
  56. // else if (xSamples * ySamples > 1) c.g = 0.3;
  57. // else c.g = 0;
  58. return c;
  59. }