설명 없음
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BSDF.hlsl 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. #ifndef UNITY_BSDF_INCLUDED
  2. #define UNITY_BSDF_INCLUDED
  3. #if SHADER_API_MOBILE || SHADER_API_GLES3 || SHADER_API_SWITCH || defined(UNITY_UNIFIED_SHADER_PRECISION_MODEL)
  4. #pragma warning (disable : 3205) // conversion of larger type to smaller
  5. #endif
  6. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
  7. // Note: All NDF and diffuse term have a version with and without divide by PI.
  8. // Version with divide by PI are use for direct lighting.
  9. // Version without divide by PI are use for image based lighting where often the PI cancel during importance sampling
  10. //-----------------------------------------------------------------------------
  11. // Help for BSDF evaluation
  12. //-----------------------------------------------------------------------------
  13. // Cosine-weighted BSDF (a BSDF taking the projected solid angle into account).
  14. // If some of the values are monochromatic, the compiler will optimize accordingly.
  15. struct CBSDF
  16. {
  17. float3 diffR; // Diffuse reflection (T -> MS -> T, same sides)
  18. float3 specR; // Specular reflection (R, RR, TRT, etc)
  19. float3 diffT; // Diffuse transmission (rough T or TT, opposite sides)
  20. float3 specT; // Specular transmission (T, TT, TRRT, etc)
  21. };
  22. //-----------------------------------------------------------------------------
  23. // Fresnel term
  24. //-----------------------------------------------------------------------------
  25. real F_Schlick(real f0, real f90, real u)
  26. {
  27. real x = 1.0 - u;
  28. real x2 = x * x;
  29. real x5 = x * x2 * x2;
  30. return (f90 - f0) * x5 + f0; // sub mul mul mul sub mad
  31. }
  32. real F_Schlick(real f0, real u)
  33. {
  34. return F_Schlick(f0, 1.0, u); // sub mul mul mul sub mad
  35. }
  36. real3 F_Schlick(real3 f0, real f90, real u)
  37. {
  38. real x = 1.0 - u;
  39. real x2 = x * x;
  40. real x5 = x * x2 * x2;
  41. return f0 * (1.0 - x5) + (f90 * x5); // sub mul mul mul sub mul mad*3
  42. }
  43. real3 F_Schlick(real3 f0, real u)
  44. {
  45. return F_Schlick(f0, 1.0, u); // sub mul mul mul sub mad*3
  46. }
  47. // Does not handle TIR.
  48. real F_Transm_Schlick(real f0, real f90, real u)
  49. {
  50. real x = 1.0 - u;
  51. real x2 = x * x;
  52. real x5 = x * x2 * x2;
  53. return (1.0 - f90 * x5) - f0 * (1.0 - x5); // sub mul mul mul mad sub mad
  54. }
  55. // Does not handle TIR.
  56. real F_Transm_Schlick(real f0, real u)
  57. {
  58. return F_Transm_Schlick(f0, 1.0, u); // sub mul mul mad mad
  59. }
  60. // Does not handle TIR.
  61. real3 F_Transm_Schlick(real3 f0, real f90, real u)
  62. {
  63. real x = 1.0 - u;
  64. real x2 = x * x;
  65. real x5 = x * x2 * x2;
  66. return (1.0 - f90 * x5) - f0 * (1.0 - x5); // sub mul mul mul mad sub mad*3
  67. }
  68. // Does not handle TIR.
  69. real3 F_Transm_Schlick(real3 f0, real u)
  70. {
  71. return F_Transm_Schlick(f0, 1.0, u); // sub mul mul mad mad*3
  72. }
  73. // Compute the cos of critical angle: cos(asin(eta)) == sqrt(1.0 - eta*eta)
  74. // eta == IORMedium/IORSource
  75. // If eta >= 1 the it's an AirMedium interation, otherwise it's MediumAir interation
  76. real CosCriticalAngle(real eta)
  77. {
  78. return sqrt(max(1.0 - Sq(eta), 0.0));
  79. // For 1 <= IOR <= 4: Max error: 0.0268594
  80. //return eta >= 1.0 ? 0.0 : (((3.0 + eta) * sqrt(max(0.0, 1.0 - eta))) / (2.0 * sqrt(2.0)));
  81. // For 1 <= IOR <= 4: Max error: 0.00533065
  82. //return eta >= 1.0 ? 0.0 : (-((-23.0 - 10.0 * eta + Sq(eta)) * sqrt(max(0.0, 1.0 - eta))) / (16.0 * sqrt(2.0)));
  83. // For 1 <= IOR <= 4: Max error: 0.00129402
  84. //return eta >= 1.0 ? 0.0 : (((91.0 + 43.0 * eta - 7.0 * Sq(eta) + pow(eta, 3)) * sqrt(max(0.0, 1.0 - eta))) / (64. * sqrt(2.0)));
  85. }
  86. // Ref: https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/
  87. // Fresnel dielectric / dielectric
  88. real F_FresnelDielectric(real ior, real u)
  89. {
  90. real g = sqrt(Sq(ior) + Sq(u) - 1.0);
  91. // The "1.0 - saturate(1.0 - result)" formulation allows to recover form cases where g is undefined, for IORs < 1
  92. return 1.0 - saturate(1.0 - 0.5 * Sq((g - u) / (g + u)) * (1.0 + Sq(((g + u) * u - 1.0) / ((g - u) * u + 1.0))));
  93. }
  94. // Fresnel dieletric / conductor
  95. // Note: etak2 = etak * etak (optimization for Artist Friendly Metallic Fresnel below)
  96. // eta = eta_t / eta_i and etak = k_t / n_i
  97. real3 F_FresnelConductor(real3 eta, real3 etak2, real cosTheta)
  98. {
  99. real cosTheta2 = cosTheta * cosTheta;
  100. real sinTheta2 = 1.0 - cosTheta2;
  101. real3 eta2 = eta * eta;
  102. real3 t0 = eta2 - etak2 - sinTheta2;
  103. real3 a2plusb2 = sqrt(t0 * t0 + 4.0 * eta2 * etak2);
  104. real3 t1 = a2plusb2 + cosTheta2;
  105. real3 a = sqrt(0.5 * (a2plusb2 + t0));
  106. real3 t2 = 2.0 * a * cosTheta;
  107. real3 Rs = (t1 - t2) / (t1 + t2);
  108. real3 t3 = cosTheta2 * a2plusb2 + sinTheta2 * sinTheta2;
  109. real3 t4 = t2 * sinTheta2;
  110. real3 Rp = Rs * (t3 - t4) / (t3 + t4);
  111. return 0.5 * (Rp + Rs);
  112. }
  113. // Conversion FO/IOR
  114. TEMPLATE_2_FLT_HALF(IorToFresnel0, transmittedIor, incidentIor, return Sq((transmittedIor - incidentIor) / (transmittedIor + incidentIor)) )
  115. // ior is a value between 1.0 and 3.0. 1.0 is air interface
  116. real IorToFresnel0(real transmittedIor)
  117. {
  118. return IorToFresnel0(transmittedIor, 1.0);
  119. }
  120. // Assume air interface for top
  121. // Note: We don't handle the case fresnel0 == 1
  122. //real Fresnel0ToIor(real fresnel0)
  123. //{
  124. // real sqrtF0 = sqrt(fresnel0);
  125. // return (1.0 + sqrtF0) / (1.0 - sqrtF0);
  126. //}
  127. TEMPLATE_1_FLT_HALF(Fresnel0ToIor, fresnel0, return ((1.0 + sqrt(fresnel0)) / (1.0 - sqrt(fresnel0))) )
  128. // This function is a coarse approximation of computing fresnel0 for a different top than air (here clear coat of IOR 1.5) when we only have fresnel0 with air interface
  129. // This function is equivalent to IorToFresnel0(Fresnel0ToIor(fresnel0), 1.5)
  130. // mean
  131. // real sqrtF0 = sqrt(fresnel0);
  132. // return Sq(1.0 - 5.0 * sqrtF0) / Sq(5.0 - sqrtF0);
  133. // Optimization: Fit of the function (3 mad) for range [0.04 (should return 0), 1 (should return 1)]
  134. TEMPLATE_1_FLT_HALF(ConvertF0ForAirInterfaceToF0ForClearCoat15, fresnel0, return saturate(-0.0256868 + fresnel0 * (0.326846 + (0.978946 - 0.283835 * fresnel0) * fresnel0)))
  135. // Even coarser approximation of ConvertF0ForAirInterfaceToF0ForClearCoat15 (above) for mobile (2 mad)
  136. TEMPLATE_1_FLT_HALF(ConvertF0ForAirInterfaceToF0ForClearCoat15Fast, fresnel0, return saturate(fresnel0 * (fresnel0 * 0.526868 + 0.529324) - 0.0482256))
  137. // Artist Friendly Metallic Fresnel Ref: http://jcgt.org/published/0003/04/03/paper.pdf
  138. real3 GetIorN(real3 f0, real3 edgeTint)
  139. {
  140. real3 sqrtF0 = sqrt(f0);
  141. return lerp((1.0 - f0) / (1.0 + f0), (1.0 + sqrtF0) / (1.0 - sqrt(f0)), edgeTint);
  142. }
  143. real3 getIorK2(real3 f0, real3 n)
  144. {
  145. real3 nf0 = Sq(n + 1.0) * f0 - Sq(f0 - 1.0);
  146. return nf0 / (1.0 - f0);
  147. }
  148. // same as regular refract except there is not the test for total internal reflection + the vector is flipped for processing
  149. real3 CoatRefract(real3 X, real3 N, real ieta)
  150. {
  151. real XdotN = saturate(dot(N, X));
  152. return ieta * X + (sqrt(1 + ieta * ieta * (XdotN * XdotN - 1)) - ieta * XdotN) * N;
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Specular BRDF
  156. //-----------------------------------------------------------------------------
  157. float Lambda_GGX(float roughness, float3 V)
  158. {
  159. return 0.5 * (sqrt(1.0 + (Sq(roughness * V.x) + Sq(roughness * V.y)) / Sq(V.z)) - 1.0);
  160. }
  161. real D_GGXNoPI(real NdotH, real roughness)
  162. {
  163. real a2 = Sq(roughness);
  164. real s = (NdotH * a2 - NdotH) * NdotH + 1.0;
  165. // If roughness is 0, returns (NdotH == 1 ? 1 : 0).
  166. // That is, it returns 1 for perfect mirror reflection, and 0 otherwise.
  167. return SafeDiv(a2, s * s);
  168. }
  169. real D_GGX(real NdotH, real roughness)
  170. {
  171. return INV_PI * D_GGXNoPI(NdotH, roughness);
  172. }
  173. // Ref: Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, p. 19, 29.
  174. // p. 84 (37/60)
  175. real G_MaskingSmithGGX(real NdotV, real roughness)
  176. {
  177. // G1(V, H) = HeavisideStep(VdotH) / (1 + Lambda(V)).
  178. // Lambda(V) = -0.5 + 0.5 * sqrt(1 + 1 / a^2).
  179. // a = 1 / (roughness * tan(theta)).
  180. // 1 + Lambda(V) = 0.5 + 0.5 * sqrt(1 + roughness^2 * tan^2(theta)).
  181. // tan^2(theta) = (1 - cos^2(theta)) / cos^2(theta) = 1 / cos^2(theta) - 1.
  182. // Assume that (VdotH > 0), e.i. (acos(LdotV) < Pi).
  183. return 1.0 / (0.5 + 0.5 * sqrt(1.0 + Sq(roughness) * (1.0 / Sq(NdotV) - 1.0)));
  184. }
  185. // Precompute part of lambdaV
  186. real GetSmithJointGGXPartLambdaV(real NdotV, real roughness)
  187. {
  188. real a2 = Sq(roughness);
  189. return sqrt((-NdotV * a2 + NdotV) * NdotV + a2);
  190. }
  191. // Note: V = G / (4 * NdotL * NdotV)
  192. // Ref: http://jcgt.org/published/0003/02/03/paper.pdf
  193. real V_SmithJointGGX(real NdotL, real NdotV, real roughness, real partLambdaV)
  194. {
  195. real a2 = Sq(roughness);
  196. // Original formulation:
  197. // lambda_v = (-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5
  198. // lambda_l = (-1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5
  199. // G = 1 / (1 + lambda_v + lambda_l);
  200. // Reorder code to be more optimal:
  201. real lambdaV = NdotL * partLambdaV;
  202. real lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);
  203. // Simplify visibility term: (2.0 * NdotL * NdotV) / ((4.0 * NdotL * NdotV) * (lambda_v + lambda_l))
  204. return 0.5 / max(lambdaV + lambdaL, REAL_MIN);
  205. }
  206. real V_SmithJointGGX(real NdotL, real NdotV, real roughness)
  207. {
  208. real partLambdaV = GetSmithJointGGXPartLambdaV(NdotV, roughness);
  209. return V_SmithJointGGX(NdotL, NdotV, roughness, partLambdaV);
  210. }
  211. // Inline D_GGX() * V_SmithJointGGX() together for better code generation.
  212. real DV_SmithJointGGX(real NdotH, real NdotL, real NdotV, real roughness, real partLambdaV)
  213. {
  214. real a2 = Sq(roughness);
  215. real s = (NdotH * a2 - NdotH) * NdotH + 1.0;
  216. real lambdaV = NdotL * partLambdaV;
  217. real lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);
  218. real2 D = real2(a2, s * s); // Fraction without the multiplier (1/Pi)
  219. real2 G = real2(1, lambdaV + lambdaL); // Fraction without the multiplier (1/2)
  220. // This function is only used for direct lighting.
  221. // If roughness is 0, the probability of hitting a punctual or directional light is also 0.
  222. // Therefore, we return 0. The most efficient way to do it is with a max().
  223. return INV_PI * 0.5 * (D.x * G.x) / max(D.y * G.y, REAL_MIN);
  224. }
  225. real DV_SmithJointGGX(real NdotH, real NdotL, real NdotV, real roughness)
  226. {
  227. real partLambdaV = GetSmithJointGGXPartLambdaV(NdotV, roughness);
  228. return DV_SmithJointGGX(NdotH, NdotL, NdotV, roughness, partLambdaV);
  229. }
  230. // Precompute a part of LambdaV.
  231. // Note on this linear approximation.
  232. // Exact for roughness values of 0 and 1. Also, exact when the cosine is 0 or 1.
  233. // Otherwise, the worst case relative error is around 10%.
  234. // https://www.desmos.com/calculator/wtp8lnjutx
  235. real GetSmithJointGGXPartLambdaVApprox(real NdotV, real roughness)
  236. {
  237. real a = roughness;
  238. return NdotV * (1 - a) + a;
  239. }
  240. real V_SmithJointGGXApprox(real NdotL, real NdotV, real roughness, real partLambdaV)
  241. {
  242. real a = roughness;
  243. real lambdaV = NdotL * partLambdaV;
  244. real lambdaL = NdotV * (NdotL * (1 - a) + a);
  245. return 0.5 / (lambdaV + lambdaL);
  246. }
  247. real V_SmithJointGGXApprox(real NdotL, real NdotV, real roughness)
  248. {
  249. real partLambdaV = GetSmithJointGGXPartLambdaVApprox(NdotV, roughness);
  250. return V_SmithJointGGXApprox(NdotL, NdotV, roughness, partLambdaV);
  251. }
  252. // roughnessT -> roughness in tangent direction
  253. // roughnessB -> roughness in bitangent direction
  254. real D_GGXAnisoNoPI(real TdotH, real BdotH, real NdotH, real roughnessT, real roughnessB)
  255. {
  256. real a2 = roughnessT * roughnessB;
  257. real3 v = real3(roughnessB * TdotH, roughnessT * BdotH, a2 * NdotH);
  258. real s = dot(v, v);
  259. // If roughness is 0, returns (NdotH == 1 ? 1 : 0).
  260. // That is, it returns 1 for perfect mirror reflection, and 0 otherwise.
  261. return SafeDiv(a2 * a2 * a2, s * s);
  262. }
  263. real D_GGXAniso(real TdotH, real BdotH, real NdotH, real roughnessT, real roughnessB)
  264. {
  265. return INV_PI * D_GGXAnisoNoPI(TdotH, BdotH, NdotH, roughnessT, roughnessB);
  266. }
  267. real GetSmithJointGGXAnisoPartLambdaV(real TdotV, real BdotV, real NdotV, real roughnessT, real roughnessB)
  268. {
  269. return length(real3(roughnessT * TdotV, roughnessB * BdotV, NdotV));
  270. }
  271. // Note: V = G / (4 * NdotL * NdotV)
  272. // Ref: https://cedec.cesa.or.jp/2015/session/ENG/14698.html The Rendering Materials of Far Cry 4
  273. real V_SmithJointGGXAniso(real TdotV, real BdotV, real NdotV, real TdotL, real BdotL, real NdotL, real roughnessT, real roughnessB, real partLambdaV)
  274. {
  275. real lambdaV = NdotL * partLambdaV;
  276. real lambdaL = NdotV * length(real3(roughnessT * TdotL, roughnessB * BdotL, NdotL));
  277. return 0.5 / (lambdaV + lambdaL);
  278. }
  279. real V_SmithJointGGXAniso(real TdotV, real BdotV, real NdotV, real TdotL, real BdotL, real NdotL, real roughnessT, real roughnessB)
  280. {
  281. real partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, roughnessT, roughnessB);
  282. return V_SmithJointGGXAniso(TdotV, BdotV, NdotV, TdotL, BdotL, NdotL, roughnessT, roughnessB, partLambdaV);
  283. }
  284. // Inline D_GGXAniso() * V_SmithJointGGXAniso() together for better code generation.
  285. real DV_SmithJointGGXAniso(real TdotH, real BdotH, real NdotH, real NdotV,
  286. real TdotL, real BdotL, real NdotL,
  287. real roughnessT, real roughnessB, real partLambdaV)
  288. {
  289. real a2 = roughnessT * roughnessB;
  290. real3 v = real3(roughnessB * TdotH, roughnessT * BdotH, a2 * NdotH);
  291. real s = dot(v, v);
  292. real lambdaV = NdotL * partLambdaV;
  293. real lambdaL = NdotV * length(real3(roughnessT * TdotL, roughnessB * BdotL, NdotL));
  294. real2 D = real2(a2 * a2 * a2, s * s); // Fraction without the multiplier (1/Pi)
  295. real2 G = real2(1, lambdaV + lambdaL); // Fraction without the multiplier (1/2)
  296. // This function is only used for direct lighting.
  297. // If roughness is 0, the probability of hitting a punctual or directional light is also 0.
  298. // Therefore, we return 0. The most efficient way to do it is with a max().
  299. return (INV_PI * 0.5) * (D.x * G.x) / max(D.y * G.y, REAL_MIN);
  300. }
  301. real DV_SmithJointGGXAniso(real TdotH, real BdotH, real NdotH,
  302. real TdotV, real BdotV, real NdotV,
  303. real TdotL, real BdotL, real NdotL,
  304. real roughnessT, real roughnessB)
  305. {
  306. real partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, roughnessT, roughnessB);
  307. return DV_SmithJointGGXAniso(TdotH, BdotH, NdotH, NdotV,
  308. TdotL, BdotL, NdotL,
  309. roughnessT, roughnessB, partLambdaV);
  310. }
  311. // Get projected roughness for a certain normalized direction V in tangent space
  312. // and an anisotropic roughness
  313. // Ref: Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, Heitz 2014, pp. 86, 88 - 39/60, 41/60
  314. float GetProjectedRoughness(float TdotV, float BdotV, float NdotV, float roughnessT, float roughnessB)
  315. {
  316. float2 roughness = float2(roughnessT, roughnessB);
  317. float sinTheta2 = max((1 - Sq(NdotV)), FLT_MIN);
  318. // if sinTheta^2 = 0, NdotV = 1, TdotV = BdotV = 0 and roughness is arbitrary, no real azimuth
  319. // as there's a breakdown of the spherical parameterization, so we clamp under by FLT_MIN in any case
  320. // for safe division
  321. // Note:
  322. // sin(thetaV)^2 * cos(phiV)^2 = (TdotV)^2
  323. // sin(thetaV)^2 * sin(phiV)^2 = (BdotV)^2
  324. float2 vProj2 = Sq(float2(TdotV, BdotV)) * rcp(sinTheta2);
  325. // vProj2 = (cos^2(phi), sin^2(phi))
  326. float projRoughness = sqrt(dot(vProj2, roughness*roughness));
  327. return projRoughness;
  328. }
  329. //-----------------------------------------------------------------------------
  330. // Diffuse BRDF - diffuseColor is expected to be multiply by the caller
  331. //-----------------------------------------------------------------------------
  332. real LambertNoPI()
  333. {
  334. return 1.0;
  335. }
  336. real Lambert()
  337. {
  338. return INV_PI;
  339. }
  340. real DisneyDiffuseNoPI(real NdotV, real NdotL, real LdotV, real perceptualRoughness)
  341. {
  342. // (2 * LdotH * LdotH) = 1 + LdotV
  343. // real fd90 = 0.5 + (2 * LdotH * LdotH) * perceptualRoughness;
  344. real fd90 = 0.5 + (perceptualRoughness + perceptualRoughness * LdotV);
  345. // Two schlick fresnel term
  346. real lightScatter = F_Schlick(1.0, fd90, NdotL);
  347. real viewScatter = F_Schlick(1.0, fd90, NdotV);
  348. // Normalize the BRDF for polar view angles of up to (Pi/4).
  349. // We use the worst case of (roughness = albedo = 1), and, for each view angle,
  350. // integrate (brdf * cos(theta_light)) over all light directions.
  351. // The resulting value is for (theta_view = 0), which is actually a little bit larger
  352. // than the value of the integral for (theta_view = Pi/4).
  353. // Hopefully, the compiler folds the constant together with (1/Pi).
  354. return rcp(1.03571) * (lightScatter * viewScatter);
  355. }
  356. #ifndef BUILTIN_TARGET_API
  357. real DisneyDiffuse(real NdotV, real NdotL, real LdotV, real perceptualRoughness)
  358. {
  359. return INV_PI * DisneyDiffuseNoPI(NdotV, NdotL, LdotV, perceptualRoughness);
  360. }
  361. #endif
  362. // Ref: Diffuse Lighting for GGX + Smith Microsurfaces, p. 113.
  363. real3 DiffuseGGXNoPI(real3 albedo, real NdotV, real NdotL, real NdotH, real LdotV, real roughness)
  364. {
  365. real facing = 0.5 + 0.5 * LdotV; // (LdotH)^2
  366. real rough = facing * (0.9 - 0.4 * facing) * (0.5 / NdotH + 1);
  367. real transmitL = F_Transm_Schlick(0, NdotL);
  368. real transmitV = F_Transm_Schlick(0, NdotV);
  369. real smooth = transmitL * transmitV * 1.05; // Normalize F_t over the hemisphere
  370. real single = lerp(smooth, rough, roughness); // Rescaled by PI
  371. real multiple = roughness * (0.1159 * PI); // Rescaled by PI
  372. return single + albedo * multiple;
  373. }
  374. real3 DiffuseGGX(real3 albedo, real NdotV, real NdotL, real NdotH, real LdotV, real roughness)
  375. {
  376. // Note that we could save 2 cycles by inlining the multiplication by INV_PI.
  377. return INV_PI * DiffuseGGXNoPI(albedo, NdotV, NdotL, NdotH, LdotV, roughness);
  378. }
  379. //-----------------------------------------------------------------------------
  380. // Iridescence
  381. //-----------------------------------------------------------------------------
  382. // Ref: https://belcour.github.io/blog/research/2017/05/01/brdf-thin-film.html
  383. // Evaluation XYZ sensitivity curves in Fourier space
  384. real3 EvalSensitivity(real opd, real shift)
  385. {
  386. // Use Gaussian fits, given by 3 parameters: val, pos and var
  387. real phase = 2.0 * PI * opd * 1e-6;
  388. real3 val = real3(5.4856e-13, 4.4201e-13, 5.2481e-13);
  389. real3 pos = real3(1.6810e+06, 1.7953e+06, 2.2084e+06);
  390. real3 var = real3(4.3278e+09, 9.3046e+09, 6.6121e+09);
  391. real3 xyz = val * sqrt(2.0 * PI * var) * cos(pos * phase + shift) * exp(-var * phase * phase);
  392. xyz.x += 9.7470e-14 * sqrt(2.0 * PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift) * exp(-4.5282e+09 * phase * phase);
  393. xyz /= 1.0685e-7;
  394. // Convert to linear sRGb color space here.
  395. // EvalIridescence works in linear sRGB color space and does not switch...
  396. real3 srgb = mul(XYZ_2_REC709_MAT, xyz);
  397. return srgb;
  398. }
  399. // Evaluate the reflectance for a thin-film layer on top of a dielectric medum.
  400. real3 EvalIridescence(real eta_1, real cosTheta1, real iridescenceThickness, real3 baseLayerFresnel0, real iorOverBaseLayer = 0.0)
  401. {
  402. real3 I;
  403. // iridescenceThickness unit is micrometer for this equation here. Mean 0.5 is 500nm.
  404. real Dinc = 3.0 * iridescenceThickness;
  405. // Note: Unlike the code provide with the paper, here we use schlick approximation
  406. // Schlick is a very poor approximation when dealing with iridescence to the Fresnel
  407. // term and there is no "neutral" value in this unlike in the original paper.
  408. // We use Iridescence mask here to allow to have neutral value
  409. // Hack: In order to use only one parameter (DInc), we deduced the ior of iridescence from current Dinc iridescenceThickness
  410. // and we use mask instead to fade out the effect
  411. real eta_2 = lerp(2.0, 1.0, iridescenceThickness);
  412. // Following line from original code is not needed for us, it create a discontinuity
  413. // Force eta_2 -> eta_1 when Dinc -> 0.0
  414. // real eta_2 = lerp(eta_1, eta_2, smoothstep(0.0, 0.03, Dinc));
  415. // Evaluate the cosTheta on the base layer (Snell law)
  416. real sinTheta2Sq = Sq(eta_1 / eta_2) * (1.0 - Sq(cosTheta1));
  417. // Handle TIR:
  418. // (Also note that with just testing sinTheta2Sq > 1.0, (1.0 - sinTheta2Sq) can be negative, as emitted instructions
  419. // can eg be a mad giving a small negative for (1.0 - sinTheta2Sq), while sinTheta2Sq still testing equal to 1.0), so we actually
  420. // test the operand [cosTheta2Sq := (1.0 - sinTheta2Sq)] < 0 directly:)
  421. real cosTheta2Sq = (1.0 - sinTheta2Sq);
  422. // Or use this "artistic hack" to get more continuity even though wrong (no TIR, continue the effect by mirroring it):
  423. // if( cosTheta2Sq < 0.0 ) => { sinTheta2Sq = 2 - sinTheta2Sq; => so cosTheta2Sq = sinTheta2Sq - 1 }
  424. // ie don't test and simply do
  425. // real cosTheta2Sq = abs(1.0 - sinTheta2Sq);
  426. if (cosTheta2Sq < 0.0)
  427. I = real3(1.0, 1.0, 1.0);
  428. else
  429. {
  430. real cosTheta2 = sqrt(cosTheta2Sq);
  431. // First interface
  432. real R0 = IorToFresnel0(eta_2, eta_1);
  433. real R12 = F_Schlick(R0, cosTheta1);
  434. real R21 = R12;
  435. real T121 = 1.0 - R12;
  436. real phi12 = 0.0;
  437. real phi21 = PI - phi12;
  438. // Second interface
  439. // The f0 or the base should account for the new computed eta_2 on top.
  440. // This is optionally done if we are given the needed current ior over the base layer that is accounted for
  441. // in the baseLayerFresnel0 parameter:
  442. if (iorOverBaseLayer > 0.0)
  443. {
  444. // Fresnel0ToIor will give us a ratio of baseIor/topIor, hence we * iorOverBaseLayer to get the baseIor
  445. real3 baseIor = iorOverBaseLayer * Fresnel0ToIor(baseLayerFresnel0 + 0.0001); // guard against 1.0
  446. baseLayerFresnel0 = IorToFresnel0(baseIor, eta_2);
  447. }
  448. real3 R23 = F_Schlick(baseLayerFresnel0, cosTheta2);
  449. real phi23 = 0.0;
  450. // Phase shift
  451. real OPD = Dinc * cosTheta2;
  452. real phi = phi21 + phi23;
  453. // Compound terms
  454. real3 R123 = clamp(R12 * R23, 1e-5, 0.9999);
  455. real3 r123 = sqrt(R123);
  456. real3 Rs = Sq(T121) * R23 / (real3(1.0, 1.0, 1.0) - R123);
  457. // Reflectance term for m = 0 (DC term amplitude)
  458. real3 C0 = R12 + Rs;
  459. I = C0;
  460. // Reflectance term for m > 0 (pairs of diracs)
  461. real3 Cm = Rs - T121;
  462. for (int m = 1; m <= 2; ++m)
  463. {
  464. Cm *= r123;
  465. real3 Sm = 2.0 * EvalSensitivity(m * OPD, m * phi);
  466. //vec3 SmP = 2.0 * evalSensitivity(m*OPD, m*phi2.y);
  467. I += Cm * Sm;
  468. }
  469. // Since out of gamut colors might be produced, negative color values are clamped to 0.
  470. I = max(I, float3(0.0, 0.0, 0.0));
  471. }
  472. return I;
  473. }
  474. //-----------------------------------------------------------------------------
  475. // Fabric
  476. //-----------------------------------------------------------------------------
  477. // Ref: https://knarkowicz.wordpress.com/2018/01/04/cloth-shading/
  478. real D_CharlieNoPI(real NdotH, real roughness)
  479. {
  480. float invR = rcp(roughness);
  481. float cos2h = NdotH * NdotH;
  482. float sin2h = 1.0 - cos2h;
  483. // Note: We have sin^2 so multiply by 0.5 to cancel it
  484. return (2.0 + invR) * PositivePow(sin2h, invR * 0.5) / 2.0;
  485. }
  486. real D_Charlie(real NdotH, real roughness)
  487. {
  488. return INV_PI * D_CharlieNoPI(NdotH, roughness);
  489. }
  490. real CharlieL(real x, real r)
  491. {
  492. r = saturate(r);
  493. r = 1.0 - (1.0 - r) * (1.0 - r);
  494. float a = lerp(25.3245, 21.5473, r);
  495. float b = lerp(3.32435, 3.82987, r);
  496. float c = lerp(0.16801, 0.19823, r);
  497. float d = lerp(-1.27393, -1.97760, r);
  498. float e = lerp(-4.85967, -4.32054, r);
  499. return a / (1. + b * PositivePow(x, c)) + d * x + e;
  500. }
  501. // Note: This version don't include the softening of the paper: Production Friendly Microfacet Sheen BRDF
  502. real V_Charlie(real NdotL, real NdotV, real roughness)
  503. {
  504. real lambdaV = NdotV < 0.5 ? exp(CharlieL(NdotV, roughness)) : exp(2.0 * CharlieL(0.5, roughness) - CharlieL(1.0 - NdotV, roughness));
  505. real lambdaL = NdotL < 0.5 ? exp(CharlieL(NdotL, roughness)) : exp(2.0 * CharlieL(0.5, roughness) - CharlieL(1.0 - NdotL, roughness));
  506. return 1.0 / ((1.0 + lambdaV + lambdaL) * (4.0 * NdotV * NdotL));
  507. }
  508. // We use V_Ashikhmin instead of V_Charlie in practice for game due to the cost of V_Charlie
  509. real V_Ashikhmin(real NdotL, real NdotV)
  510. {
  511. // Use soft visibility term introduce in: Crafting a Next-Gen Material Pipeline for The Order : 1886
  512. return 1.0 / (4.0 * (NdotL + NdotV - NdotL * NdotV));
  513. }
  514. // A diffuse term use with fabric done by tech artist - empirical
  515. real FabricLambertNoPI(real roughness)
  516. {
  517. return lerp(1.0, 0.5, roughness);
  518. }
  519. real FabricLambert(real roughness)
  520. {
  521. return INV_PI * FabricLambertNoPI(roughness);
  522. }
  523. real G_CookTorrance(real NdotH, real NdotV, real NdotL, real HdotV)
  524. {
  525. return min(1.0, 2.0 * NdotH * min(NdotV, NdotL) / HdotV);
  526. }
  527. //-----------------------------------------------------------------------------
  528. // Hair
  529. //-----------------------------------------------------------------------------
  530. //http://web.engr.oregonstate.edu/~mjb/cs519/Projects/Papers/HairRendering.pdf
  531. real3 ShiftTangent(real3 T, real3 N, real shift)
  532. {
  533. return normalize(T + N * shift);
  534. }
  535. // Note: this is Blinn-Phong, the original paper uses Phong.
  536. real3 D_KajiyaKay(real3 T, real3 H, real specularExponent)
  537. {
  538. real TdotH = dot(T, H);
  539. real sinTHSq = saturate(1.0 - TdotH * TdotH);
  540. real dirAttn = saturate(TdotH + 1.0); // Evgenii: this seems like a hack? Do we really need this?
  541. // Note: Kajiya-Kay is not energy conserving.
  542. // We attempt at least some energy conservation by approximately normalizing Blinn-Phong NDF.
  543. // We use the formulation with the NdotL.
  544. // See http://www.thetenthplanet.de/archives/255.
  545. real n = specularExponent;
  546. real norm = (n + 2) * rcp(2 * PI);
  547. return dirAttn * norm * PositivePow(sinTHSq, 0.5 * n);
  548. }
  549. #if SHADER_API_MOBILE || SHADER_API_GLES3 || SHADER_API_SWITCH
  550. #pragma warning (enable : 3205) // conversion of larger type to smaller
  551. #endif
  552. #endif // UNITY_BSDF_INCLUDED