bsdf_util.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * Adapted from Open Shading Language with this license:
  3. *
  4. * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
  5. * All Rights Reserved.
  6. *
  7. * Modifications Copyright 2011, Blender Foundation.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions are
  11. * met:
  12. * * Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * * Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * * Neither the name of Sony Pictures Imageworks nor the names of its
  18. * contributors may be used to endorse or promote products derived from
  19. * this software without specific prior written permission.
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #ifndef __BSDF_UTIL_H__
  33. #define __BSDF_UTIL_H__
  34. CCL_NAMESPACE_BEGIN
  35. ccl_device float fresnel_dielectric(float eta,
  36. const float3 N,
  37. const float3 I,
  38. float3 *R,
  39. float3 *T,
  40. #ifdef __RAY_DIFFERENTIALS__
  41. const float3 dIdx,
  42. const float3 dIdy,
  43. float3 *dRdx,
  44. float3 *dRdy,
  45. float3 *dTdx,
  46. float3 *dTdy,
  47. #endif
  48. bool *is_inside)
  49. {
  50. float cos = dot(N, I), neta;
  51. float3 Nn;
  52. // check which side of the surface we are on
  53. if (cos > 0) {
  54. // we are on the outside of the surface, going in
  55. neta = 1 / eta;
  56. Nn = N;
  57. *is_inside = false;
  58. }
  59. else {
  60. // we are inside the surface
  61. cos = -cos;
  62. neta = eta;
  63. Nn = -N;
  64. *is_inside = true;
  65. }
  66. // compute reflection
  67. *R = (2 * cos) * Nn - I;
  68. #ifdef __RAY_DIFFERENTIALS__
  69. *dRdx = (2 * dot(Nn, dIdx)) * Nn - dIdx;
  70. *dRdy = (2 * dot(Nn, dIdy)) * Nn - dIdy;
  71. #endif
  72. float arg = 1 - (neta * neta * (1 - (cos * cos)));
  73. if (arg < 0) {
  74. *T = make_float3(0.0f, 0.0f, 0.0f);
  75. #ifdef __RAY_DIFFERENTIALS__
  76. *dTdx = make_float3(0.0f, 0.0f, 0.0f);
  77. *dTdy = make_float3(0.0f, 0.0f, 0.0f);
  78. #endif
  79. return 1; // total internal reflection
  80. }
  81. else {
  82. float dnp = max(sqrtf(arg), 1e-7f);
  83. float nK = (neta * cos) - dnp;
  84. *T = -(neta * I) + (nK * Nn);
  85. #ifdef __RAY_DIFFERENTIALS__
  86. *dTdx = -(neta * dIdx) + ((neta - neta * neta * cos / dnp) * dot(dIdx, Nn)) * Nn;
  87. *dTdy = -(neta * dIdy) + ((neta - neta * neta * cos / dnp) * dot(dIdy, Nn)) * Nn;
  88. #endif
  89. // compute Fresnel terms
  90. float cosTheta1 = cos; // N.R
  91. float cosTheta2 = -dot(Nn, *T);
  92. float pPara = (cosTheta1 - eta * cosTheta2) / (cosTheta1 + eta * cosTheta2);
  93. float pPerp = (eta * cosTheta1 - cosTheta2) / (eta * cosTheta1 + cosTheta2);
  94. return 0.5f * (pPara * pPara + pPerp * pPerp);
  95. }
  96. }
  97. ccl_device float fresnel_dielectric_cos(float cosi, float eta)
  98. {
  99. // compute fresnel reflectance without explicitly computing
  100. // the refracted direction
  101. float c = fabsf(cosi);
  102. float g = eta * eta - 1 + c * c;
  103. if (g > 0) {
  104. g = sqrtf(g);
  105. float A = (g - c) / (g + c);
  106. float B = (c * (g + c) - 1) / (c * (g - c) + 1);
  107. return 0.5f * A * A * (1 + B * B);
  108. }
  109. return 1.0f; // TIR(no refracted component)
  110. }
  111. ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k)
  112. {
  113. float3 cosi2 = make_float3(cosi * cosi, cosi * cosi, cosi * cosi);
  114. float3 one = make_float3(1.0f, 1.0f, 1.0f);
  115. float3 tmp_f = eta * eta + k * k;
  116. float3 tmp = tmp_f * cosi2;
  117. float3 Rparl2 = (tmp - (2.0f * eta * cosi) + one) / (tmp + (2.0f * eta * cosi) + one);
  118. float3 Rperp2 = (tmp_f - (2.0f * eta * cosi) + cosi2) / (tmp_f + (2.0f * eta * cosi) + cosi2);
  119. return (Rparl2 + Rperp2) * 0.5f;
  120. }
  121. ccl_device float schlick_fresnel(float u)
  122. {
  123. float m = clamp(1.0f - u, 0.0f, 1.0f);
  124. float m2 = m * m;
  125. return m2 * m2 * m; // pow(m, 5)
  126. }
  127. ccl_device float smooth_step(float edge0, float edge1, float x)
  128. {
  129. float result;
  130. if (x < edge0)
  131. result = 0.0f;
  132. else if (x >= edge1)
  133. result = 1.0f;
  134. else {
  135. float t = (x - edge0) / (edge1 - edge0);
  136. result = (3.0f - 2.0f * t) * (t * t);
  137. }
  138. return result;
  139. }
  140. /* Calculate the fresnel color which is a blend between white and the F0 color (cspec0) */
  141. ccl_device_forceinline float3
  142. interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0)
  143. {
  144. /* Calculate the fresnel interpolation factor
  145. * The value from fresnel_dielectric_cos(...) has to be normalized because
  146. * the cspec0 keeps the F0 color
  147. */
  148. float F0_norm = 1.0f / (1.0f - F0);
  149. float FH = (fresnel_dielectric_cos(dot(L, H), ior) - F0) * F0_norm;
  150. /* Blend between white and a specular color with respect to the fresnel */
  151. return cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH;
  152. }
  153. CCL_NAMESPACE_END
  154. #endif /* __BSDF_UTIL_H__ */