Sampling.hlsl 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #ifndef UNITY_SAMPLING_INCLUDED
  2. #define UNITY_SAMPLING_INCLUDED
  3. //-----------------------------------------------------------------------------
  4. // Sample generator
  5. //-----------------------------------------------------------------------------
  6. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Fibonacci.hlsl"
  7. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Hammersley.hlsl"
  8. //-----------------------------------------------------------------------------
  9. // Coordinate system conversion
  10. //-----------------------------------------------------------------------------
  11. // Transforms the unit vector from the spherical to the Cartesian (right-handed, Z up) coordinate.
  12. real3 SphericalToCartesian(real cosPhi, real sinPhi, real cosTheta)
  13. {
  14. real sinTheta = SinFromCos(cosTheta);
  15. return real3(real2(cosPhi, sinPhi) * sinTheta, cosTheta);
  16. }
  17. real3 SphericalToCartesian(real phi, real cosTheta)
  18. {
  19. real sinPhi, cosPhi;
  20. sincos(phi, sinPhi, cosPhi);
  21. return SphericalToCartesian(cosPhi, sinPhi, cosTheta);
  22. }
  23. // Converts Cartesian coordinates given in the right-handed coordinate system
  24. // with Z pointing upwards (OpenGL style) to the coordinates in the left-handed
  25. // coordinate system with Y pointing up and Z facing forward (DirectX style).
  26. real3 TransformGLtoDX(real3 v)
  27. {
  28. return v.xzy;
  29. }
  30. // Performs conversion from equiareal map coordinates to Cartesian (DirectX cubemap) ones.
  31. real3 ConvertEquiarealToCubemap(real u, real v)
  32. {
  33. real phi = TWO_PI - TWO_PI * u;
  34. real cosTheta = 1.0 - 2.0 * v;
  35. return TransformGLtoDX(SphericalToCartesian(phi, cosTheta));
  36. }
  37. // Convert a texel position into normalized position [-1..1]x[-1..1]
  38. real2 CubemapTexelToNVC(uint2 unPositionTXS, uint cubemapSize)
  39. {
  40. return 2.0 * real2(unPositionTXS) / real(max(cubemapSize - 1, 1)) - 1.0;
  41. }
  42. // Map cubemap face to world vector basis
  43. static const real3 CUBEMAP_FACE_BASIS_MAPPING[6][3] =
  44. {
  45. //XPOS face
  46. {
  47. real3(0.0, 0.0, -1.0),
  48. real3(0.0, -1.0, 0.0),
  49. real3(1.0, 0.0, 0.0)
  50. },
  51. //XNEG face
  52. {
  53. real3(0.0, 0.0, 1.0),
  54. real3(0.0, -1.0, 0.0),
  55. real3(-1.0, 0.0, 0.0)
  56. },
  57. //YPOS face
  58. {
  59. real3(1.0, 0.0, 0.0),
  60. real3(0.0, 0.0, 1.0),
  61. real3(0.0, 1.0, 0.0)
  62. },
  63. //YNEG face
  64. {
  65. real3(1.0, 0.0, 0.0),
  66. real3(0.0, 0.0, -1.0),
  67. real3(0.0, -1.0, 0.0)
  68. },
  69. //ZPOS face
  70. {
  71. real3(1.0, 0.0, 0.0),
  72. real3(0.0, -1.0, 0.0),
  73. real3(0.0, 0.0, 1.0)
  74. },
  75. //ZNEG face
  76. {
  77. real3(-1.0, 0.0, 0.0),
  78. real3(0.0, -1.0, 0.0),
  79. real3(0.0, 0.0, -1.0)
  80. }
  81. };
  82. // Convert a normalized cubemap face position into a direction
  83. real3 CubemapTexelToDirection(real2 positionNVC, uint faceId)
  84. {
  85. real3 dir = CUBEMAP_FACE_BASIS_MAPPING[faceId][0] * positionNVC.x
  86. + CUBEMAP_FACE_BASIS_MAPPING[faceId][1] * positionNVC.y
  87. + CUBEMAP_FACE_BASIS_MAPPING[faceId][2];
  88. return normalize(dir);
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Sampling function
  92. // Reference : http://www.cs.virginia.edu/~jdl/bib/globillum/mis/shirley96.pdf + PBRT
  93. //-----------------------------------------------------------------------------
  94. // Performs uniform sampling of the unit disk.
  95. // Ref: PBRT v3, p. 777.
  96. real2 SampleDiskUniform(real u1, real u2)
  97. {
  98. real r = sqrt(u1);
  99. real phi = TWO_PI * u2;
  100. real sinPhi, cosPhi;
  101. sincos(phi, sinPhi, cosPhi);
  102. return r * real2(cosPhi, sinPhi);
  103. }
  104. real3 SampleConeUniform(real u1, real u2, real cos_theta)
  105. {
  106. float r0 = cos_theta + u1 * (1.0f - cos_theta);
  107. float r = sqrt(max(0.0, 1.0 - r0 * r0));
  108. float phi = TWO_PI * u2;
  109. return float3(r * cos(phi), r * sin(phi), r0);
  110. }
  111. real3 SampleSphereUniform(real u1, real u2)
  112. {
  113. real phi = TWO_PI * u2;
  114. real cosTheta = 1.0 - 2.0 * u1;
  115. return SphericalToCartesian(phi, cosTheta);
  116. }
  117. // Performs cosine-weighted sampling of the hemisphere.
  118. // Ref: PBRT v3, p. 780.
  119. real3 SampleHemisphereCosine(real u1, real u2)
  120. {
  121. real3 localL;
  122. // Since we don't really care about the area distortion,
  123. // we substitute uniform disk sampling for the concentric one.
  124. localL.xy = SampleDiskUniform(u1, u2);
  125. // Project the point from the disk onto the hemisphere.
  126. localL.z = sqrt(1.0 - u1);
  127. return localL;
  128. }
  129. // Cosine-weighted sampling without the tangent frame.
  130. // Ref: http://www.amietia.com/lambertnotangent.html
  131. real3 SampleHemisphereCosine(real u1, real u2, real3 normal)
  132. {
  133. real3 pointOnSphere = SampleSphereUniform(u1, u2);
  134. return normalize(normal + pointOnSphere);
  135. }
  136. real3 SampleHemisphereUniform(real u1, real u2)
  137. {
  138. real phi = TWO_PI * u2;
  139. real cosTheta = 1.0 - u1;
  140. return SphericalToCartesian(phi, cosTheta);
  141. }
  142. void SampleSphere(real2 u,
  143. real4x4 localToWorld,
  144. real radius,
  145. out real lightPdf,
  146. out real3 P,
  147. out real3 Ns)
  148. {
  149. real u1 = u.x;
  150. real u2 = u.y;
  151. Ns = SampleSphereUniform(u1, u2);
  152. // Transform from unit sphere to world space
  153. P = radius * Ns + localToWorld[3].xyz;
  154. // pdf is inverse of area
  155. lightPdf = 1.0 / (FOUR_PI * radius * radius);
  156. }
  157. void SampleHemisphere(real2 u,
  158. real4x4 localToWorld,
  159. real radius,
  160. out real lightPdf,
  161. out real3 P,
  162. out real3 Ns)
  163. {
  164. real u1 = u.x;
  165. real u2 = u.y;
  166. // Random point at hemisphere surface
  167. Ns = -SampleHemisphereUniform(u1, u2); // We want the y down hemisphere
  168. P = radius * Ns;
  169. // Transform to world space
  170. P = mul(real4(P, 1.0), localToWorld).xyz;
  171. Ns = mul(Ns, (real3x3)(localToWorld));
  172. // pdf is inverse of area
  173. lightPdf = 1.0 / (TWO_PI * radius * radius);
  174. }
  175. // Note: The cylinder has no end caps (i.e. no disk on the side)
  176. void SampleCylinder(real2 u,
  177. real4x4 localToWorld,
  178. real radius,
  179. real width,
  180. out real lightPdf,
  181. out real3 P,
  182. out real3 Ns)
  183. {
  184. real u1 = u.x;
  185. real u2 = u.y;
  186. // Random point at cylinder surface
  187. real t = (u1 - 0.5) * width;
  188. real theta = 2.0 * PI * u2;
  189. real cosTheta = cos(theta);
  190. real sinTheta = sin(theta);
  191. // Cylinder are align on the right axis
  192. P = real3(t, radius * cosTheta, radius * sinTheta);
  193. Ns = normalize(real3(0.0, cosTheta, sinTheta));
  194. // Transform to world space
  195. P = mul(real4(P, 1.0), localToWorld).xyz;
  196. Ns = mul(Ns, (real3x3)(localToWorld));
  197. // pdf is inverse of area
  198. lightPdf = 1.0 / (TWO_PI * radius * width);
  199. }
  200. void SampleRectangle(real2 u,
  201. real4x4 localToWorld,
  202. real width,
  203. real height,
  204. out real lightPdf,
  205. out real3 P,
  206. out real3 Ns)
  207. {
  208. // Random point at rectangle surface
  209. P = real3((u.x - 0.5) * width, (u.y - 0.5) * height, 0);
  210. Ns = real3(0, 0, -1); // Light down (-Z)
  211. // Transform to world space
  212. P = mul(real4(P, 1.0), localToWorld).xyz;
  213. Ns = mul(Ns, (real3x3)(localToWorld));
  214. // pdf is inverse of area
  215. lightPdf = 1.0 / (width * height);
  216. }
  217. void SampleDisk(real2 u,
  218. real4x4 localToWorld,
  219. real radius,
  220. out real lightPdf,
  221. out real3 P,
  222. out real3 Ns)
  223. {
  224. // Random point at disk surface
  225. P = real3(radius * SampleDiskUniform(u.x, u.y), 0);
  226. Ns = real3(0.0, 0.0, -1.0); // Light down (-Z)
  227. // Transform to world space
  228. P = mul(real4(P, 1.0), localToWorld).xyz;
  229. Ns = mul(Ns, (real3x3)(localToWorld));
  230. // pdf is inverse of area
  231. lightPdf = 1.0 / (PI * radius * radius);
  232. }
  233. // Solid angle cone sampling.
  234. // Takes the cosine of the aperture as an input.
  235. void SampleCone(real2 u, real cosHalfAngle,
  236. out real3 dir, out real rcpPdf)
  237. {
  238. real cosTheta = lerp(1, cosHalfAngle, u.x);
  239. real phi = TWO_PI * u.y;
  240. dir = SphericalToCartesian(phi, cosTheta);
  241. rcpPdf = TWO_PI * (1 - cosHalfAngle);
  242. }
  243. #endif // UNITY_SAMPLING_INCLUDED