CommonMaterial.hlsl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. #ifndef UNITY_COMMON_MATERIAL_INCLUDED
  2. #define UNITY_COMMON_MATERIAL_INCLUDED
  3. #if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
  4. #pragma warning (disable : 3205) // conversion of larger type to smaller
  5. #endif
  6. //-----------------------------------------------------------------------------
  7. // Define constants
  8. //-----------------------------------------------------------------------------
  9. #define DEFAULT_SPECULAR_VALUE 0.04
  10. // Following constant are used when we use clear coat properties that can't be store in the Gbuffer (with the Lit shader)
  11. #define CLEAR_COAT_IOR 1.5
  12. #define CLEAR_COAT_IETA (1.0 / CLEAR_COAT_IOR) // IETA is the inverse eta which is the ratio of IOR of two interface
  13. #define CLEAR_COAT_F0 0.04 // IORToFresnel0(CLEAR_COAT_IOR)
  14. #define CLEAR_COAT_ROUGHNESS 0.01
  15. #define CLEAR_COAT_PERCEPTUAL_SMOOTHNESS RoughnessToPerceptualSmoothness(CLEAR_COAT_ROUGHNESS)
  16. #define CLEAR_COAT_PERCEPTUAL_ROUGHNESS RoughnessToPerceptualRoughness(CLEAR_COAT_ROUGHNESS)
  17. #define CLEAR_COAT_SSR_PERCEPTUAL_ROUGHNESS 0.0 // For screen space reflections and ray traced reflections, we want to have a purely smooth surface to map the envrionement light behavior
  18. //-----------------------------------------------------------------------------
  19. // Helper functions for roughness
  20. //-----------------------------------------------------------------------------
  21. #ifndef BUILTIN_TARGET_API
  22. real PerceptualRoughnessToRoughness(real perceptualRoughness)
  23. {
  24. return perceptualRoughness * perceptualRoughness;
  25. }
  26. real RoughnessToPerceptualRoughness(real roughness)
  27. {
  28. return sqrt(roughness);
  29. }
  30. #endif
  31. real RoughnessToPerceptualSmoothness(real roughness)
  32. {
  33. return 1.0 - sqrt(roughness);
  34. }
  35. real PerceptualSmoothnessToRoughness(real perceptualSmoothness)
  36. {
  37. return (1.0 - perceptualSmoothness) * (1.0 - perceptualSmoothness);
  38. }
  39. real PerceptualSmoothnessToPerceptualRoughness(real perceptualSmoothness)
  40. {
  41. return (1.0 - perceptualSmoothness);
  42. }
  43. // Beckmann to GGX roughness "conversions":
  44. //
  45. // As also noted for NormalVariance in this file, Beckmann microfacet models use a Gaussian distribution of slopes
  46. // and the roughness parameter absorbs constants in the canonical Gaussian formula and is thus not exactly the variance.
  47. // The relationship is:
  48. //
  49. // roughnessBeckmann^2 = 2 variance (where variance is usually denoted sigma^2 but some comp gfx papers use sigma for
  50. // variance or even sigma for roughness itself.)
  51. //
  52. // Microfacet BRDF models with a GGX NDF implies a Cauchy distribution of slopes (also corresponds to the distribution
  53. // of slopes on an ellipsoid). Cauchy distributions don't have second moments, which precludes having a variance,
  54. // but chopping the far tails of GGX and keeping 94% of the mass yields a distribution with a defined variance where
  55. // we can then relate the roughness of GGX to a variance (see Ray Tracing Gems p153 - the reference is wrong though,
  56. // the Conty paper doesn't mention this at all, but it can be found in stats using quantiles):
  57. //
  58. // roughnessGGX^2 = variance / 2
  59. //
  60. // From the two previous, if we want roughly comparable variances of slopes between a Beckmann and a GGX NDF, we can
  61. // equate the variances and get a conversion of their roughnesses:
  62. //
  63. // 2 * roughnessGGX^2 = roughnessBeckmann^2 / 2 <==>
  64. // 4 * roughnessGGX^2 = roughnessBeckmann^2 <==>
  65. // 2 * roughnessGGX = roughnessBeckmann
  66. //
  67. // (Note that the Ray Tracing Gems paper makes an error on p154 writing sqrt(2) * roughnessGGX = roughnessBeckmann;
  68. // Their validation study using ray tracing and LEADR - which looks good - is for the *variance to GGX* roughness mapping,
  69. // not the Beckmann to GGX roughness "conversion")
  70. real BeckmannRoughnessToGGXRoughness(real roughnessBeckmann)
  71. {
  72. return 0.5 * roughnessBeckmann;
  73. }
  74. real PerceptualRoughnessBeckmannToGGX(real perceptualRoughnessBeckmann)
  75. {
  76. //sqrt(a_ggx) = sqrt(0.5) sqrt(a_beckmann)
  77. return sqrt(0.5) * perceptualRoughnessBeckmann;
  78. }
  79. real GGXRoughnessToBeckmannRoughness(real roughnessGGX)
  80. {
  81. return 2.0 * roughnessGGX;
  82. }
  83. real PerceptualRoughnessToPerceptualSmoothness(real perceptualRoughness)
  84. {
  85. return (1.0 - perceptualRoughness);
  86. }
  87. // WARNING: this has been deprecated, and should not be used!
  88. // Using roughness values of 0 leads to INFs and NANs. The only sensible place to use the roughness
  89. // value of 0 is IBL, so we do not modify the perceptual roughness which is used to select the MIP map level.
  90. // Note: making the constant too small results in aliasing.
  91. real ClampRoughnessForAnalyticalLights(real roughness)
  92. {
  93. return max(roughness, 1.0 / 1024.0);
  94. }
  95. // Given that the GGX model is invalid for a roughness of 0.0. This values have been experimentally evaluated to be the limit for the roughness
  96. // for integration.
  97. real ClampRoughnessForRaytracing(real roughness)
  98. {
  99. return max(roughness, 0.001225);
  100. }
  101. real ClampPerceptualRoughnessForRaytracing(real perceptualRoughness)
  102. {
  103. return max(perceptualRoughness, 0.035);
  104. }
  105. void ConvertValueAnisotropyToValueTB(real value, real anisotropy, out real valueT, out real valueB)
  106. {
  107. // Use the parametrization of Sony Imageworks.
  108. // Ref: Revisiting Physically Based Shading at Imageworks, p. 15.
  109. valueT = value * (1 + anisotropy);
  110. valueB = value * (1 - anisotropy);
  111. }
  112. void ConvertAnisotropyToRoughness(real perceptualRoughness, real anisotropy, out real roughnessT, out real roughnessB)
  113. {
  114. real roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
  115. ConvertValueAnisotropyToValueTB(roughness, anisotropy, roughnessT, roughnessB);
  116. }
  117. void ConvertRoughnessTAndAnisotropyToRoughness(real roughnessT, real anisotropy, out real roughness)
  118. {
  119. roughness = roughnessT / (1 + anisotropy);
  120. }
  121. real ConvertRoughnessTAndBToRoughness(real roughnessT, real roughnessB)
  122. {
  123. return 0.5 * (roughnessT + roughnessB);
  124. }
  125. void ConvertRoughnessToAnisotropy(real roughnessT, real roughnessB, out real anisotropy)
  126. {
  127. anisotropy = ((roughnessT - roughnessB) / max(roughnessT + roughnessB, 0.0001));
  128. }
  129. // WARNING: this has been deprecated, and should not be used!
  130. // Same as ConvertAnisotropyToRoughness but
  131. // roughnessT and roughnessB are clamped, and are meant to be used with punctual and directional lights.
  132. void ConvertAnisotropyToClampRoughness(real perceptualRoughness, real anisotropy, out real roughnessT, out real roughnessB)
  133. {
  134. ConvertAnisotropyToRoughness(perceptualRoughness, anisotropy, roughnessT, roughnessB);
  135. roughnessT = ClampRoughnessForAnalyticalLights(roughnessT);
  136. roughnessB = ClampRoughnessForAnalyticalLights(roughnessB);
  137. }
  138. // Use with stack BRDF (clear coat / coat) - This only used same equation to convert from Blinn-Phong spec power to Beckmann roughness
  139. real RoughnessToVariance(real roughness)
  140. {
  141. return 2.0 / Sq(roughness) - 2.0;
  142. }
  143. real VarianceToRoughness(real variance)
  144. {
  145. return sqrt(2.0 / (variance + 2.0));
  146. }
  147. // Normal Map Filtering - This must match HDRP\Editor\AssetProcessors\NormalMapFilteringTexturePostprocessor.cs - highestVarianceAllowed (TODO: Move in core)
  148. #define NORMALMAP_HIGHEST_VARIANCE 0.03125
  149. float DecodeVariance(float gradientW)
  150. {
  151. return gradientW * NORMALMAP_HIGHEST_VARIANCE;
  152. }
  153. // Return modified perceptualSmoothness based on provided variance (get from GeometricNormalVariance + TextureNormalVariance)
  154. float NormalFiltering(float perceptualSmoothness, float variance, float threshold)
  155. {
  156. float roughness = PerceptualSmoothnessToRoughness(perceptualSmoothness);
  157. // Ref: Geometry into Shading - http://graphics.pixar.com/library/BumpRoughness/paper.pdf - equation (3)
  158. float squaredRoughness = saturate(roughness * roughness + min(2.0 * variance, threshold * threshold)); // threshold can be really low, square the value for easier control
  159. return RoughnessToPerceptualSmoothness(sqrt(squaredRoughness));
  160. }
  161. float ProjectedSpaceNormalFiltering(float perceptualSmoothness, float variance, float threshold)
  162. {
  163. float roughness = PerceptualSmoothnessToRoughness(perceptualSmoothness);
  164. // Ref: Stable Geometric Specular Antialiasing with Projected-Space NDF Filtering - https://yusuketokuyoshi.com/papers/2021/Tokuyoshi2021SAA.pdf
  165. float squaredRoughness = roughness * roughness;
  166. float projRoughness2 = squaredRoughness / (1.0 - squaredRoughness);
  167. float filteredProjRoughness2 = saturate(projRoughness2 + min(2.0 * variance, threshold * threshold));
  168. squaredRoughness = filteredProjRoughness2 / (filteredProjRoughness2 + 1.0f);
  169. return RoughnessToPerceptualSmoothness(sqrt(squaredRoughness));
  170. }
  171. // Reference: Error Reduction and Simplification for Shading Anti-Aliasing
  172. // Specular antialiasing for geometry-induced normal (and NDF) variations: Tokuyoshi / Kaplanyan et al.'s method.
  173. // This is the deferred approximation, which works reasonably well so we keep it for forward too for now.
  174. // screenSpaceVariance should be at most 0.5^2 = 0.25, as that corresponds to considering
  175. // a gaussian pixel reconstruction kernel with a standard deviation of 0.5 of a pixel, thus 2 sigma covering the whole pixel.
  176. float GeometricNormalVariance(float3 geometricNormalWS, float screenSpaceVariance)
  177. {
  178. float3 deltaU = ddx(geometricNormalWS);
  179. float3 deltaV = ddy(geometricNormalWS);
  180. return screenSpaceVariance * (dot(deltaU, deltaU) + dot(deltaV, deltaV));
  181. }
  182. // Return modified perceptualSmoothness
  183. float GeometricNormalFiltering(float perceptualSmoothness, float3 geometricNormalWS, float screenSpaceVariance, float threshold)
  184. {
  185. float variance = GeometricNormalVariance(geometricNormalWS, screenSpaceVariance);
  186. return NormalFiltering(perceptualSmoothness, variance, threshold);
  187. }
  188. float ProjectedSpaceGeometricNormalFiltering(float perceptualSmoothness, float3 geometricNormalWS, float screenSpaceVariance, float threshold)
  189. {
  190. float variance = GeometricNormalVariance(geometricNormalWS, screenSpaceVariance);
  191. return ProjectedSpaceNormalFiltering(perceptualSmoothness, variance, threshold);
  192. }
  193. // Normal map filtering based on The Order : 1886 SIGGRAPH course notes implementation.
  194. // Basically Toksvig with an intermediate single vMF lobe induced dispersion (Han et al. 2007)
  195. //
  196. // This returns 2 times the variance of the induced "mesoNDF" lobe (an NDF induced from a section of
  197. // the normal map) from the level 0 mip normals covered by the "current texel".
  198. //
  199. // avgNormalLength gives the dispersion information for the covered normals.
  200. //
  201. // Note that hw filtering on the normal map should be trilinear to be conservative, while anisotropic
  202. // risk underfiltering. Could also compute average normal on the fly with a proper normal map format,
  203. // like Toksvig.
  204. float TextureNormalVariance(float avgNormalLength)
  205. {
  206. float variance = 0.0;
  207. if (avgNormalLength < 1.0)
  208. {
  209. float avgNormLen2 = avgNormalLength * avgNormalLength;
  210. float kappa = (3.0 * avgNormalLength - avgNormalLength * avgNormLen2) / (1.0 - avgNormLen2);
  211. // Ref: Frequency Domain Normal Map Filtering - http://www.cs.columbia.edu/cg/normalmap/normalmap.pdf (equation 21)
  212. // Relationship between between the standard deviation of a Gaussian distribution and the roughness parameter of a Beckmann distribution.
  213. // is roughness^2 = 2 variance (note: variance is sigma^2)
  214. // (Ref: Filtering Distributions of Normals for Shading Antialiasing - Equation just after (14))
  215. // Relationship between gaussian lobe and vMF lobe is 2 * variance = 1 / (2 * kappa) = roughness^2
  216. // (Equation 36 of Normal map filtering based on The Order : 1886 SIGGRAPH course notes implementation).
  217. // So to get variance we must use variance = 1 / (4 * kappa)
  218. variance = 0.25 / kappa;
  219. }
  220. return variance;
  221. }
  222. float TextureNormalFiltering(float perceptualSmoothness, float avgNormalLength, float threshold)
  223. {
  224. float variance = TextureNormalVariance(avgNormalLength);
  225. return NormalFiltering(perceptualSmoothness, variance, threshold);
  226. }
  227. // ----------------------------------------------------------------------------
  228. // Helper for Disney parametrization
  229. // ----------------------------------------------------------------------------
  230. float3 ComputeDiffuseColor(float3 baseColor, float metallic)
  231. {
  232. return baseColor * (1.0 - metallic);
  233. }
  234. float3 ComputeFresnel0(float3 baseColor, float metallic, float dielectricF0)
  235. {
  236. return lerp(dielectricF0.xxx, baseColor, metallic);
  237. }
  238. // ----------------------------------------------------------------------------
  239. // Helper for normal blending
  240. // ----------------------------------------------------------------------------
  241. // ref https://www.gamedev.net/topic/678043-how-to-blend-world-space-normals/#entry5287707
  242. // assume compositing in world space
  243. // Note: Using vtxNormal = real3(0, 0, 1) give the BlendNormalRNM formulation.
  244. // TODO: Untested
  245. real3 BlendNormalWorldspaceRNM(real3 n1, real3 n2, real3 vtxNormal)
  246. {
  247. // Build the shortest-arc quaternion
  248. real4 q = real4(cross(vtxNormal, n2), dot(vtxNormal, n2) + 1.0) / sqrt(2.0 * (dot(vtxNormal, n2) + 1));
  249. // Rotate the normal
  250. return n1 * (q.w * q.w - dot(q.xyz, q.xyz)) + 2 * q.xyz * dot(q.xyz, n1) + 2 * q.w * cross(q.xyz, n1);
  251. }
  252. // ref http://blog.selfshadow.com/publications/blending-in-detail/
  253. // ref https://gist.github.com/selfshadow/8048308
  254. // Reoriented Normal Mapping
  255. // Blending when n1 and n2 are already 'unpacked' and normalised
  256. // assume compositing in tangent space
  257. real3 BlendNormalRNM(real3 n1, real3 n2)
  258. {
  259. real3 t = n1.xyz + real3(0.0, 0.0, 1.0);
  260. real3 u = n2.xyz * real3(-1.0, -1.0, 1.0);
  261. real3 r = (t / t.z) * dot(t, u) - u;
  262. return r;
  263. }
  264. // assume compositing in tangent space
  265. real3 BlendNormal(real3 n1, real3 n2)
  266. {
  267. return normalize(real3(n1.xy * n2.z + n2.xy * n1.z, n1.z * n2.z));
  268. }
  269. // ----------------------------------------------------------------------------
  270. // Helper for triplanar
  271. // ----------------------------------------------------------------------------
  272. // Ref: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch01.html / http://www.slideshare.net/icastano/cascades-demo-secrets
  273. real3 ComputeTriplanarWeights(real3 normal)
  274. {
  275. // Determine the blend weights for the 3 planar projections.
  276. real3 blendWeights = abs(normal);
  277. // Tighten up the blending zone
  278. blendWeights = (blendWeights - 0.2);
  279. blendWeights = blendWeights * blendWeights * blendWeights; // pow(blendWeights, 3);
  280. // Force weights to sum to 1.0 (very important!)
  281. blendWeights = max(blendWeights, real3(0.0, 0.0, 0.0));
  282. blendWeights /= dot(blendWeights, 1.0);
  283. return blendWeights;
  284. }
  285. // Planar/Triplanar convention for Unity in world space
  286. void GetTriplanarCoordinate(float3 position, out float2 uvXZ, out float2 uvXY, out float2 uvZY)
  287. {
  288. // Caution: This must follow the same rule as what is use for SurfaceGradient triplanar
  289. // TODO: Currently the normal mapping looks wrong without SURFACE_GRADIENT option because we don't handle corretly the tangent space
  290. uvXZ = float2(position.x, position.z);
  291. uvXY = float2(position.x, position.y);
  292. uvZY = float2(position.z, position.y);
  293. }
  294. // ----------------------------------------------------------------------------
  295. // Helper for detail map operation
  296. // ----------------------------------------------------------------------------
  297. real LerpWhiteTo(real b, real t)
  298. {
  299. real oneMinusT = 1.0 - t;
  300. return oneMinusT + b * t;
  301. }
  302. #ifndef BUILTIN_TARGET_API
  303. real3 LerpWhiteTo(real3 b, real t)
  304. {
  305. real oneMinusT = 1.0 - t;
  306. return real3(oneMinusT, oneMinusT, oneMinusT) + b * t;
  307. }
  308. #endif
  309. #if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
  310. #pragma warning (enable : 3205) // conversion of larger type to smaller
  311. #endif
  312. #endif // UNITY_COMMON_MATERIAL_INCLUDED