ThinFilmInterference - 图1

    1. /* OSL shader to calculate thin-film interference
    2. v3: Modified : 03.23.2021 by Saul Espinosa for Redshift 3d GPU Renderer, added metadata, new labels, ACES output.
    3. v1.6, 2016 prutser. License for the *code*: CC BY-NC-SA 4.0
    4. Note: the output of the code may explicitly be used for commercial renders.
    5. v1.6: Allow double layers for more flexibility. Use the #define statements below to make the code only calculate
    6. */
    7. #include "stdosl.h"
    8. #define SINGLELAYER
    9. #define DOUBLELAYER
    10. #define NONVACUUM
    11. #define EXPOSE_WAVELENGTH
    12. #ifdef DOUBLELAYER
    13. #define SINGLELAYER
    14. #endif
    15. #ifndef NONVACUUM
    16. #define IOR_outside 1
    17. #endif
    18. #ifndef EXPOSE_WAVELENGTH
    19. #define wavelength color(0.65,0.532,0.45)
    20. #endif
    21. struct complex {
    22. color r;
    23. color i;
    24. };
    25. shader thin_film
    26. [[ string help = "Advanced Multi-Layered Thin Film Interference",
    27. string label = "Thin Film Interference" ]]
    28. (
    29. #ifdef SINGLELAYER
    30. float thickness_T = 1
    31. [[
    32. string help = "thickness of layer 1 in micrometers",
    33. string label = "Top Layer Thickness",
    34. string page = "1 : Top Layer",
    35. float min = 0,
    36. float max = 25
    37. ]],
    38. float IOR_top = 1.6
    39. [[
    40. string help = "IOR for top layer",
    41. string label = "Top Layer IOR",
    42. string page = "1 : Top Layer",
    43. float min = 0,
    44. float max = 25
    45. ]],
    46. color k_top = 0
    47. [[
    48. string help = "Extinction coefficient of top layer",
    49. string label = "Top Layer Extinction",
    50. string page = "1 : Top Layer",
    51. color min = 0,
    52. color max = 1
    53. ]],
    54. #endif
    55. #ifdef DOUBLELAYER
    56. float thickness_M = 0
    57. [[
    58. string help = "thickness of layer 2 in micrometers",
    59. string label = "Middle Layer Thickness",
    60. string page = "2 : Middle Layer",
    61. float min = 0,
    62. float max = 25
    63. ]],
    64. float IOR_middle = 1
    65. [[
    66. string help = "IOR for middle layer",
    67. string label = "Mid Layer IOR",
    68. string page = "2 : Middle Layer",
    69. float min = 0,
    70. float max = 25
    71. ]],
    72. color k_middle = 0
    73. [[
    74. string help = "Extinction coefficient of top layer",
    75. string label = "Mid Layer Extinction",
    76. string page = "2 : Middle Layer",
    77. color min = 0,
    78. color max = 1
    79. ]],
    80. #endif
    81. // Substrate Parameters
    82. float IOR_base_material = 1
    83. [[
    84. string help = "IOR for Substrate Base layer",
    85. string label = "Base Layer IOR",
    86. string page = "3 : Base Layer",
    87. float min = 0,
    88. float max = 25
    89. ]],
    90. color k_base_material = 0
    91. [[
    92. string help = "Extinction coefficient of substrate layer",
    93. string label = "Base Layer Extinction",
    94. string page = "3 : Base Layer",
    95. color min = 0,
    96. color max = 1
    97. ]],
    98. #ifdef EXPOSE_WAVELENGTH
    99. color wavelength = color(0.65,0.532,0.45)
    100. [[
    101. string help = "RGB wavelengths to use for the interference",
    102. string label = "Wavelength",
    103. string page = "4 : Extra",
    104. color min = 0,
    105. color max = 1
    106. ]],
    107. #endif
    108. #ifdef NONVACUUM
    109. color IOR_outside = 1
    110. [[
    111. string help = "the index of refraction of the ‘outside world’. Typically 1, but under water would be 1.33, for example",
    112. string label = "IOR of Environment",
    113. string page = "4 : Extra",
    114. color min = 0,
    115. color max = 3
    116. ]],
    117. normal Normal = N
    118. [[
    119. string page = "4 : Extra"
    120. ]],
    121. int aces = 0
    122. [[ string widget = "checkBox",
    123. string label = "ACES",
    124. string page = "4 : Extra",
    125. int connectable = 0 ]],
    126. #endif
    127. // Outputs
    128. output color outColor = 0
    129. [[
    130. string help = "outColor: Reflected percentage of the light, per color (RGB), at the angle between the normal and the ray of light"
    131. ]],
    132. output color outColor_N = 0
    133. [[
    134. string help = "outColor_N: reflected percentage of the light, per color (RGB), at normal incidence",
    135. ]],
    136. output color Transmission = 1
    137. [[
    138. string help = "Transmission: transmitted percentage of light, per color. Can be hooked up to a refractive shader"
    139. ]],
    140. output color Trans_N = 1
    141. [[
    142. string help = "Trans_N: transmitted percentage of light at normal incidence"
    143. ]]
    144. )
    145. {
    146. // ACES sRGB Transform
    147. matrix aces_tm = matrix(
    148. 0.6131, 0.0701, 0.0206, 0,
    149. 0.3395, 0.9164, 0.1096, 0,
    150. 0.0474, 0.0135, 0.8698, 0,
    151. 0, 0, 0, 1);
    152. void cmult(complex x, complex y, output complex z)
    153. {
    154. complex tmp; //pass by reference issues, if in reality x == z
    155. tmp.r = x.r*y.r-x.i*y.i;
    156. tmp.i = x.r*y.i + x.i*y.r;
    157. z.r = tmp.r; z.i = tmp.i;
    158. }
    159. void cmult(color x, complex y, output complex z)
    160. {
    161. z.r = x*y.r;
    162. z.i = x*y.i;
    163. }
    164. void cmult(complex x, color y, output complex z)
    165. {
    166. z.r = x.r*y;
    167. z.i = x.i*y;
    168. }
    169. void cdiv(complex x, complex y, output complex z)
    170. {
    171. complex ystar;
    172. ystar.r = y.r;
    173. ystar.i = -y.i;
    174. cmult(x,ystar,z);
    175. z.r = z.r/color((ystar.r*ystar.r+ystar.i*ystar.i));
    176. z.i = z.i/color((ystar.r*ystar.r+ystar.i*ystar.i));
    177. }
    178. void cadd(complex x, complex y, output complex z)
    179. {
    180. z.r = x.r + y.r;
    181. z.i = x.i + y.i;
    182. }
    183. void cadd(complex x, color y, output complex z)
    184. {
    185. z.r = x.r + y;
    186. z.i = x.i;
    187. }
    188. void cadd(color x, complex y, output complex z)
    189. {
    190. z.r = x + y.r;
    191. z.i = y.i;
    192. }
    193. void csub(complex x, complex y, output complex z)
    194. {
    195. z.r = x.r - y.r;
    196. z.i = x.i - y.i;
    197. }
    198. void csub(color x, complex y, output complex z)
    199. {
    200. z.r = x - y.r;
    201. z.i = -y.i;
    202. }
    203. void csub(complex x, color y, output complex z)
    204. {
    205. z.r = x.r - y;
    206. z.i = x.i;
    207. }
    208. void csqrt(complex x, output complex z)
    209. {
    210. color r = sqrt(sqrt(color(x.r*x.r) + color(x.i*x.i)));
    211. color phi = atan2(x.i,x.r)/2;
    212. z.r = r*cos(phi);
    213. z.i = r*sin(phi);
    214. }
    215. void cexp(complex x, output complex z)
    216. {
    217. complex tmp;
    218. tmp.r = exp(x.r)*cos(x.i);
    219. tmp.i = exp(x.r)*sin(x.i);
    220. z.r=tmp.r;z.i=tmp.i;
    221. }
    222. void kz(complex epsilon, color k, color kx, output complex kz_)
    223. {
    224. complex root;
    225. cmult(epsilon,k*k,root); //eps*k^2
    226. csub(root, kx*kx, root); //eps*k^2-kx^2
    227. csqrt(root, kz_);
    228. }
    229. // void kx_k(float cosi, color wavelength, color n, output color kx, output color k)
    230. // {
    231. // k = M_PI*2/wavelength;
    232. // kx = sin(acos(cosi))*k*n;
    233. // }
    234. void rp(complex kzi, complex kzk, complex ei, complex ek, output complex _rp)
    235. {
    236. //return (ek kzi - ei kzk)/(ek kzi + ei kzk);
    237. complex ek_kzi; complex ei_kzk;
    238. cmult(ek, kzi, ek_kzi);
    239. cmult(ei, kzk, ei_kzk);
    240. complex N; complex D;
    241. csub(ek_kzi, ei_kzk, N);
    242. cadd(ek_kzi, ei_kzk, D);
    243. cdiv(N,D,_rp);
    244. }
    245. void rp2tp(complex rp, complex ei, complex ek, output complex _tp)
    246. {
    247. complex tmp;
    248. cdiv(ei, ek, tmp); //tmp = ei/ek
    249. csqrt(tmp,tmp); //tmp = sqrt(ei/ek)
    250. cadd(1,rp,_tp); //tp = 1 + rp
    251. cmult(_tp,tmp,_tp); //tp = (1+rp)*sqrt(ei/ek)
    252. }
    253. void rs(complex kzi, complex kzk, output complex _rs)
    254. {
    255. //return (kzi - kzk)/(kzi + kzk);
    256. complex N; complex D;
    257. csub(kzi, kzk, N);
    258. cadd(kzi, kzk, D);
    259. cdiv(N,D,_rs);
    260. }
    261. #ifdef SINGLELAYER
    262. void FR(complex r01, complex r12, complex kz1, color d, output complex _R, output complex D)
    263. {
    264. // R = (r01+r12*exp(2*1i*kz1*d))/(1+r01*r12*exp(2i*kz1*d))
    265. complex im = {color(0),color(1)};
    266. complex exponent;
    267. cmult(2,im,exponent); //2i;
    268. cmult(exponent, kz1,exponent); //2i*kz1;
    269. cmult(d, exponent, exponent); //2i*kz1*d
    270. cexp(exponent, exponent); //exp(2i*kz1*d)
    271. cmult(r12, exponent, exponent); //r12*exp(2i*kz1*d)
    272. complex Num;
    273. cadd(r01, exponent, Num); // N = r01+r12.*exp(2*1i.*kz1*d)
    274. cmult(r01,exponent, exponent); //exponent = r01*r12.*exp(2*1i.*kz1*d)
    275. cadd(1, exponent,D); // D = 1+r01*r12.*exp(2*1i.*kz1*d)
    276. cdiv(Num,D, _R);
    277. }
    278. void FT(complex t01, complex t12, complex kz1, color d, complex D, output complex _T)
    279. {
    280. complex im = {color(0),color(1)};
    281. complex Num;
    282. cmult(im, kz1,Num); //1i*kz1;
    283. cmult(d, Num, Num); //1i*kz1*d
    284. cexp(Num, Num); //exp(1i*kz1*d)
    285. cmult(t01,Num,Num);
    286. cmult(t12,Num,Num);
    287. cdiv(Num,D,_T);
    288. }
    289. #endif
    290. #if defined(SINGLELAYER) && !defined(DOUBLELAYER)
    291. void RperpRpar(color kx, color k, complex eps_0, complex eps_1, complex eps_2, float thickness_T, output complex Rp, output complex Rs, output complex Tp, output complex Ts, int calcT)
    292. {
    293. complex kz0; complex kz1; complex kz2;
    294. kz(eps_0, k, kx, kz0);
    295. kz(eps_1, k, kx, kz1);
    296. kz(eps_2, k, kx, kz2);
    297. complex r01; complex r12; complex D; // Denominator, reuse for speed
    298. complex t01; complex t12;
    299. rp(kz0,kz1,eps_0,eps_1, r01);
    300. rp(kz1,kz2,eps_1, eps_2, r12);
    301. FR(r01,r12,kz1,thickness_T,Rp, D);
    302. if (calcT)
    303. {
    304. //Transmission = t01*t12*(exp(1i*kz1*thickness_T))/(1+r01*r12*(exp(2i*kz1*thickness_T)))
    305. rp2tp(r01, eps_0,eps_1, t01);
    306. rp2tp(r12, eps_1, eps_2, t12);
    307. FT(t01,t12,kz1,thickness_T,D, Tp);
    308. }
    309. // Now S-polarized light
    310. rs(kz0,kz1, r01);
    311. rs(kz1,kz2, r12);
    312. FR(r01,r12,kz1,thickness_T,Rs, D);
    313. if (calcT)
    314. {
    315. cadd(1,r01,t01);
    316. cadd(1,r12,t12);
    317. FT(t01,t12,kz1,thickness_T,D, Ts);
    318. }
    319. }
    320. #endif
    321. #ifdef DOUBLELAYER
    322. void RperpRpar(color kx, color k, complex eps_0, complex eps_1, complex eps_2, complex eps_3, float thickness_T, float thickness_M, output complex Rp, output complex Rs, output complex Tp, output complex Ts, int calcT)
    323. {
    324. complex kz0; complex kz1; complex kz2; complex kz3;
    325. kz(eps_0, k, kx, kz0);
    326. kz(eps_1, k, kx, kz1);
    327. kz(eps_2, k, kx, kz2);
    328. kz(eps_3, k, kx, kz3);
    329. complex r01; complex r12; complex r23; complex D; // Denominator, reuse for speed
    330. complex t01; complex t12; complex t23;
    331. rp(kz0,kz1,eps_0, eps_1, r01);
    332. rp(kz1,kz2,eps_1, eps_2, r12);
    333. rp(kz2,kz3,eps_2, eps_3, r23);
    334. // calculate last layer first
    335. FR(r12,r23,kz2,thickness_M,Rp, D);
    336. // because we reuse D, do not continue with thin film calculation before calculating partial Tp
    337. if (calcT)
    338. {
    339. //Transmission = t01*t12*(exp(1i*kz1*thickness_T))/(1+r01*r12*(exp(2i*kz1*thickness_T)))
    340. rp2tp(r12, eps_1,eps_2, t12);
    341. rp2tp(r23, eps_2, eps_3, t23);
    342. FT(t12,t23,kz2,thickness_M,D, Tp);
    343. }
    344. FR(r01,Rp,kz1,thickness_T,Rp,D);
    345. if (calcT)
    346. {
    347. //Transmission = t01*t12*(exp(1i*kz1*thickness_T))/(1+r01*r12*(exp(2i*kz1*thickness_T)))
    348. rp2tp(r01, eps_0,eps_1, t01);
    349. FT(t01,Tp,kz1,thickness_T,D, Tp);
    350. }
    351. // Now S-polarized light
    352. rs(kz0,kz1, r01);
    353. rs(kz1,kz2, r12);
    354. rs(kz2,kz3, r23);
    355. FR(r12,r23,kz2,thickness_M,Rs, D);
    356. if (calcT)
    357. {
    358. cadd(1,r12,t12);
    359. cadd(1,r23,t23);
    360. FT(t12,t23,kz2,thickness_M,D, Ts);
    361. }
    362. FR(r01,Rs,kz1,thickness_T,Rs, D);
    363. if (calcT)
    364. {
    365. cadd(1,r01,t01);
    366. FT(t01,Ts,kz1,thickness_T,D, Ts);
    367. }
    368. }
    369. #endif
    370. #if !defined(SINGLELAYER)
    371. void RperpRpar(color kx, color k, complex eps_0, complex eps_2, output complex Rp, output complex Rs, output complex Tp, output complex Ts, int calcT)
    372. {
    373. complex kz0; complex kz2;
    374. kz(eps_0, k, kx, kz0);
    375. kz(eps_2, k, kx, kz2);
    376. rp(kz0,kz2,eps_0,eps_2, Rp);
    377. rs(kz0,kz2, Rs);
    378. if (calcT)
    379. {
    380. rp2tp(Rp,eps_0,eps_2, Tp);
    381. cadd(Rs,1,Ts);
    382. }
    383. }
    384. #endif
    385. int calcT = isconnected(Transmission);
    386. color k = M_PI*2/wavelength; //denominator is wavelength in um
    387. complex Rp; complex Rs; complex Ts; complex Tp;
    388. #ifdef DOUBLELAYER
    389. float local_d1 = thickness_T; float local_d2 = thickness_M;
    390. #endif
    391. complex nsub = {IOR_base_material, k_base_material};
    392. complex eps3; complex eps0;
    393. if (backfacing())
    394. {
    395. cmult(nsub,nsub,eps0);
    396. eps3.r=IOR_outside; eps3.i=0;
    397. }
    398. else
    399. {
    400. cmult(nsub,nsub,eps3);
    401. eps0.r=IOR_outside; eps0.i=0;
    402. }
    403. // the following is nonsense for backfacing metallic substrates
    404. // but so is a ray of light coming out of a metallic substrate
    405. color kx = sin(acos(dot(I,Normal)))*k*sqrt(eps0.r);
    406. #ifdef SINGLELAYER
    407. complex nfilm = {IOR_top, k_top};
    408. complex eps1;
    409. cmult(nfilm,nfilm,eps1);
    410. #endif
    411. #ifdef DOUBLELAYER
    412. nfilm.r = IOR_middle; nfilm.i =k_middle;
    413. complex eps2;
    414. cmult(nfilm,nfilm,eps2);
    415. if (backfacing())
    416. {
    417. complex tmp = eps1;
    418. eps1 = eps2;
    419. eps2 = tmp;
    420. local_d1 = thickness_M; local_d2 = thickness_T;
    421. }
    422. #endif
    423. #ifdef DOUBLELAYER
    424. RperpRpar(kx, k, eps0, eps1, eps2, eps3, local_d1, local_d2, Rp, Rs, Tp, Ts, calcT);
    425. #elif defined(SINGLELAYER)
    426. RperpRpar(kx, k, eps0, eps1, eps3, thickness_T, Rp, Rs, Tp, Ts, calcT);
    427. #else //no layer
    428. RperpRpar(kx, k, eps0, eps3, Rp, Rs, Tp, Ts, calcT);
    429. #endif
    430. color out_film = (Rp.r*Rp.r+Rp.i*Rp.i+Rs.r*Rs.r+Rs.i*Rs.i)*0.5;
    431. float r = out_film[0], g = out_film[1], b = out_film[2];
    432. // ACES Output
    433. if (aces == 0)
    434. outColor = out_film;
    435. else
    436. {
    437. outColor = transform(aces_tm, vector(r,g,b));
    438. }
    439. if(calcT)
    440. {
    441. #ifdef DOUBLELAYER
    442. if (k_top == 0 && k_middle == 0) //no absorption in the film
    443. #endif
    444. #if defined(SINGLELAYER) && !defined(DOUBLELAYER)
    445. if (k_top == 0) //no absorption in the film
    446. #endif
    447. #ifdef SINGLELAYER
    448. Transmission = 1-outColor; // Quick shortcut
    449. else
    450. { // I'm going to be pragmatic here.
    451. // Strictly speaking, the angle of refraction depends not only on the IOR, but also on the absorbance of the substrate (k).
    452. // But, since this isn't supported in ray tracers anyway, I'm going to let it slide.
    453. // Moreover, this is only really an issue when k ~ 1, and then the light is absorbed within about a wavelength anyway.
    454. Transmission = (Tp.r*Tp.r+Tp.i*Tp.i+Ts.r*Ts.r+Ts.i*Ts.i)*0.5;
    455. Transmission = backfacing()? Transmission/IOR_base_material:Transmission*IOR_base_material;
    456. }
    457. #endif
    458. #ifndef SINGLELAYER
    459. Transmission = 1-outColor;
    460. #endif
    461. }
    462. calcT = isconnected(Trans_N);
    463. if (isconnected(outColor_N) || calcT)
    464. {
    465. #ifdef DOUBLELAYER
    466. RperpRpar(0, k, eps0, eps1, eps2, eps3, thickness_T, thickness_M, Rp, Rs, Tp, Ts, calcT);
    467. #elif defined(SINGLELAYER)
    468. RperpRpar(0, k, eps0, eps1, eps3, thickness_T, Rp, Rs, Tp, Ts, calcT);
    469. #else //no layer
    470. RperpRpar(0, k, eps0, eps3, Rp, Rs, Tp, Ts, calcT);
    471. #endif
    472. color outColor_N = (Rp.r*Rp.r+Rp.i*Rp.i+Rs.r*Rs.r+Rs.i*Rs.i)*0.5;
    473. if (calcT)
    474. {
    475. #ifdef DOUBLELAYER
    476. if (k_top == 0 && k_middle == 0) //no absorption in the film
    477. #elif defined(SINGLELAYER)
    478. if (k_top == 0) //no absorption in the film
    479. #else
    480. color Trans_N = 1-outColor_N;
    481. #endif
    482. #ifdef SINGLELAYER
    483. color Trans_N = 1-outColor_N; // Quick shortcut
    484. else
    485. {
    486. Trans_N = (Tp.r*Tp.r+Tp.i*Tp.i+Ts.r*Ts.r+Ts.i*Ts.i)*0.5;
    487. Trans_N = backfacing()? Trans_N/IOR_base_material:Trans_N*IOR_base_material;
    488. }
    489. #endif
    490. }
    491. }
    492. }