BRDF.hlsl 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #ifdef COMPILEPS
  2. #ifdef PBR
  3. // Following BRDF methods are based upon research Frostbite EA
  4. //[Lagrade et al. 2014, "Moving Frostbite to Physically Based Rendering"]
  5. //Schlick Fresnel
  6. //specular = the rgb specular color value of the pixel
  7. //VdotH = the dot product of the camera view direction and the half vector
  8. float3 SchlickFresnel(float3 specular, float VdotH)
  9. {
  10. return specular + (float3(1.0, 1.0, 1.0) - specular) * pow(1.0 - VdotH, 5.0);
  11. }
  12. //Schlick Gaussian Fresnel
  13. //specular = the rgb specular color value of the pixel
  14. //VdotH = the dot product of the camera view direction and the half vector
  15. float3 SchlickGaussianFresnel(in float3 specular, in float VdotH)
  16. {
  17. float sphericalGaussian = pow(2.0, (-5.55473 * VdotH - 6.98316) * VdotH);
  18. return specular + (float3(1.0, 1.0, 1.0) - specular) * sphericalGaussian;
  19. }
  20. float3 SchlickFresnelCustom(float3 specular, float LdotH)
  21. {
  22. float ior = 0.25;
  23. float airIor = 1.000277;
  24. float f0 = (ior - airIor) / (ior + airIor);
  25. const float max_ior = 2.5;
  26. f0 = clamp(f0 * f0, 0.0, (max_ior - airIor) / (max_ior + airIor));
  27. return specular * (f0 + (1 - f0) * pow(2, (-5.55473 * LdotH - 6.98316) * LdotH));
  28. }
  29. //Get Fresnel
  30. //specular = the rgb specular color value of the pixel
  31. //VdotH = the dot product of the camera view direction and the half vector
  32. float3 Fresnel(float3 specular, float VdotH, float LdotH)
  33. {
  34. return SchlickFresnelCustom(specular, LdotH);
  35. //return SchlickFresnel(specular, VdotH);
  36. }
  37. // Smith GGX corrected Visibility
  38. // NdotL = the dot product of the normal and direction to the light
  39. // NdotV = the dot product of the normal and the camera view direction
  40. // roughness = the roughness of the pixel
  41. float SmithGGXSchlickVisibility(float NdotL, float NdotV, float roughness)
  42. {
  43. float rough2 = roughness * roughness;
  44. float lambdaV = NdotL * sqrt((-NdotV * rough2 + NdotV) * NdotV + rough2);
  45. float lambdaL = NdotV * sqrt((-NdotL * rough2 + NdotL) * NdotL + rough2);
  46. return 0.5 / (lambdaV + lambdaL);
  47. }
  48. float NeumannVisibility(float NdotV, float NdotL)
  49. {
  50. return NdotL * NdotV / max(1e-7, max(NdotL, NdotV));
  51. }
  52. // Get Visibility
  53. // NdotL = the dot product of the normal and direction to the light
  54. // NdotV = the dot product of the normal and the camera view direction
  55. // roughness = the roughness of the pixel
  56. float Visibility(float NdotL, float NdotV, float roughness)
  57. {
  58. return NeumannVisibility(NdotV, NdotL);
  59. //return SmithGGXSchlickVisibility(NdotL, NdotV, roughness);
  60. }
  61. // GGX Distribution
  62. // NdotH = the dot product of the normal and the half vector
  63. // roughness = the roughness of the pixel
  64. float GGXDistribution(float NdotH, float roughness)
  65. {
  66. float rough2 = roughness * roughness;
  67. float tmp = (NdotH * rough2 - NdotH) * NdotH + 1;
  68. return rough2 / (tmp * tmp);
  69. }
  70. // Blinn Distribution
  71. // NdotH = the dot product of the normal and the half vector
  72. // roughness = the roughness of the pixel
  73. float BlinnPhongDistribution(in float NdotH, in float roughness)
  74. {
  75. const float specPower = max((2.0 / (roughness * roughness)) - 2.0, 1e-4f); // Calculate specular power from roughness
  76. return pow(saturate(NdotH), specPower);
  77. }
  78. // Beckmann Distribution
  79. // NdotH = the dot product of the normal and the half vector
  80. // roughness = the roughness of the pixel
  81. float BeckmannDistribution(in float NdotH, in float roughness)
  82. {
  83. const float rough2 = roughness * roughness;
  84. const float roughnessA = 1.0 / (4.0 * rough2 * pow(NdotH, 4.0));
  85. const float roughnessB = NdotH * NdotH - 1.0;
  86. const float roughnessC = rough2 * NdotH * NdotH;
  87. return roughnessA * exp(roughnessB / roughnessC);
  88. }
  89. // Get Distribution
  90. // NdotH = the dot product of the normal and the half vector
  91. // roughness = the roughness of the pixel
  92. float Distribution(float NdotH, float roughness)
  93. {
  94. return GGXDistribution(NdotH, roughness);
  95. }
  96. // Lambertian Diffuse
  97. // diffuseColor = the rgb color value of the pixel
  98. // roughness = the roughness of the pixel
  99. // NdotV = the normal dot with the camera view direction
  100. // NdotL = the normal dot with the light direction
  101. // VdotH = the camera view direction dot with the half vector
  102. float3 LambertianDiffuse(float3 diffuseColor)
  103. {
  104. return diffuseColor * (1.0 / M_PI) ;
  105. }
  106. // Custom Lambertian Diffuse
  107. // diffuseColor = the rgb color value of the pixel
  108. // roughness = the roughness of the pixel
  109. // NdotV = the normal dot with the camera view direction
  110. // NdotL = the normal dot with the light direction
  111. // VdotH = the camera view direction dot with the half vector
  112. float3 CustomLambertianDiffuse(float3 diffuseColor, float NdotV, float roughness)
  113. {
  114. return diffuseColor * (1.0 / M_PI) * pow(NdotV, 0.5 + 0.3 * roughness);
  115. }
  116. // Burley Diffuse
  117. // diffuseColor = the rgb color value of the pixel
  118. // roughness = the roughness of the pixel
  119. // NdotV = the normal dot with the camera view direction
  120. // NdotL = the normal dot with the light direction
  121. // VdotH = the camera view direction dot with the half vector
  122. float3 BurleyDiffuse(float3 diffuseColor, float roughness, float NdotV, float NdotL, float VdotH)
  123. {
  124. const float energyBias = lerp(0, 0.5, roughness);
  125. const float energyFactor = lerp(1.0, 1.0 / 1.51, roughness);
  126. const float fd90 = energyBias + 2.0 * VdotH * VdotH * roughness;
  127. const float f0 = 1.0;
  128. const float lightScatter = f0 + (fd90 - f0) * pow(1.0f - NdotL, 5.0f);
  129. const float viewScatter = f0 + (fd90 - f0) * pow(1.0f - NdotV, 5.0f);
  130. return diffuseColor * lightScatter * viewScatter * energyFactor;
  131. }
  132. //Get Diffuse
  133. // diffuseColor = the rgb color value of the pixel
  134. // roughness = the roughness of the pixel
  135. // NdotV = the normal dot with the camera view direction
  136. // NdotL = the normal dot with the light direction
  137. // VdotH = the camera view direction dot with the half vector
  138. float3 Diffuse(float3 diffuseColor, float roughness, float NdotV, float NdotL, float VdotH)
  139. {
  140. //return LambertianDiffuse(diffuseColor);
  141. return CustomLambertianDiffuse(diffuseColor, NdotV, roughness);
  142. //return BurleyDiffuse(diffuseColor, roughness, NdotV, NdotL, VdotH);
  143. }
  144. #endif
  145. #endif