VolumeRendering.hlsl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. #ifndef UNITY_VOLUME_RENDERING_INCLUDED
  2. #define UNITY_VOLUME_RENDERING_INCLUDED
  3. // Reminder:
  4. // OpticalDepth(x, y) = Integral{x, y}{Extinction(t) dt}
  5. // Transmittance(x, y) = Exp(-OpticalDepth(x, y))
  6. // Transmittance(x, z) = Transmittance(x, y) * Transmittance(y, z)
  7. // Integral{a, b}{Transmittance(0, t) dt} = Transmittance(0, a) * Integral{a, b}{Transmittance(0, t - a) dt}
  8. real TransmittanceFromOpticalDepth(real opticalDepth)
  9. {
  10. return exp(-opticalDepth);
  11. }
  12. real3 TransmittanceFromOpticalDepth(real3 opticalDepth)
  13. {
  14. return exp(-opticalDepth);
  15. }
  16. real OpacityFromOpticalDepth(real opticalDepth)
  17. {
  18. return 1 - TransmittanceFromOpticalDepth(opticalDepth);
  19. }
  20. real3 OpacityFromOpticalDepth(real3 opticalDepth)
  21. {
  22. return 1 - TransmittanceFromOpticalDepth(opticalDepth);
  23. }
  24. real OpticalDepthFromOpacity(real opacity)
  25. {
  26. return -log(1 - opacity);
  27. }
  28. real3 OpticalDepthFromOpacity(real3 opacity)
  29. {
  30. return -log(1 - opacity);
  31. }
  32. //
  33. // ---------------------------------- Deep Pixel Compositing ---------------------------------------
  34. //
  35. // TODO: it would be good to improve the perf and numerical stability
  36. // of approximations below by finding a polynomial approximation.
  37. // input = {radiance, opacity}
  38. // Note that opacity must be less than 1 (not fully opaque).
  39. real4 LinearizeRGBA(real4 value)
  40. {
  41. // See "Deep Compositing Using Lie Algebras".
  42. // log(A) = {OpticalDepthFromOpacity(A.a) / A.a * A.rgb, -OpticalDepthFromOpacity(A.a)}.
  43. // We drop redundant negations.
  44. real a = value.a;
  45. real d = -log(1 - a);
  46. real r = (a >= REAL_EPS) ? (d * rcp(a)) : 1; // Prevent numerical explosion
  47. return real4(r * value.rgb, d);
  48. }
  49. // input = {radiance, optical_depth}
  50. // Note that opacity must be less than 1 (not fully opaque).
  51. real4 LinearizeRGBD(real4 value)
  52. {
  53. // See "Deep Compositing Using Lie Algebras".
  54. // log(A) = {A.a / OpacityFromOpticalDepth(A.a) * A.rgb, -A.a}.
  55. // We drop redundant negations.
  56. real d = value.a;
  57. real a = 1 - exp(-d);
  58. real r = (a >= REAL_EPS) ? (d * rcp(a)) : 1; // Prevent numerical explosion
  59. return real4(r * value.rgb, d);
  60. }
  61. // output = {radiance, opacity}
  62. // Note that opacity must be less than 1 (not fully opaque).
  63. real4 DelinearizeRGBA(real4 value)
  64. {
  65. // See "Deep Compositing Using Lie Algebras".
  66. // exp(B) = {OpacityFromOpticalDepth(-B.a) / -B.a * B.rgb, OpacityFromOpticalDepth(-B.a)}.
  67. // We drop redundant negations.
  68. real d = value.a;
  69. real a = 1 - exp(-d);
  70. real i = (a >= REAL_EPS) ? (a * rcp(d)) : 1; // Prevent numerical explosion
  71. return real4(i * value.rgb, a);
  72. }
  73. // input = {radiance, optical_depth}
  74. // Note that opacity must be less than 1 (not fully opaque).
  75. real4 DelinearizeRGBD(real4 value)
  76. {
  77. // See "Deep Compositing Using Lie Algebras".
  78. // exp(B) = {OpacityFromOpticalDepth(-B.a) / -B.a * B.rgb, -B.a}.
  79. // We drop redundant negations.
  80. real d = value.a;
  81. real a = 1 - exp(-d);
  82. real i = (a >= REAL_EPS) ? (a * rcp(d)) : 1; // Prevent numerical explosion
  83. return real4(i * value.rgb, d);
  84. }
  85. //
  86. // ----------------------------- Homogeneous Participating Media -----------------------------------
  87. //
  88. real OpticalDepthHomogeneousMedium(real extinction, real intervalLength)
  89. {
  90. return extinction * intervalLength;
  91. }
  92. real TransmittanceHomogeneousMedium(real extinction, real intervalLength)
  93. {
  94. return TransmittanceFromOpticalDepth(OpticalDepthHomogeneousMedium(extinction, intervalLength));
  95. }
  96. // Integral{a, b}{TransmittanceHomogeneousMedium(k, t - a) dt}.
  97. real TransmittanceIntegralHomogeneousMedium(real extinction, real intervalLength)
  98. {
  99. // Note: when multiplied by the extinction coefficient, it becomes
  100. // Albedo * (1 - TransmittanceFromOpticalDepth(d)) = Albedo * Opacity(d).
  101. return rcp(extinction) - rcp(extinction) * exp(-extinction * intervalLength);
  102. }
  103. //
  104. // ----------------------------------- Height Fog --------------------------------------------------
  105. //
  106. // Can be used to scale base extinction and scattering coefficients.
  107. real ComputeHeightFogMultiplier(real height, real baseHeight, real2 heightExponents)
  108. {
  109. real h = max(height - baseHeight, 0);
  110. real rcpH = heightExponents.x;
  111. return exp(-h * rcpH);
  112. }
  113. // Optical depth between two endpoints.
  114. real OpticalDepthHeightFog(real baseExtinction, real baseHeight, real2 heightExponents,
  115. real cosZenith, real startHeight, real intervalLength)
  116. {
  117. // Height fog is composed of two slices of optical depth:
  118. // - homogeneous fog below 'baseHeight': d = k * t
  119. // - exponential fog above 'baseHeight': d = Integrate[k * e^(-(h + z * x) / H) dx, {x, 0, t}]
  120. real H = heightExponents.y;
  121. real rcpH = heightExponents.x;
  122. real Z = cosZenith;
  123. real absZ = max(abs(cosZenith), 0.001f);
  124. real rcpAbsZ = rcp(absZ);
  125. real endHeight = startHeight + intervalLength * Z;
  126. real minHeight = min(startHeight, endHeight);
  127. real h = max(minHeight - baseHeight, 0);
  128. real homFogDist = clamp((baseHeight - minHeight) * rcpAbsZ, 0, intervalLength);
  129. real expFogDist = intervalLength - homFogDist;
  130. real expFogMult = exp(-h * rcpH) * (1 - exp(-expFogDist * absZ * rcpH)) * (rcpAbsZ * H);
  131. return baseExtinction * (homFogDist + expFogMult);
  132. }
  133. // This version of the function assumes the interval of infinite length.
  134. real OpticalDepthHeightFog(real baseExtinction, real baseHeight, real2 heightExponents,
  135. real cosZenith, real startHeight)
  136. {
  137. real H = heightExponents.y;
  138. real rcpH = heightExponents.x;
  139. real Z = cosZenith;
  140. real absZ = max(abs(cosZenith), REAL_EPS);
  141. real rcpAbsZ = rcp(absZ);
  142. real minHeight = (Z >= 0) ? startHeight : -rcp(REAL_EPS);
  143. real h = max(minHeight - baseHeight, 0);
  144. real homFogDist = max((baseHeight - minHeight) * rcpAbsZ, 0);
  145. real expFogMult = exp(-h * rcpH) * (rcpAbsZ * H);
  146. return baseExtinction * (homFogDist + expFogMult);
  147. }
  148. real TransmittanceHeightFog(real baseExtinction, real baseHeight, real2 heightExponents,
  149. real cosZenith, real startHeight, real intervalLength)
  150. {
  151. real od = OpticalDepthHeightFog(baseExtinction, baseHeight, heightExponents,
  152. cosZenith, startHeight, intervalLength);
  153. return TransmittanceFromOpticalDepth(od);
  154. }
  155. real TransmittanceHeightFog(real baseExtinction, real baseHeight, real2 heightExponents,
  156. real cosZenith, real startHeight)
  157. {
  158. real od = OpticalDepthHeightFog(baseExtinction, baseHeight, heightExponents,
  159. cosZenith, startHeight);
  160. return TransmittanceFromOpticalDepth(od);
  161. }
  162. //
  163. // ----------------------------------- Phase Functions ---------------------------------------------
  164. //
  165. real IsotropicPhaseFunction()
  166. {
  167. return INV_FOUR_PI;
  168. }
  169. real RayleighPhaseFunction(real cosTheta)
  170. {
  171. real k = 3 / (16 * PI);
  172. return k * (1 + cosTheta * cosTheta);
  173. }
  174. real HenyeyGreensteinPhasePartConstant(real anisotropy)
  175. {
  176. real g = anisotropy;
  177. return INV_FOUR_PI * (1 - g * g);
  178. }
  179. real HenyeyGreensteinPhasePartVarying(real anisotropy, real cosTheta)
  180. {
  181. real g = anisotropy;
  182. real x = 1 + g * g - 2 * g * cosTheta;
  183. real f = rsqrt(max(x, REAL_EPS)); // x^(-1/2)
  184. return f * f * f; // x^(-3/2)
  185. }
  186. real HenyeyGreensteinPhaseFunction(real anisotropy, real cosTheta)
  187. {
  188. return HenyeyGreensteinPhasePartConstant(anisotropy) *
  189. HenyeyGreensteinPhasePartVarying(anisotropy, cosTheta);
  190. }
  191. real CornetteShanksPhasePartConstant(real anisotropy)
  192. {
  193. real g = anisotropy;
  194. return (3 / (8 * PI)) * (1 - g * g) / (2 + g * g);
  195. }
  196. // Similar to the RayleighPhaseFunction.
  197. real CornetteShanksPhasePartSymmetrical(real cosTheta)
  198. {
  199. real h = 1 + cosTheta * cosTheta;
  200. return h;
  201. }
  202. real CornetteShanksPhasePartAsymmetrical(real anisotropy, real cosTheta)
  203. {
  204. real g = anisotropy;
  205. real x = 1 + g * g - 2 * g * cosTheta;
  206. real f = rsqrt(max(x, REAL_EPS)); // x^(-1/2)
  207. return f * f * f; // x^(-3/2)
  208. }
  209. real CornetteShanksPhasePartVarying(real anisotropy, real cosTheta)
  210. {
  211. return CornetteShanksPhasePartSymmetrical(cosTheta) *
  212. CornetteShanksPhasePartAsymmetrical(anisotropy, cosTheta); // h * x^(-3/2)
  213. }
  214. // A better approximation of the Mie phase function.
  215. // Ref: Henyey-Greenstein and Mie phase functions in Monte Carlo radiative transfer computations
  216. real CornetteShanksPhaseFunction(real anisotropy, real cosTheta)
  217. {
  218. return CornetteShanksPhasePartConstant(anisotropy) *
  219. CornetteShanksPhasePartVarying(anisotropy, cosTheta);
  220. }
  221. //
  222. // --------------------------------- Importance Sampling -------------------------------------------
  223. //
  224. // Samples the interval of homogeneous participating medium using the closed-form tracking approach
  225. // (proportionally to the transmittance).
  226. // Returns the offset from the start of the interval and the weight = (transmittance / pdf).
  227. // Ref: Monte Carlo Methods for Volumetric Light Transport Simulation, p. 5.
  228. void ImportanceSampleHomogeneousMedium(real rndVal, real extinction, real intervalLength,
  229. out real offset, out real weight)
  230. {
  231. // pdf = extinction * exp(extinction * (intervalLength - t)) / (exp(intervalLength * extinction) - 1)
  232. // pdf = extinction * exp(-extinction * t) / (1 - exp(-extinction * intervalLength))
  233. // weight = TransmittanceFromOpticalDepth(t) / pdf
  234. // weight = exp(-extinction * t) / pdf
  235. // weight = (1 - exp(-extinction * intervalLength)) / extinction
  236. // weight = OpacityFromOpticalDepth(extinction * intervalLength) / extinction
  237. real x = 1 - exp(-extinction * intervalLength);
  238. real c = rcp(extinction);
  239. // TODO: return 'rcpPdf' to support imperfect importance sampling...
  240. weight = x * c;
  241. offset = -log(1 - rndVal * x) * c;
  242. }
  243. void ImportanceSampleExponentialMedium(real rndVal, real extinction, real falloff,
  244. out real offset, out real rcpPdf)
  245. {
  246. // Extinction[t] = Extinction[0] * exp(-falloff * t).
  247. real c = extinction;
  248. real a = falloff;
  249. // TODO: optimize...
  250. offset = -log(1 - a / c * log(rndVal)) / a;
  251. rcpPdf = rcp(c * exp(-a * offset) * exp(-c / a * (1 - exp(-a * offset))));
  252. }
  253. // Implements equiangular light sampling.
  254. // Returns the distance from the origin of the ray, the squared distance from the light,
  255. // and the reciprocal of the PDF.
  256. // Ref: Importance Sampling of Area Lights in Participating Medium.
  257. void ImportanceSamplePunctualLight(real rndVal, real3 lightPosition, real lightSqRadius,
  258. real3 rayOrigin, real3 rayDirection,
  259. real tMin, real tMax,
  260. out real t, out real sqDist, out real rcpPdf)
  261. {
  262. real3 originToLight = lightPosition - rayOrigin;
  263. real originToLightProjDist = dot(originToLight, rayDirection);
  264. real originToLightSqDist = dot(originToLight, originToLight);
  265. real rayToLightSqDist = originToLightSqDist - originToLightProjDist * originToLightProjDist;
  266. // Virtually offset the light to modify the PDF distribution.
  267. real sqD = max(rayToLightSqDist + lightSqRadius, REAL_EPS);
  268. real rcpD = rsqrt(sqD);
  269. real d = sqD * rcpD;
  270. real a = tMin - originToLightProjDist;
  271. real b = tMax - originToLightProjDist;
  272. real x = a * rcpD;
  273. real y = b * rcpD;
  274. #if 0
  275. real theta0 = FastATan(x);
  276. real theta1 = FastATan(y);
  277. real gamma = theta1 - theta0;
  278. real tanTheta = tan(theta0 + rndVal * gamma);
  279. #else
  280. // Same but faster:
  281. // atan(y) - atan(x) = atan((y - x) / (1 + x * y))
  282. // tan(atan(x) + z) = (x * cos(z) + sin(z)) / (cos(z) - x * sin(z))
  283. // Both the tangent and the angle cannot be negative.
  284. real tanGamma = abs((y - x) * rcp(max(0, 1 + x * y)));
  285. real gamma = FastATanPos(tanGamma);
  286. real z = rndVal * gamma;
  287. real numer = x * cos(z) + sin(z);
  288. real denom = cos(z) - x * sin(z);
  289. real tanTheta = numer * rcp(denom);
  290. #endif
  291. real tRelative = d * tanTheta;
  292. sqDist = sqD + tRelative * tRelative;
  293. rcpPdf = gamma * rcpD * sqDist;
  294. t = originToLightProjDist + tRelative;
  295. // Remove the virtual light offset to obtain the real geometric distance.
  296. sqDist = max(sqDist - lightSqRadius, REAL_EPS);
  297. }
  298. // Returns the cosine.
  299. // Weight = Phase / Pdf = 1.
  300. real ImportanceSampleRayleighPhase(real rndVal)
  301. {
  302. // real a = sqrt(16 * (rndVal - 1) * rndVal + 5);
  303. // real b = -4 * rndVal + a + 2;
  304. // real c = PositivePow(b, 0.33333333);
  305. // return rcp(c) - c;
  306. // Approximate...
  307. return lerp(cos(PI * rndVal + PI), 2 * rndVal - 1, 0.5);
  308. }
  309. //
  310. // ------------------------------------ Miscellaneous ----------------------------------------------
  311. //
  312. // Absorption coefficient from Disney: http://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf
  313. real3 TransmittanceColorAtDistanceToAbsorption(real3 transmittanceColor, real atDistance)
  314. {
  315. return -log(transmittanceColor + REAL_EPS) / max(atDistance, REAL_EPS);
  316. }
  317. #endif // UNITY_VOLUME_RENDERING_INCLUDED