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