Iridescence - 图1

    1. /* Amplitude reflection coefficient (s-polarized) */
    2. float rs(float n1, float n2, float cosI, float cosT) {
    3. return (n1 * cosI - n2 * cosT) / (n1 * cosI + n2 * cosT);
    4. }
    5. /* Amplitude reflection coefficient (p-polarized) */
    6. float rp(float n1, float n2, float cosI, float cosT) {
    7. return (n2 * cosI - n1 * cosT) / (n1 * cosT + n2 * cosI);
    8. }
    9. /* Amplitude transmission coefficient (s-polarized) */
    10. float ts(float n1, float n2, float cosI, float cosT) {
    11. return 2 * n1 * cosI / (n1 * cosI + n2 * cosT);
    12. }
    13. /* Amplitude transmission coefficient (p-polarized) */
    14. float tp(float n1, float n2, float cosI, float cosT) {
    15. return 2 * n1 * cosI / (n1 * cosT + n2 * cosI);
    16. }
    17. // cosI is the cosine of the incident angle, that is, cos0 = dot(view angle, normal)
    18. // lambda is the wavelength of the incident light (e.g. lambda = 510 for green)
    19. // From http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/thin-film-interference-for-computer-graphics-r2962
    20. // The above converted to OSL from https://docs.chaosgroup.com/display/OSLShaders/Thin+Film+Shader
    21. // Modified : 03/15/2021 by Saul Espinosa - Added min/max Metadata, page groups, labels and ACES output support
    22. float thinFilmReflectance(float cos0, float lambda, float thickness, float n0, float n1, float n2) {
    23. float PI=M_PI ;
    24. // compute the phase change term (constant)
    25. float d10 = (n1 > n0) ? 0 : PI;
    26. float d12 = (n1 > n2) ? 0 : PI;
    27. float delta = d10 + d12;
    28. // now, compute cos1, the cosine of the reflected angle
    29. float sin1 = pow(n0 / n1, 2) * (1 - pow(cos0, 2));
    30. if (sin1 > 1) return 1.0; // total internal reflection
    31. float cos1 = sqrt(1 - sin1);
    32. // compute cos2, the cosine of the final transmitted angle, i.e. cos(theta_2)
    33. // we need this angle for the Fresnel terms at the bottom interface
    34. float sin2 = pow(n0 / n2, 2) * (1 - pow(cos0, 2));
    35. if (sin2 > 1) return 1.0; // total internal reflection
    36. float cos2 = sqrt(1 - sin2);
    37. // get the reflection transmission amplitude Fresnel coefficients
    38. float alpha_s = rs(n1, n0, cos1, cos0) * rs(n1, n2, cos1, cos2); // rho_10 * rho_12 (s-polarized)
    39. float alpha_p = rp(n1, n0, cos1, cos0) * rp(n1, n2, cos1, cos2); // rho_10 * rho_12 (p-polarized)
    40. float beta_s = ts(n0, n1, cos0, cos1) * ts(n1, n2, cos1, cos2); // tau_01 * tau_12 (s-polarized)
    41. float beta_p = tp(n0, n1, cos0, cos1) * tp(n1, n2, cos1, cos2); // tau_01 * tau_12 (p-polarized)
    42. // compute the phase term (phi)
    43. float phi = (2 * PI / lambda) * (2 * n1 * thickness * cos1) + delta;
    44. // finally, evaluate the transmitted intensity for the two possible polarizations
    45. float ts = pow(beta_s, 2) / (pow(alpha_s, 2) - 2 * alpha_s * cos(phi) + 1);
    46. float tp = pow(beta_p, 2) / (pow(alpha_p, 2) - 2 * alpha_p * cos(phi) + 1);
    47. // we need to take into account conservation of energy for transmission
    48. float beamRatio = (n2 * cos2) / (n0 * cos0);
    49. // calculate the average transmitted intensity (if you know the polarization distribution of your
    50. // light source, you should specify it here. if you don't, a 50%/50% average is generally used)
    51. float t = beamRatio * (ts + tp) / 2;
    52. // and finally, derive the reflected intensity
    53. return 1 - t;
    54. }
    55. surface iridescence
    56. [[ string description = "Thin film coating shader. Use as reflection color for the material, with Fresnel for the material OFF (this texture computes its own Fresnel)" ]]
    57. (
    58. float thicknessMin = 220 [[ string description = "Minimum thickness of the film, in nm", string label = "Thickness Min", float min = 0, float max = 2000 ]],
    59. float thicknessMax = 2000 [[ string description = "Maximum thickness of the film, in nm", string label = "Thickness Max", float min = 0, float max = 5000 ]],
    60. float thickness = 0 [[ string description = "Thickness variation of the film between the min and max", string label = "Thickness Variation", float min = 0, float max = 1 ]],
    61. float nfilm = 1.5 [[ string description = "Refractive index of the thin film itself", string label = "IOR Thinfilm", string page = "IOR", float min = 0, float max = 5 ]] , // approximate refractive index of water
    62. float ninternal = 1 [[ string description = "Refractive index of the material below the film", string label = "IOR Base Surface", string page = "IOR", float min = 0, float max = 5 ]], // approximate refractive index of the lower material
    63. float nmedium = 1 [[ string description = "Refractive index of the outer medium (typically air)", string label = "IOR Exterior", string page = "IOR", float min = 0, float max = 3 ]], // approximate refractive index of air
    64. int convToAces = 0 [[ string widget = "checkBox", string label = "ACES", int connectable = 0 ]],
    65. output color colorOut = 0
    66. )
    67. {
    68. // ACES Transform
    69. matrix srgbToAcesAP1 = {
    70. 0.6131, 0.0701, 0.0206, 0,
    71. 0.3395, 0.9164, 0.1096, 0,
    72. 0.0474, 0.0135, 0.8698, 0,
    73. 0, 0, 0, 1 };
    74. float cos0 = abs(dot(I , N));
    75. // color thickTex=texture(thickness, u, v);
    76. float thicktex = thickness;
    77. float t = thicktex/3.0;
    78. float thick=thicknessMin*(1.0-t)+thicknessMax*t;
    79. float red=thinFilmReflectance(cos0, 650, thick, nmedium, nfilm, ninternal);
    80. float green=thinFilmReflectance(cos0, 510, thick, nmedium, nfilm, ninternal);
    81. float blue=thinFilmReflectance(cos0, 475, thick, nmedium, nfilm, ninternal);
    82. color reflColor = color(red, green, blue);
    83. float sR = reflColor[0];
    84. float sG = reflColor[1];
    85. float sB = reflColor[2];
    86. if (convToAces == 1){
    87. colorOut = transform(srgbToAcesAP1, vector(sR, sG, sB));
    88. }
    89. else {
    90. colorOut = reflColor;
    91. }
    92. }