暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

VolumeRendering.hlsl 15KB

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