ShadowSamplingTent.hlsl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // ------------------------------------------------------------------
  2. // PCF Filtering Tent Functions
  3. // ------------------------------------------------------------------
  4. // Assuming a isoceles right angled triangle of height "triangleHeight" (as drawn below).
  5. // This function return the area of the triangle above the first texel.
  6. //
  7. // |\ <-- 45 degree slop isosceles right angled triangle
  8. // | \
  9. // ---- <-- length of this side is "triangleHeight"
  10. // _ _ _ _ <-- texels
  11. real SampleShadow_GetTriangleTexelArea(real triangleHeight)
  12. {
  13. return triangleHeight - 0.5;
  14. }
  15. // Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
  16. // This function return the area of the triangle above each of those texels.
  17. // | <-- offset from -0.5 to 0.5, 0 meaning triangle is exactly in the center
  18. // / \ <-- 45 degree slop isosceles triangle (ie tent projected in 2D)
  19. // / \
  20. // _ _ _ _ <-- texels
  21. // X Y Z W <-- result indices (in computedArea.xyzw and computedAreaUncut.xyzw)
  22. void SampleShadow_GetTexelAreas_Tent_3x3(real offset, out real4 computedArea, out real4 computedAreaUncut)
  23. {
  24. // Compute the exterior areas
  25. real offset01SquaredHalved = (offset + 0.5) * (offset + 0.5) * 0.5;
  26. computedAreaUncut.x = computedArea.x = offset01SquaredHalved - offset;
  27. computedAreaUncut.w = computedArea.w = offset01SquaredHalved;
  28. // Compute the middle areas
  29. // For Y : We find the area in Y of as if the left section of the isoceles triangle would
  30. // intersect the axis between Y and Z (ie where offset = 0).
  31. computedAreaUncut.y = SampleShadow_GetTriangleTexelArea(1.5 - offset);
  32. // This area is superior to the one we are looking for if (offset < 0) thus we need to
  33. // subtract the area of the triangle defined by (0,1.5-offset), (0,1.5+offset), (-offset,1.5).
  34. real clampedOffsetLeft = min(offset,0);
  35. real areaOfSmallLeftTriangle = clampedOffsetLeft * clampedOffsetLeft;
  36. computedArea.y = computedAreaUncut.y - areaOfSmallLeftTriangle;
  37. // We do the same for the Z but with the right part of the isoceles triangle
  38. computedAreaUncut.z = SampleShadow_GetTriangleTexelArea(1.5 + offset);
  39. real clampedOffsetRight = max(offset,0);
  40. real areaOfSmallRightTriangle = clampedOffsetRight * clampedOffsetRight;
  41. computedArea.z = computedAreaUncut.z - areaOfSmallRightTriangle;
  42. }
  43. // Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
  44. // This function return the weight of each texels area relative to the full triangle area.
  45. void SampleShadow_GetTexelWeights_Tent_3x3(real offset, out real4 computedWeight)
  46. {
  47. real4 dummy;
  48. SampleShadow_GetTexelAreas_Tent_3x3(offset, computedWeight, dummy);
  49. computedWeight *= 0.44444;//0.44 == 1/(the triangle area)
  50. }
  51. // Assuming a isoceles triangle of 2.5 texel height and 5 texels wide lying on 6 texels.
  52. // This function return the weight of each texels area relative to the full triangle area.
  53. // / \
  54. // _ _ _ _ _ _ <-- texels
  55. // 0 1 2 3 4 5 <-- computed area indices (in texelsWeights[])
  56. void SampleShadow_GetTexelWeights_Tent_5x5(real offset, out real3 texelsWeightsA, out real3 texelsWeightsB)
  57. {
  58. // See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
  59. real4 computedArea_From3texelTriangle;
  60. real4 computedAreaUncut_From3texelTriangle;
  61. SampleShadow_GetTexelAreas_Tent_3x3(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
  62. // Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
  63. // the 5 texel wide triangle can be seen as the 3 texel wide one but shifted up by one unit/texel.
  64. // 0.16 is 1/(the triangle area)
  65. texelsWeightsA.x = 0.16 * (computedArea_From3texelTriangle.x);
  66. texelsWeightsA.y = 0.16 * (computedAreaUncut_From3texelTriangle.y);
  67. texelsWeightsA.z = 0.16 * (computedArea_From3texelTriangle.y + 1);
  68. texelsWeightsB.x = 0.16 * (computedArea_From3texelTriangle.z + 1);
  69. texelsWeightsB.y = 0.16 * (computedAreaUncut_From3texelTriangle.z);
  70. texelsWeightsB.z = 0.16 * (computedArea_From3texelTriangle.w);
  71. }
  72. // Assuming a isoceles triangle of 3.5 texel height and 7 texels wide lying on 8 texels.
  73. // This function return the weight of each texels area relative to the full triangle area.
  74. // / \
  75. // _ _ _ _ _ _ _ _ <-- texels
  76. // 0 1 2 3 4 5 6 7 <-- computed area indices (in texelsWeights[])
  77. void SampleShadow_GetTexelWeights_Tent_7x7(real offset, out real4 texelsWeightsA, out real4 texelsWeightsB)
  78. {
  79. // See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
  80. real4 computedArea_From3texelTriangle;
  81. real4 computedAreaUncut_From3texelTriangle;
  82. SampleShadow_GetTexelAreas_Tent_3x3(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
  83. // Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
  84. // the 7 texel wide triangle can be seen as the 3 texel wide one but shifted up by two unit/texel.
  85. // 0.081632 is 1/(the triangle area)
  86. texelsWeightsA.x = 0.081632 * (computedArea_From3texelTriangle.x);
  87. texelsWeightsA.y = 0.081632 * (computedAreaUncut_From3texelTriangle.y);
  88. texelsWeightsA.z = 0.081632 * (computedAreaUncut_From3texelTriangle.y + 1);
  89. texelsWeightsA.w = 0.081632 * (computedArea_From3texelTriangle.y + 2);
  90. texelsWeightsB.x = 0.081632 * (computedArea_From3texelTriangle.z + 2);
  91. texelsWeightsB.y = 0.081632 * (computedAreaUncut_From3texelTriangle.z + 1);
  92. texelsWeightsB.z = 0.081632 * (computedAreaUncut_From3texelTriangle.z);
  93. texelsWeightsB.w = 0.081632 * (computedArea_From3texelTriangle.w);
  94. }
  95. // 3x3 Tent filter (45 degree sloped triangles in U and V)
  96. void SampleShadow_ComputeSamples_Tent_3x3(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[4], out real2 fetchesUV[4])
  97. {
  98. // tent base is 3x3 base thus covering from 9 to 12 texels, thus we need 4 bilinear PCF fetches
  99. real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
  100. real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
  101. real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
  102. // find the weight of each texel based
  103. real4 texelsWeightsU, texelsWeightsV;
  104. SampleShadow_GetTexelWeights_Tent_3x3(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU);
  105. SampleShadow_GetTexelWeights_Tent_3x3(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV);
  106. // each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
  107. real2 fetchesWeightsU = texelsWeightsU.xz + texelsWeightsU.yw;
  108. real2 fetchesWeightsV = texelsWeightsV.xz + texelsWeightsV.yw;
  109. // move the PCF bilinear fetches to respect texels weights
  110. real2 fetchesOffsetsU = texelsWeightsU.yw / fetchesWeightsU.xy + real2(-1.5,0.5);
  111. real2 fetchesOffsetsV = texelsWeightsV.yw / fetchesWeightsV.xy + real2(-1.5,0.5);
  112. fetchesOffsetsU *= shadowMapTexture_TexelSize.xx;
  113. fetchesOffsetsV *= shadowMapTexture_TexelSize.yy;
  114. real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
  115. fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
  116. fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
  117. fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
  118. fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
  119. fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
  120. fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
  121. fetchesWeights[2] = fetchesWeightsU.x * fetchesWeightsV.y;
  122. fetchesWeights[3] = fetchesWeightsU.y * fetchesWeightsV.y;
  123. }
  124. // 5x5 Tent filter (45 degree sloped triangles in U and V)
  125. void SampleShadow_ComputeSamples_Tent_5x5(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[9], out real2 fetchesUV[9])
  126. {
  127. // tent base is 5x5 base thus covering from 25 to 36 texels, thus we need 9 bilinear PCF fetches
  128. real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
  129. real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
  130. real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
  131. // find the weight of each texel based on the area of a 45 degree slop tent above each of them.
  132. real3 texelsWeightsU_A, texelsWeightsU_B;
  133. real3 texelsWeightsV_A, texelsWeightsV_B;
  134. SampleShadow_GetTexelWeights_Tent_5x5(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
  135. SampleShadow_GetTexelWeights_Tent_5x5(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
  136. // each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
  137. real3 fetchesWeightsU = real3(texelsWeightsU_A.xz, texelsWeightsU_B.y) + real3(texelsWeightsU_A.y, texelsWeightsU_B.xz);
  138. real3 fetchesWeightsV = real3(texelsWeightsV_A.xz, texelsWeightsV_B.y) + real3(texelsWeightsV_A.y, texelsWeightsV_B.xz);
  139. // move the PCF bilinear fetches to respect texels weights
  140. real3 fetchesOffsetsU = real3(texelsWeightsU_A.y, texelsWeightsU_B.xz) / fetchesWeightsU.xyz + real3(-2.5,-0.5,1.5);
  141. real3 fetchesOffsetsV = real3(texelsWeightsV_A.y, texelsWeightsV_B.xz) / fetchesWeightsV.xyz + real3(-2.5,-0.5,1.5);
  142. fetchesOffsetsU *= shadowMapTexture_TexelSize.xxx;
  143. fetchesOffsetsV *= shadowMapTexture_TexelSize.yyy;
  144. real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
  145. fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
  146. fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
  147. fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.x);
  148. fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
  149. fetchesUV[4] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
  150. fetchesUV[5] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.y);
  151. fetchesUV[6] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.z);
  152. fetchesUV[7] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.z);
  153. fetchesUV[8] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.z);
  154. fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
  155. fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
  156. fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;
  157. fetchesWeights[3] = fetchesWeightsU.x * fetchesWeightsV.y;
  158. fetchesWeights[4] = fetchesWeightsU.y * fetchesWeightsV.y;
  159. fetchesWeights[5] = fetchesWeightsU.z * fetchesWeightsV.y;
  160. fetchesWeights[6] = fetchesWeightsU.x * fetchesWeightsV.z;
  161. fetchesWeights[7] = fetchesWeightsU.y * fetchesWeightsV.z;
  162. fetchesWeights[8] = fetchesWeightsU.z * fetchesWeightsV.z;
  163. }
  164. // 7x7 Tent filter (45 degree sloped triangles in U and V)
  165. void SampleShadow_ComputeSamples_Tent_7x7(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[16], out real2 fetchesUV[16])
  166. {
  167. // tent base is 7x7 base thus covering from 49 to 64 texels, thus we need 16 bilinear PCF fetches
  168. real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
  169. real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
  170. real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
  171. // find the weight of each texel based on the area of a 45 degree slop tent above each of them.
  172. real4 texelsWeightsU_A, texelsWeightsU_B;
  173. real4 texelsWeightsV_A, texelsWeightsV_B;
  174. SampleShadow_GetTexelWeights_Tent_7x7(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
  175. SampleShadow_GetTexelWeights_Tent_7x7(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
  176. // each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
  177. real4 fetchesWeightsU = real4(texelsWeightsU_A.xz, texelsWeightsU_B.xz) + real4(texelsWeightsU_A.yw, texelsWeightsU_B.yw);
  178. real4 fetchesWeightsV = real4(texelsWeightsV_A.xz, texelsWeightsV_B.xz) + real4(texelsWeightsV_A.yw, texelsWeightsV_B.yw);
  179. // move the PCF bilinear fetches to respect texels weights
  180. real4 fetchesOffsetsU = real4(texelsWeightsU_A.yw, texelsWeightsU_B.yw) / fetchesWeightsU.xyzw + real4(-3.5,-1.5,0.5,2.5);
  181. real4 fetchesOffsetsV = real4(texelsWeightsV_A.yw, texelsWeightsV_B.yw) / fetchesWeightsV.xyzw + real4(-3.5,-1.5,0.5,2.5);
  182. fetchesOffsetsU *= shadowMapTexture_TexelSize.xxxx;
  183. fetchesOffsetsV *= shadowMapTexture_TexelSize.yyyy;
  184. real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
  185. fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
  186. fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
  187. fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.x);
  188. fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.x);
  189. fetchesUV[4] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
  190. fetchesUV[5] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
  191. fetchesUV[6] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.y);
  192. fetchesUV[7] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.y);
  193. fetchesUV[8] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.z);
  194. fetchesUV[9] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.z);
  195. fetchesUV[10] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.z);
  196. fetchesUV[11] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.z);
  197. fetchesUV[12] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.w);
  198. fetchesUV[13] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.w);
  199. fetchesUV[14] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.w);
  200. fetchesUV[15] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.w);
  201. fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
  202. fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
  203. fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;
  204. fetchesWeights[3] = fetchesWeightsU.w * fetchesWeightsV.x;
  205. fetchesWeights[4] = fetchesWeightsU.x * fetchesWeightsV.y;
  206. fetchesWeights[5] = fetchesWeightsU.y * fetchesWeightsV.y;
  207. fetchesWeights[6] = fetchesWeightsU.z * fetchesWeightsV.y;
  208. fetchesWeights[7] = fetchesWeightsU.w * fetchesWeightsV.y;
  209. fetchesWeights[8] = fetchesWeightsU.x * fetchesWeightsV.z;
  210. fetchesWeights[9] = fetchesWeightsU.y * fetchesWeightsV.z;
  211. fetchesWeights[10] = fetchesWeightsU.z * fetchesWeightsV.z;
  212. fetchesWeights[11] = fetchesWeightsU.w * fetchesWeightsV.z;
  213. fetchesWeights[12] = fetchesWeightsU.x * fetchesWeightsV.w;
  214. fetchesWeights[13] = fetchesWeightsU.y * fetchesWeightsV.w;
  215. fetchesWeights[14] = fetchesWeightsU.z * fetchesWeightsV.w;
  216. fetchesWeights[15] = fetchesWeightsU.w * fetchesWeightsV.w;
  217. }