GoogleMapsShaderLib.cginc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #ifndef NINE_SLICING
  2. #define NINE_SLICING
  3. // Returns one of two float values depending on the value of the provided condition variable. This
  4. // is provided as an alternative to if/else branching, which is inefficient on GPUs.
  5. // condition: The condition to evaluate.
  6. // ifTrue: Returned if cond is true.
  7. // ifFalse: Returned if cond is false.
  8. float _ifElsef(bool condition, float ifTrue, float ifFalse) {
  9. return (ifTrue * (condition > 0)) + (ifFalse * (condition == 0));
  10. }
  11. // A struct containing the texture coordinate information of a nine-sliced fragment.
  12. struct nineSliceResult {
  13. // A UV coordinates for a texture.
  14. float2 uv;
  15. // A partial derivative of UV coordinates respective to the screen-space x-coordinate.
  16. // The derivative represents the rate of changes between texture coordinates in two adjacent
  17. // fragments, and is used for passing into the `tex2D` function for selecting the the correct
  18. // mipmap level of the texture.
  19. float2 ddx;
  20. // A partial derivative of UV coordinates respective to the screen-space y-coordinate.
  21. // The derivative represents the rate of changes between texture coordinates in two adjacent
  22. // fragments, and is used for passing into the `tex2D` function for selecting the the correct
  23. // mipmap level of the texture.
  24. float2 ddy;
  25. };
  26. // Nine-slices the UV coordinates of a fragment within the specified bounds. Nine-slicing is used to
  27. // tile the applied texture in the following manner:
  28. //
  29. // + +
  30. // (0, 1) | | (1, 1)
  31. // +----------------------+
  32. // | | tiled | |
  33. // | | x | | upper
  34. // +----------------------------+ bound
  35. // | t | | t |
  36. // | i | tiled | i |
  37. // | l y| x & y | l y|
  38. // | e | | e |
  39. // | d | | d |
  40. // +----------------------------+ lower
  41. // | | tiled | | bound
  42. // | | x | |
  43. // +----------------------+
  44. // (0, 0) | | (1, 0)
  45. // + +
  46. // left right
  47. // bound bound
  48. //
  49. // It offers functionality similar to Unity's inbuilt nine-slicing for sprites:
  50. // https://docs.unity3d.com/Manual/9SliceSprites.html.
  51. // pos: The (x, y) coordinates of the fragment being textured, relative to the origin of the face.
  52. // faceSize: The (width, height) of the face being nine-sliced.
  53. // texSize: The (width, height) of the base texture.
  54. // leftBound: The position of the left nine-slicing boundary normalized to the width of the texture
  55. // (in the range 0 to 1 inclusive). Tiling on the U axis only occurs to the right of leftBound.
  56. // rightBound: The position of the right nine-slicing boundary normalized to the width of the
  57. // texture (in the range 0 to 1 inclusive). Tiling on the U axis only occurs to the left of
  58. // rightBound.
  59. // lowerBound: The position of the lower nine-slicing boundary normalized to the height of the
  60. // texture (in the range 0 to 1 inclusive). Tiling on the V axis only occurs above lowerBound.
  61. // upperBound: The position of the upper nine-slicing boundary normalized to the height of the
  62. // texture (in the range 0 to 1 inclusive). Tiling on the V axis only occurs below upperBound.
  63. nineSliceResult nineSlice(
  64. float2 pos, float2 faceSize, float2 texSize,
  65. float leftBound, float rightBound, float lowerBound, float upperBound) {
  66. // Normalize relative to texture size.
  67. float2 normalFaceSize = faceSize / texSize;
  68. float2 normalPos = pos / texSize;
  69. // Calculate the size of the center fragment of the face.
  70. float centerFaceSizeX = normalFaceSize.x - leftBound - (1 - rightBound);
  71. float centerFaceSizeY = normalFaceSize.y - lowerBound - (1 - upperBound);
  72. // Calculate the size of the center fragment of each tiling;
  73. float centerTexSizeX = rightBound - leftBound;
  74. float centerTexSizeY = upperBound - lowerBound;
  75. // Calculate the number of tilings in the center fragment of the face.
  76. int tileNumX = max(round(centerFaceSizeX / centerTexSizeX), 1);
  77. int tileNumY = max(round(centerFaceSizeY / centerTexSizeY), 1);
  78. // Calculate the continuous UV used for calculating the derivative of the UV.
  79. float2 continuousUV = float2(
  80. pos.x / faceSize.x * (centerTexSizeX * tileNumX + leftBound + (1 - rightBound)),
  81. pos.y / faceSize.y * (centerTexSizeY * tileNumY + lowerBound + (1 - upperBound)));
  82. // Calculate bounding conditionals.
  83. bool isLeftBound = normalPos.x < leftBound;
  84. bool isRightBound = normalPos.x > normalFaceSize.x - (1 - rightBound);
  85. bool isLowerBound = normalPos.y < lowerBound;
  86. bool isUpperBound = normalPos.y > normalFaceSize.y - (1 - upperBound);
  87. // Calculate UV coordinates within each bound.
  88. float leftBoundU = normalPos.x;
  89. float rightBoundU = 1 - (normalFaceSize.x - normalPos.x);
  90. float centerBoundU = lerp(leftBound, rightBound,
  91. (normalPos.x - leftBound) * tileNumX / centerFaceSizeX % 1);
  92. float lowerBoundV = normalPos.y;
  93. float upperBoundV = 1 - (normalFaceSize.y - normalPos.y);
  94. float centerBoundV = lerp(lowerBound, upperBound,
  95. (normalPos.y - lowerBound) * tileNumY / centerFaceSizeY % 1);
  96. // Construct final UV coordinates based on the fragment's location in the face.
  97. float u = _ifElsef(isLeftBound,
  98. leftBoundU,
  99. _ifElsef(isRightBound,
  100. rightBoundU,
  101. centerBoundU));
  102. float v = _ifElsef(isLowerBound,
  103. lowerBoundV,
  104. _ifElsef(isUpperBound,
  105. upperBoundV,
  106. centerBoundV));
  107. // Construct the nine-slicing result struct.
  108. nineSliceResult result;
  109. result.uv = float2(u, v);
  110. result.ddx = ddx(continuousUV);
  111. result.ddy = ddy(continuousUV);
  112. return result;
  113. }
  114. #endif