PBR.hlsl 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #include "BRDF.hlsl"
  2. #ifdef COMPILEPS
  3. float3 GetSpecularDominantDir(float3 normal, float3 reflection, float roughness)
  4. {
  5. const float smoothness = 1.0 - roughness;
  6. const float lerpFactor = smoothness * (sqrt(smoothness) + roughness);
  7. return lerp(normal, reflection, lerpFactor);
  8. }
  9. float3 SphereLight(float3 worldPos, float3 lightVec, float3 normal, float3 toCamera, float roughness, float3 specColor, float3 diffColor, out float ndl)
  10. {
  11. float specEnergy = 1.0f;
  12. float radius = cLightRad / 100;
  13. float rough2 = max(roughness, 0.08);
  14. rough2 *= rough2;
  15. float radius2 = radius * radius;
  16. float distToLightSqrd = dot(lightVec,lightVec);
  17. float invDistToLight = rsqrt(distToLightSqrd);
  18. float sinAlphaSqr = saturate(radius2 / distToLightSqrd);
  19. float sinAlpha = sqrt(sinAlphaSqr);
  20. ndl = dot(normal, (lightVec * invDistToLight));
  21. if(ndl < sinAlpha)
  22. {
  23. ndl = max(ndl, -sinAlpha);
  24. ndl = ((sinAlpha + ndl) * (sinAlpha + ndl)) / (4 * sinAlpha);
  25. }
  26. float sphereAngle = saturate(radius * invDistToLight);
  27. specEnergy = rough2 / (rough2 + 0.5f * sphereAngle);
  28. specEnergy *= specEnergy;
  29. float3 R = 2 * dot(toCamera, normal) * normal - toCamera;
  30. R = GetSpecularDominantDir(normal, R, roughness);
  31. // Find closest point on sphere to ray
  32. float3 closestPointOnRay = dot(lightVec, R) * R;
  33. float3 centerToRay = closestPointOnRay - lightVec;
  34. float invDistToRay = rsqrt(dot(centerToRay, centerToRay));
  35. float3 closestPointOnSphere = lightVec + centerToRay * saturate(radius * invDistToRay);
  36. lightVec = closestPointOnSphere;
  37. float3 L = normalize(lightVec);
  38. float3 h = normalize(toCamera + L);
  39. float hdn = saturate(dot(h, normal));
  40. float hdv = dot(h, toCamera);
  41. float ndv = saturate(dot(normal, toCamera));
  42. float hdl = saturate(dot(h, lightVec));
  43. const float3 diffuseFactor = Diffuse(diffColor, roughness, ndv, ndl, hdv) * ndl;
  44. const float3 fresnelTerm = Fresnel(specColor, hdv, hdl) ;
  45. const float distTerm = Distribution(hdn, roughness);
  46. const float visTerm = Visibility(ndl, ndv, roughness);
  47. float3 specularFactor = distTerm * visTerm * fresnelTerm * ndl/ M_PI;
  48. return diffuseFactor + specularFactor;
  49. }
  50. float3 TubeLight(float3 worldPos, float3 lightVec, float3 normal, float3 toCamera, float roughness, float3 specColor, float3 diffColor, out float ndl)
  51. {
  52. float radius = cLightRad / 100;
  53. float len = cLightLength / 10;
  54. float3 pos = (cLightPosPS.xyz - worldPos);
  55. float3 reflectVec = reflect(-toCamera, normal);
  56. float3 L01 = cLightDirPS * len;
  57. float3 L0 = pos - 0.5 * L01;
  58. float3 L1 = pos + 0.5 * L01;
  59. float3 ld = L1 - L0;
  60. float distL0 = length( L0 );
  61. float distL1 = length( L1 );
  62. float NoL0 = dot( L0, normal ) / ( 2.0 * distL0 );
  63. float NoL1 = dot( L1, normal ) / ( 2.0 * distL1 );
  64. ndl = ( 2.0 * clamp( NoL0 + NoL1, 0.0, 1.0 ) )
  65. / ( distL0 * distL1 + dot( L0, L1 ) + 2.0 );
  66. float a = len * len;
  67. float b = dot( reflectVec, L01 );
  68. float t = saturate( dot( L0, b * reflectVec - L01 ) / (a - b*b) );
  69. float3 closestPoint = L0 + ld * saturate( t);
  70. float3 centreToRay = dot( closestPoint, reflectVec ) * reflectVec - closestPoint;
  71. closestPoint = closestPoint + centreToRay * saturate(radius / length(centreToRay));
  72. float3 l = normalize(closestPoint);
  73. float3 h = normalize(toCamera + l);
  74. ndl = saturate(dot(normal, lightVec));
  75. float hdn = saturate(dot(h, normal));
  76. float hdv = dot(h, toCamera);
  77. float ndv = saturate(dot(normal, toCamera));
  78. float hdl = saturate(dot(h, lightVec));
  79. float distL = length(closestPoint);
  80. float alpha = max(roughness, 0.08) * max(roughness, 0.08);
  81. float alphaPrime = saturate(radius / (distL * 2.0) + alpha);
  82. const float3 diffuseFactor = Diffuse(diffColor, roughness, ndv, ndl, hdv) * ndl;
  83. const float3 fresnelTerm = Fresnel(specColor, hdv, hdl) ;
  84. const float distTerm = Distribution(hdn, roughness);
  85. const float visTerm = Visibility(ndl, ndv, roughness);
  86. float3 specularFactor = distTerm * visTerm * fresnelTerm * ndl/ M_PI;
  87. return diffuseFactor + specularFactor;
  88. }
  89. //Return the PBR BRDF value
  90. // lightDir = the vector to the light
  91. // lightVec = normalised lightDir
  92. // toCamera = vector to the camera
  93. // normal = surface normal of the pixel
  94. // roughness = roughness of the pixel
  95. // diffColor = the rgb color of the pixel
  96. // specColor = the rgb specular color of the pixel
  97. float3 GetBRDF(float3 worldPos, float3 lightDir, float3 lightVec, float3 toCamera, float3 normal, float roughness, float3 diffColor, float3 specColor)
  98. {
  99. const float3 Hn = normalize(toCamera + lightDir);
  100. const float vdh = clamp((dot(toCamera, Hn)), M_EPSILON, 1.0);
  101. const float ndh = clamp((dot(normal, Hn)), M_EPSILON, 1.0);
  102. float ndl = clamp((dot(normal, lightVec)), M_EPSILON, 1.0);
  103. const float ndv = clamp((dot(normal, toCamera)), M_EPSILON, 1.0);
  104. const float ldh = clamp((dot(lightVec, Hn)), M_EPSILON, 1.0);
  105. const float3 diffuseFactor = Diffuse(diffColor, roughness, ndv, ndl, vdh) * ndl;
  106. float3 specularFactor = 0;
  107. #ifdef SPECULAR
  108. if(cLightRad > 0.0)
  109. {
  110. if(cLightLength > 0.0)
  111. {
  112. return TubeLight(worldPos, lightVec, normal, toCamera, roughness, specColor, diffColor, ndl);
  113. }
  114. else
  115. {
  116. return SphereLight(worldPos, lightVec, normal, toCamera, roughness, specColor, diffColor, ndl);
  117. }
  118. }
  119. else
  120. {
  121. const float3 fresnelTerm = Fresnel(specColor, vdh, ldh) ;
  122. const float distTerm = Distribution(ndh, roughness);
  123. const float visTerm = Visibility(ndl, ndv, roughness);
  124. specularFactor = distTerm * visTerm * fresnelTerm * ndl/ M_PI;
  125. return diffuseFactor + specularFactor;
  126. }
  127. #endif
  128. return diffuseFactor + specularFactor;
  129. }
  130. #endif