Advertisement
Guest User

Untitled

a guest
Oct 22nd, 2019
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 38.96 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include "redner.h"
  4. #include "vector.h"
  5. #include "intersection.h"
  6. #include "buffer.h"
  7. #include "ptr.h"
  8. #include "texture.h"
  9.  
  10. #include <tuple>
  11.  
  12. struct Material {
  13. Material() {}
  14.  
  15. Material(Texture3 diffuse_reflectance,
  16. Texture3 specular_reflectance,
  17. Texture1 roughness,
  18. Texture3 normal_map,
  19. bool two_sided)
  20. : diffuse_reflectance(diffuse_reflectance),
  21. specular_reflectance(specular_reflectance),
  22. roughness(roughness),
  23. normal_map(normal_map),
  24. two_sided(two_sided) {}
  25.  
  26. inline std::tuple<int, int, int> get_diffuse_size() const {
  27. return std::make_tuple(
  28. diffuse_reflectance.width,
  29. diffuse_reflectance.height,
  30. diffuse_reflectance.num_levels);
  31. }
  32.  
  33. inline std::tuple<int, int, int> get_specular_size() const {
  34. return std::make_tuple(
  35. specular_reflectance.width,
  36. specular_reflectance.height,
  37. specular_reflectance.num_levels);
  38. }
  39.  
  40. inline std::tuple<int, int, int> get_roughness_size() const {
  41. return std::make_tuple(
  42. roughness.width,
  43. roughness.height,
  44. roughness.num_levels);
  45. }
  46.  
  47. inline std::tuple<int, int, int> get_normal_map_size() const {
  48. return std::make_tuple(
  49. normal_map.width,
  50. normal_map.height,
  51. normal_map.num_levels);
  52. }
  53.  
  54. Texture3 diffuse_reflectance;
  55. Texture3 specular_reflectance;
  56. Texture1 roughness;
  57. Texture3 normal_map;
  58. bool two_sided;
  59. };
  60.  
  61. struct DMaterial {
  62. Texture3 diffuse_reflectance;
  63. Texture3 specular_reflectance;
  64. Texture1 roughness;
  65. Texture3 normal_map;
  66. };
  67.  
  68. template <typename T>
  69. struct TBSDFSample {
  70. TVector2<T> uv;
  71. T w;
  72. };
  73.  
  74. using BSDFSample = TBSDFSample<Real>;
  75.  
  76. DEVICE
  77. inline Vector3 get_diffuse_reflectance(const Material &material,
  78. const SurfacePoint &shading_point) {
  79. return get_texture_value(material.diffuse_reflectance,
  80. shading_point.uv, shading_point.du_dxy, shading_point.dv_dxy);
  81. }
  82.  
  83. DEVICE
  84. inline void d_get_diffuse_reflectance(const Material &material,
  85. const SurfacePoint &shading_point,
  86. const Vector3 &d_output,
  87. Texture3 &d_texture,
  88. SurfacePoint &d_shading_point) {
  89. d_get_texture_value(material.diffuse_reflectance,
  90. shading_point.uv,
  91. shading_point.du_dxy,
  92. shading_point.dv_dxy,
  93. d_output,
  94. d_texture,
  95. d_shading_point.uv,
  96. d_shading_point.du_dxy,
  97. d_shading_point.dv_dxy);
  98. }
  99.  
  100. DEVICE
  101. inline Vector3 get_specular_reflectance(const Material &material,
  102. const SurfacePoint &shading_point) {
  103. return get_texture_value(material.specular_reflectance,
  104. shading_point.uv, shading_point.du_dxy, shading_point.dv_dxy);
  105. }
  106.  
  107. DEVICE
  108. inline void d_get_specular_reflectance(const Material &material,
  109. const SurfacePoint &shading_point,
  110. const Vector3 &d_output,
  111. Texture3 &d_texture,
  112. SurfacePoint &d_shading_point) {
  113. d_get_texture_value(material.specular_reflectance,
  114. shading_point.uv,
  115. shading_point.du_dxy,
  116. shading_point.dv_dxy,
  117. d_output,
  118. d_texture,
  119. d_shading_point.uv,
  120. d_shading_point.du_dxy,
  121. d_shading_point.dv_dxy);
  122. }
  123.  
  124. DEVICE
  125. inline Real get_roughness(const Material &material,
  126. const SurfacePoint &shading_point) {
  127. return get_texture_value(material.roughness,
  128. shading_point.uv, shading_point.du_dxy, shading_point.dv_dxy);
  129. }
  130.  
  131. DEVICE
  132. inline void d_get_roughness(const Material &material,
  133. const SurfacePoint &shading_point,
  134. const Real d_output,
  135. Texture1 &d_texture,
  136. SurfacePoint &d_shading_point) {
  137. d_get_texture_value(material.roughness,
  138. shading_point.uv,
  139. shading_point.du_dxy,
  140. shading_point.dv_dxy,
  141. d_output,
  142. d_texture,
  143. d_shading_point.uv,
  144. d_shading_point.du_dxy,
  145. d_shading_point.dv_dxy);
  146. }
  147.  
  148. DEVICE
  149. inline bool has_normal_map(const Material &material) {
  150. return material.normal_map.texels != nullptr;
  151. }
  152.  
  153. DEVICE
  154. inline Vector3 get_normal(const Material &material,
  155. const SurfacePoint &shading_point) {
  156. return get_texture_value(material.normal_map,
  157. shading_point.uv, shading_point.du_dxy, shading_point.dv_dxy);
  158. }
  159.  
  160. DEVICE
  161. inline void d_get_normal(const Material &material,
  162. const SurfacePoint &shading_point,
  163. const Vector3 &d_output,
  164. Texture3 &d_texture,
  165. SurfacePoint &d_shading_point) {
  166. d_get_texture_value(material.normal_map,
  167. shading_point.uv,
  168. shading_point.du_dxy,
  169. shading_point.dv_dxy,
  170. d_output,
  171. d_texture,
  172. d_shading_point.uv,
  173. d_shading_point.du_dxy,
  174. d_shading_point.dv_dxy);
  175. }
  176.  
  177. // y = 2 / x - 2
  178. // y + 2 = 2 / x
  179. // x = 2 / (y + 2)
  180. DEVICE
  181. inline Real roughness_to_phong(Real roughness) {
  182. return max(2.f / roughness - 2.f, Real(0));
  183. }
  184.  
  185. DEVICE
  186. inline Real d_roughness_to_phong(Real roughness, Real d_exponent) {
  187. return (roughness > 0 && roughness <= 1.f) ?
  188. -2.f * d_exponent / square(roughness) : 0.f;
  189. }
  190.  
  191. DEVICE
  192. inline Frame perturb_shading_frame(const Material &material,
  193. const SurfacePoint &shading_point) {
  194. auto n = 2 * get_normal(material, shading_point) - 1;
  195. auto perturb_n = normalize(to_world(shading_point.shading_frame, n));
  196. auto perturb_x = normalize(
  197. shading_point.dpdu - perturb_n * dot(perturb_n, shading_point.dpdu));
  198. auto perturb_y = cross(perturb_n, perturb_x);
  199. return Frame(perturb_x, perturb_y, perturb_n);
  200. }
  201.  
  202. DEVICE
  203. inline void d_perturb_shading_frame(const Material &material,
  204. const SurfacePoint &shading_point,
  205. const Frame &d_frame,
  206. DMaterial &d_material,
  207. SurfacePoint &d_shading_point) {
  208. // Perturb shading frame
  209. auto n = 2 * get_normal(material, shading_point) - 1;
  210. auto npn = to_world(shading_point.shading_frame, n);
  211. auto perturb_n = normalize(npn);
  212. auto dot_pn_dpdu = dot(perturb_n, shading_point.dpdu);
  213. auto npx = shading_point.dpdu - perturb_n * dot_pn_dpdu;
  214. auto perturb_x = normalize(npx);
  215. // perturb_y = cross(perturb_n, perturb_x)
  216. // return Frame(perturb_x, perturb_y, perturb_n)
  217. auto d_perturb_n = Vector3{0, 0, 0};
  218. auto d_perturb_x = Vector3{0, 0, 0};
  219. d_cross(perturb_n, perturb_x, d_frame[1], d_perturb_n, d_perturb_x);
  220. // perturb_x = normalize(npx)
  221. auto d_npx = d_normalize(npx, d_perturb_x);
  222. // npx = shading_point.dpdu - perturb_n * dot(perturb_n, shading_point.dpdu)
  223. d_shading_point.dpdu += d_npx;
  224. d_perturb_n -= d_npx * dot_pn_dpdu;
  225. auto d_dot_pn_dpdu = -d_npx * dot_pn_dpdu;
  226. // dot_pn_dpdu = dot(perturb_n, shading_point.dpdu)
  227. d_perturb_n += dot_pn_dpdu * shading_point.dpdu;
  228. d_shading_point.dpdu += d_dot_pn_dpdu * perturb_n;
  229. // perturb_n = normalize(npn)
  230. auto d_npn = d_normalize(npn, d_perturb_n);
  231. // npn = to_world(shading_point.shading_frame, n)
  232. auto d_normal_map_n = Vector3{0, 0, 0};
  233. d_to_world(shading_point.shading_frame, n, d_npn,
  234. d_shading_point.shading_frame, d_normal_map_n);
  235. // n = 2 * get_normal(material, shading_point) - 1
  236. d_get_normal(material,
  237. shading_point,
  238. 2 * d_normal_map_n,
  239. d_material.normal_map,
  240. d_shading_point);
  241. }
  242.  
  243. // Specialized version
  244. DEVICE
  245. inline void d_perturb_shading_frame(const Material &material,
  246. const SurfacePoint &shading_point,
  247. const Vector3 &d_n,
  248. DMaterial &d_material,
  249. SurfacePoint &d_shading_point) {
  250. // Perturb shading frame
  251. auto n = get_normal(material, shading_point);
  252. auto npn = to_world(shading_point.shading_frame, n);
  253. // perturb_n = normalize(npn)
  254. auto d_npn = d_normalize(npn, d_n);
  255. auto d_normal_map_n = Vector3{0, 0, 0};
  256. d_to_world(shading_point.shading_frame, n, d_npn,
  257. d_shading_point.shading_frame, d_normal_map_n);
  258. // n = 2 * get_normal(material, shading_point) - 1
  259. d_get_normal(material,
  260. shading_point,
  261. 2 * d_normal_map_n,
  262. d_material.normal_map,
  263. d_shading_point);
  264. }
  265.  
  266. // TODO: update
  267. const Real ior = 1.5f;
  268. const bool sampleVisibleArea = true;
  269. const Real etaA = 1.0f;
  270. const Real etaB = 1.5f;
  271.  
  272.  
  273. DEVICE
  274. inline
  275. Real Clamp(Real val, Real low, Real high) {
  276. if (val < low) val = low;
  277. if (val > high) val = high;
  278. return val;
  279. }
  280.  
  281. // BSDF Inline Functions
  282.  
  283. DEVICE
  284. inline
  285. Real CosTheta(const Vector3 &w) { return w.z; }
  286.  
  287. Vector3 d_CosTheta(const Vector3 &w) { return }
  288.  
  289. DEVICE
  290. inline
  291. Real Cos2Theta(const Vector3 &w) { return w.z * w.z; }
  292.  
  293. DEVICE
  294. inline
  295. Real d_Cos2Theta(const Vector3 &w) { return 2.f * CosTheta(w) * -SinTheta(w); }
  296.  
  297. DEVICE
  298. inline
  299. Real AbsCosTheta(const Vector3 &w) { return fabs(w.z); }
  300.  
  301. DEVICE
  302. inline
  303. Real Sin2Theta(const Vector3 &w) {
  304. return max(Real(0), Real(1) - Cos2Theta(w));
  305. }
  306.  
  307. DEVICE
  308. inline
  309. Real d_Sin2Theta(const Vector3 &w) { return 2.f * SinTheta(w) * CosTheta(w); }
  310.  
  311. DEVICE
  312. inline
  313. Real SinTheta(const Vector3 &w) { return sqrt(Sin2Theta(w)); }
  314.  
  315. DEVICE
  316. inline
  317. Real SecTheta(const Vector3 &w) { return 1.f / CosTheta(w); }
  318.  
  319. DEVICE
  320. inline
  321. Real Sec2Theta(const Vector3 &w) { return SecTheta(w) * SecTheta(w); }
  322.  
  323. DEVICE
  324. inline
  325. Real TanTheta(const Vector3 &w) { return SinTheta(w) / CosTheta(w); }
  326.  
  327. DEVICE
  328. inline
  329. Real d_TanTheta(const Vector3 &w) { return Sec2Theta(w); }
  330.  
  331. DEVICE
  332. inline
  333. Real Tan2Theta(const Vector3 &w) {
  334. return Sin2Theta(w) / Cos2Theta(w);
  335. }
  336.  
  337. DEVICE
  338. inline
  339. Real d_Tan2Theta(const Vector3 &w) {
  340. return 2.f * TanTheta(w) * d_TanTheta(w);
  341. }
  342.  
  343. DEVICE
  344. inline
  345. Real CosPhi(const Vector3 &w) {
  346. Real sinTheta = SinTheta(w);
  347. return (sinTheta == 0) ? 1 : Clamp(w.x / sinTheta, -1, 1);
  348. }
  349.  
  350. DEVICE
  351. inline
  352. Real SinPhi(const Vector3 &w) {
  353. Real sinTheta = SinTheta(w);
  354. return (sinTheta == 0) ? 0 : Clamp(w.y / sinTheta, -1, 1);
  355. }
  356.  
  357. DEVICE
  358. inline
  359. Real Cos2Phi(const Vector3 &w) { return CosPhi(w) * CosPhi(w); }
  360.  
  361. DEVICE
  362. inline
  363. Real d_Cos2Phi(const Vector3 &w) { return 2.f * CosPhi(w) * -SinPhi(w); }
  364.  
  365. DEVICE
  366. inline
  367. Real Sin2Phi(const Vector3 &w) { return SinPhi(w) * SinPhi(w); }
  368.  
  369. DEVICE
  370. inline
  371. Real d_Sin2Phi(const Vector3 &w) { return 2.f * SinPhi(w) * CosPhi(w); }
  372.  
  373.  
  374. DEVICE
  375. inline
  376. Real RoughnessToAlpha(Real roughness) {
  377. auto x = log(roughness);
  378. return 1.62142f + 0.819955f * x + 0.1734f * x * x +
  379. 0.0171201f * x * x * x + 0.000640711f * x * x * x * x;
  380. }
  381.  
  382. DEVICE
  383. inline
  384. Real d_RoughnessToAlpha(Real roughness) {
  385. auto x = log(roughness);
  386. auto d_log_d_x = 1.f / roughness;
  387. return 0.819955f * d_log_d_x
  388. + 0.1734f * 2.f * x * d_log_d_x
  389. + 0.0171201f * 3.f * x * x * d_log_d_x
  390. + 0.000640711f * 4.f * x * x * x * d_log_d_x;
  391. }
  392.  
  393. DEVICE
  394. inline
  395. Real Lambda(const Vector3 &w, Real roughness) {
  396. Real absTanTheta = std::abs(TanTheta(w));
  397. if (std::isinf(absTanTheta)) return 0.;
  398.  
  399. Real alphax = RoughnessToAlpha(roughness);
  400. Real alphay = alphax;
  401.  
  402. // Compute _alpha_ for direction _w_
  403. Real alpha = sqrt(Cos2Phi(w) * alphax * alphax + Sin2Phi(w) * alphay * alphay);
  404. Real alpha2Tan2Theta = (alpha * absTanTheta) * (alpha * absTanTheta);
  405. return (-1 + sqrt(1.f + alpha2Tan2Theta)) / 2;
  406. }
  407.  
  408. DEVICE
  409. inline
  410. void d_Lambda(const Vector3 &w, Real roughness, Vector3 &d_lambda_d_w, Real &d_lambda_d_roughness) {
  411. Real absTanTheta = std::abs(TanTheta(w));
  412. if (std::isinf(absTanTheta)) return 0.;
  413.  
  414. Real d_absTanTheta_d_w = ((TanTheta(w) < 0.f) ? -1.f : 1.f) * d_TanTheta(w);
  415.  
  416. Real alphax = RoughnessToAlpha(roughness);
  417. Real alphay = alphax;
  418.  
  419. /* Derivatives of anisotropic alphas w.r.t. roughness. */
  420. Real d_alphax_d_roughness = d_RoughnessToAlpha(roughness);
  421. Real d_alphay_d_roughness = d_alphax;
  422.  
  423. // Compute _alpha_ for direction _w_
  424. Real alpha = sqrt(Cos2Phi(w) * alphax * alphax + Sin2Phi(w) * alphay * alphay);
  425.  
  426. /* Derivative of alpha w.r.t. roughness. */
  427. Real d_alpha_d_roughness = 0.5f/alpha * (2.f * Cos2Phi(w) * alphax * d_alphax_d_roughness
  428. + 2.f * Sin2Phi(w) * alphay * d_alphay_d_roughness);
  429.  
  430. /* Derivative of alpha w.r.t. w. */
  431. Real d_alpha_d_w = 0.5f/alpha * (alphax * alphax * d_Cos2Phi(w) + alphay * alphay * d_Sin2Phi(w));
  432.  
  433. Real alpha2Tan2Theta = (alpha * absTanTheta) * (alpha * absTanTheta);
  434.  
  435. /* Derivative of alpha2Tan2Theta w.r.t. roughness. */
  436. Real d_alpha2Tan2Theta_d_roughness = 2.f * (alpha * absTanTheta) * d_alpha_d_roughness;
  437.  
  438. /* Derivative of alpha2Tan2Theta w.r.t. w. */
  439. Real d_alpha2Tan2Theta_d_roughness = 2.f * (alpha * absTanTheta) * (d_alpha_d_w * absTanTheta + alpha * d_absTanTheta_d_w);
  440.  
  441. /* LAMBDA: return (-1 + sqrt(1.f + alpha2Tan2Theta)) / 2; */
  442.  
  443. /* Derivative of lambda w.r.t. roughness. */
  444. d_lambda_d_roughness = 0.5f * ((0.5f / sqrt(1 + alpha2Tan2Theta)) * d_alpha2Tan2Theta_d_roughness);
  445.  
  446. /* Derivative of lambda w.r.t. w. */
  447. d_lambda_d_w = 0.5f * ((0.5f / sqrt(1 + alpha2Tan2Theta)) * d_alpha2Tan2Theta_d_w);
  448. }
  449.  
  450. DEVICE
  451. inline
  452. Real FrDielectric(Real cosThetaI, Real etaI, Real etaT) {
  453. cosThetaI = Clamp(cosThetaI, -1, 1);
  454. // Potentially swap indices of refraction
  455. bool entering = cosThetaI > 0.f;
  456. if (!entering) {
  457. Real temp = etaT;
  458. etaT = etaI;
  459. etaI = temp;
  460. cosThetaI = fabs(cosThetaI);
  461. }
  462.  
  463. // Compute _cosThetaT_ using Snell's law
  464. Real sinThetaI = sqrt(max(Real(0), 1 - cosThetaI * cosThetaI));
  465. Real sinThetaT = etaI / etaT * sinThetaI;
  466.  
  467. // Handle total internal reflection
  468. if (sinThetaT >= 1) return 1;
  469. Real cosThetaT = sqrt(max(Real(0), 1 - sinThetaT * sinThetaT));
  470. Real Rparl = ((etaT * cosThetaI) - (etaI * cosThetaT)) /
  471. ((etaT * cosThetaI) + (etaI * cosThetaT));
  472. Real Rperp = ((etaI * cosThetaI) - (etaT * cosThetaT)) /
  473. ((etaI * cosThetaI) + (etaT * cosThetaT));
  474. return (Rparl * Rparl + Rperp * Rperp) / 2;
  475. }
  476.  
  477. DEVICE
  478. inline
  479. void d_FrDielectric(Real cosThetaI, Real etaI, Real etaT, Vector3 &d_FrDielectric_d_cosThetaI) {
  480. cosThetaI = Clamp(cosThetaI, -1, 1);
  481. // Potentially swap indices of refraction
  482. bool entering = cosThetaI > 0.f;
  483. if (!entering) {
  484. Real temp = etaT;
  485. etaT = etaI;
  486. etaI = temp;
  487. cosThetaI = fabs(cosThetaI);
  488. }
  489.  
  490. /* Derivative of absolute value of cosThetaI w.r.t. cosThetaI. */
  491. d_absCosThetaI_d_cosThetaI = (entering) ? 1 : -1;
  492.  
  493. // Compute _cosThetaT_ using Snell's law
  494. Real sinThetaI = sqrt(max(Real(0), 1 - cosThetaI * cosThetaI));
  495. /* Derivative of sinThetaI w.r.t. cosThetaI. */
  496. Real d_sinThetaI_d_cosThetaI = (0.5 / max(Real(0), 1 - cosThetaI * cosThetaI))
  497. * -2 * cosThetaI * d_absCosThetaI_d_cosThetaI;
  498.  
  499. Real sinThetaT = etaI / etaT * sinThetaI;
  500. /* Derivative of sinThetaT w.r.t. cosThetaI. */
  501. Real d_sinThetaT_d_cosThetaI = (etaI / etaT) * d_sinThetaI_d_cosThetaI;
  502.  
  503. // Handle total internal reflection
  504. if (sinThetaT >= 1) {
  505. d_FrDielectric_d_cosThetaI = Vector3(0, 0, 0);
  506. return;
  507. }
  508.  
  509. Real cosThetaT = sqrt(max(Real(0), 1 - sinThetaT * sinThetaT));
  510. /* Derivative of cosThetaT w.r.t. cosThetaI. */
  511. Real d_cosThetaT_d_cosThetaI = (0.5 / max(Real(0), 1 - sinThetaT * sinThetaT))
  512. * -2 * sinThetaT * d_sinThetaT_d_cosThetaI;
  513.  
  514. Real Rparl = ((etaT * cosThetaI) - (etaI * cosThetaT)) /
  515. ((etaT * cosThetaI) + (etaI * cosThetaT));
  516. /* Derivative of Rparl w.r.t. cosThetaI. */
  517. Real d_Rparl_d_cosThetaI = ((etaT - etaI * d_cosThetaT_d_cosThetaI) / ((etaT * cosThetaI) + (etaI * cosThetaT)))
  518. + ((etaT * cosThetaI) - (etaI * cosThetaT))
  519. * -1 * pow((etaT * cosThetaI) + (etaI * cosThetaT), -2) * (etaT + etaI * d_cosThetaT_d_cosThetaI);
  520.  
  521. Real Rperp = ((etaI * cosThetaI) - (etaT * cosThetaT)) /
  522. ((etaI * cosThetaI) + (etaT * cosThetaT));
  523. /* Derivative of Rperp w.r.t. cosThetaI. */
  524. Real d_Rperp_d_cosThetaI = ((etaI - etaT * d_cosThetaT_d_cosThetaI) / ((etaI * cosThetaI) + (etaT * cosThetaT)))
  525. + ((etaI * cosThetaI) - (etaT * cosThetaT))
  526. * -1 * pow((etaI * cosThetaI) + (etaT * cosThetaT), -2) * (etaI + etaT * d_cosThetaT_d_cosThetaI);
  527.  
  528. /* Derivative of output w.r.t. cosThetaI. */
  529. /* return (Rparl * Rparl + Rperp * Rperp) / 2 */
  530. d_FrDielectric_d_cosThetaI = Rparl * d_Rparl_d_cosThetaI + Rperp * d_Rperp_d_cosThetaI;
  531. }
  532.  
  533. DEVICE
  534. inline
  535. Vector3 schlick(Vector3 specular_reflectance, Real cos_theta_d) {
  536. return specular_reflectance * FrDielectric(cos_theta_d, etaA, etaB);
  537. }
  538.  
  539. DEVICE
  540. inline
  541. void d_schlick(Real cos_theta_d, Vector3 &d_schlick_d_cos_theta_d) {
  542. d_FrDielectric(cos_theta_d, etaA, etaB, d_schlick_d_cos_theta_d);
  543. }
  544.  
  545. // Trowbridge Distribution
  546. DEVICE
  547. inline
  548. Real D(Real roughness, const Vector3 &wh) {
  549. Real alphax = RoughnessToAlpha(roughness);
  550. Real alphay = alphax;
  551.  
  552. Real tan2Theta = Tan2Theta(wh);
  553. if (std::isinf(tan2Theta)) return 0.;
  554. const Real cos4Theta = Cos2Theta(wh) * Cos2Theta(wh);
  555. Real e =
  556. (Cos2Phi(wh) / (alphax * alphax) + Sin2Phi(wh) / (alphay * alphay)) *
  557. tan2Theta;
  558. return 1.0 / (M_PI * alphax * alphay * cos4Theta * (1 + e) * (1 + e));
  559. }
  560.  
  561. DEVICE
  562. inline
  563. void d_D(Real roughness, const Vector3 &wh, Real &d_D_d_roughness, Vector3 &d_D_d_wh) {
  564. Real alphax = RoughnessToAlpha(roughness);
  565. Real alphay = alphax;
  566.  
  567. /* Derivatives of anisotropic alphas w.r.t. roughness. */
  568. Real d_alphax_d_roughness = d_RoughnessToAlpha(roughness);
  569. Real d_alphay_d_roughness = d_alphax_d_roughness;
  570.  
  571. Real tan2Theta = Tan2Theta(wh);
  572.  
  573. /* Derivative of tan2Theta w.r.t. wh. */
  574. Real d_Tan2Theta_d_wh = d_Tan2Theta(wh);
  575.  
  576. if (std::isinf(tan2Theta)) return 0.;
  577.  
  578. const Real cos4Theta = Cos2Theta(wh) * Cos2Theta(wh);
  579. Real d_cos4Theta_d_wh = -4 * SinTheta(wh) * CosTheta(wh) * CosTheta(wh) * CosTheta(wh);
  580.  
  581. Real e = (Cos2Phi(wh) / (alphax * alphax) + Sin2Phi(wh) / (alphay * alphay)) * tan2Theta;
  582.  
  583. /* Derivative of e w.r.t. roughness. */
  584. Real d_e_d_roughness = -2 * (Cos2Phi(wh) / (alphax * alphax * alphax) + Sin2Phi(wh) / (alphay * alphay * alphay)) * tan2Theta;
  585.  
  586. /* Derivative of e w.r.t. wh. */
  587. Real d_e_d_wh = (d_Cos2Phi(wh) / (alphax * alphax) + d_Sin2Phi(wh) / (alphay * alphay)) * tan2Theta +
  588. (Cos2Phi(wh) / (alphax * alphax) + Sin2Phi(wh) / (alphay * alphay)) * d_Tan2Theta_d_wh;
  589.  
  590.  
  591. /* return 1.0 / (M_PI * alphax * alphay * cos4Theta * (1 + e) * (1 + e)); */
  592. Real denom = (M_PI * alphax * alphay * cos4Theta * (1 + e) * (1 + e));
  593. Real d_D_d_denom = -1.f / (denom * denom);
  594.  
  595. d_D_d_roughness = d_D_d_denom * (M_PI * cos4Theta
  596. * (
  597. d_alphax_d_roughness * alphay * ((1 + e) * (1 + e))
  598. + alphax * d_alphay_d_roughness * ((1 + e) * (1 + e))
  599. + alphax * alphay * (2 * (1 + e))
  600. ));
  601.  
  602. d_D_d_wh = d_D_d_denom * (M_PI * alphax * alphay
  603. * (
  604. d_cos4Theta_d_wh * ((1 + e) * (1 + e))
  605. + cos4Theta * (2 * (1 + e))
  606. ));
  607. }
  608.  
  609.  
  610. DEVICE
  611. inline
  612. Real G(const Vector3 &wo, const Vector3 &wi, Real roughness) {
  613. return 1.0 / (1.0 + Lambda(wo, roughness) + Lambda(wi, roughness));
  614. }
  615.  
  616. DEVICE
  617. inline
  618. void d_G(const Vector3 &wo, const Vector3 &wi, Real roughness, Vector3 &d_G_d_wo, Vector3 &d_G_d_wi, Real &d_G_d_roughness) {
  619. /* return 1.0 / (1.0 + Lambda(wo, roughness) + Lambda(wi, roughness)); */
  620.  
  621. /* Derivative of lambda w.r.t wo. */
  622. Vector3 d_Lambda_d_wo;
  623.  
  624. /* Derivative of lambda w.r.t roughness given wo. */
  625. Real d_Lambda_d_roughness_wo;
  626.  
  627. d_Lambda(wo, roughness, d_Lambda_d_wo, d_Lambda_d_roughness_wo);
  628.  
  629. /* Derivative of lambda w.r.t wi. */
  630. Vector3 d_Lambda_d_wi;
  631.  
  632. /* Derivative of lambda w.r.t roughness given wi. */
  633. Real d_Lambda_d_roughness_wi;
  634.  
  635. d_Lambda(wi, roughness, d_Lambda_d_wi, d_Lambda_d_roughness_wi);
  636.  
  637. auto denom = (1.0 + Lambda(wo, roughness) + Lambda(wi, roughness));
  638. auto d_G_d_denom = -1.f / (denom * denom);
  639.  
  640. /* Derivative of G w.r.t wo. */
  641. d_G_d_wo = d_G_d_denom * d_Lambda_d_wo;
  642. /* Derivative of G w.r.t wi. */
  643. d_G_d_wi = d_G_d_denom * d_Lambda_d_wi;
  644.  
  645. /* Derivative of G w.r.t roughness. */
  646. d_G_d_roughness = d_G_d_denom * (d_Lambda_d_roughness_wo + d_Lambda_d_roughness_wi);
  647. }
  648.  
  649. DEVICE
  650. inline bool SameHemisphere(const Vector3 &w, const Vector3 &wp) {
  651. return w.z * wp.z > 0;
  652. }
  653.  
  654. DEVICE
  655. inline Real G1(const Vector3 &w, Real roughness) {
  656. // if (Dot(w, wh) * CosTheta(w) < 0.) return 0.;
  657. return 1 / (1 + Lambda(w, roughness));
  658. }
  659.  
  660. DEVICE
  661. inline void d_G1(const Vector3 &w, Real roughness, Vector3 &d_G1_d_w, Real &d_G1_d_roughness) {
  662. // if (Dot(w, wh) * CosTheta(w) < 0.) return 0.;
  663. /* return 1 / (1 + Lambda(w, roughness)); */
  664.  
  665. /* Derivative of Lambda w.r.t. w. */
  666. Vector3 d_Lambda_d_w;
  667.  
  668. /* Derivative of Lambda w.r.t. roughness. */
  669. Real d_Lambda_d_roughness;
  670.  
  671. d_Lambda(w, roughness, d_Lambda_d_w, d_Lambda_d_roughness);
  672.  
  673. auto denom = (1.0 + Lambda(w, roughness));
  674. auto d_G_d_denom = -1.f / (denom * denom);
  675.  
  676. /* Derivative of G1 w.r.t. w. */
  677. d_G1_d_w = d_G_d_denom * d_Lambda_d_w;
  678.  
  679. /* Derivative of G1 w.r.t. roughness. */
  680. d_G_d_roughness = d_G_d_denom * d_Lambda_d_roughness;
  681. }
  682.  
  683. DEVICE
  684. inline Real Pdf(Real roughness, const Vector3 &wo, const Vector3 &wh) {
  685. if (sampleVisibleArea)
  686. return D(roughness, wh) * G1(wo, roughness) * fabs(dot(wo, wh)) / fabs(CosTheta(wo));
  687. else
  688. return D(roughness, wh) * fabs(CosTheta(wh));
  689. }
  690.  
  691. DEVICE
  692. inline void d_Pdf(Real roughness, const Vector3 &wo, const Vector3 &wh, Real &d_Pdf_d_roughness, Vector3 &d_Pdf_d_wo, Vector3 &d_Pdf_d_wh) {
  693. if (sampleVisibleArea) {
  694. /* return D(roughness, wh) * G1(wo, roughness) * fabs(dot(wo, wh)) / fabs(CosTheta(wo)); */
  695.  
  696. Real d_D_d_roughness;
  697. Vector3 d_D_d_wh;
  698. d_D(roughness, wh, d_D_d_roughness, d_D_d_wh);
  699.  
  700. Vector3 d_G1_d_wo;
  701. Real d_G1_d_roughness;
  702. d_G1(wo, roughness, d_G1_d_wo, d_G1_d_roughness);
  703.  
  704. /* Derivative of PDF w.r.t. roughness. */
  705. d_Pdf_d_roughness = fabs(dot(wo, wh)) / fabs(CosTheta(wo)) * ( d_D_d_roughness * G1(wo, roughness) + d_G1_d_wo * D(roughness, wh));
  706.  
  707. /* Derivative of PDF w.r.t. wh. */
  708. d_Pdf_d_wh = (G1(wo, roughness) / fabs(CosTheta(wo))) * (d_D_d_wh * fabs(dot(wo, wh)) + ((dot(wo, wh) < 0) ? -1 : 1) * (wo) * D(roughness, wh));
  709.  
  710. /* Derivative of PDF w.r.t. wo */
  711. d_Pdf_d_wo = D(roughness, wh) * (
  712. ((dot(wo, wh) < 0) ? -1 : 1) * wh * G1(wo, roughness) / fabs(CosTheta(wo)) +
  713. fabs(dot(wo, wh)) * d_G1_d_wo / fabs(CosTheta(wo)) +
  714. G1(wo, roughness) * fabs(dot(wo, wh)) * ((CosTheta(wo) < 0) ? -1 : 1) * (-1 / Cos2Theta(wo))
  715. );
  716.  
  717. }
  718. else {
  719. /* return D(roughness, wh) * fabs(CosTheta(wh)); */
  720.  
  721. }
  722. }
  723.  
  724. DEVICE
  725. inline bool Refract(const Vector3 &wi, const Vector3 &n, Real eta, Vector3 &wt) {
  726. // Compute $\cos \theta_\roman{t}$ using Snell's law
  727. Real cosThetaI = dot(n, wi);
  728. Real sin2ThetaI = max(Real(0), Real(1 - cosThetaI * cosThetaI));
  729. Real sin2ThetaT = eta * eta * sin2ThetaI;
  730.  
  731. // Handle total internal reflection for transmission
  732. if (sin2ThetaT >= 1) return false;
  733. Real cosThetaT = sqrt(1 - sin2ThetaT);
  734. wt = eta * -wi + (eta * cosThetaI - cosThetaT) * n;
  735. return true;
  736. }
  737.  
  738. DEVICE
  739. inline void TrowbridgeReitzSample11(Real cosTheta, Real U1, Real U2,
  740. Real &slope_x, Real &slope_y) {
  741. // special case (normal incidence)
  742. if (cosTheta > .9999) {
  743. Real r = sqrt(U1 / (1 - U1));
  744. Real phi = 6.28318530718 * U2;
  745. slope_x = r * cos(phi);
  746. slope_y = r * sin(phi);
  747. return;
  748. }
  749.  
  750. Real sinTheta = sqrt(max(Real(0), Real(1) - cosTheta * cosTheta));
  751. Real tanTheta = sinTheta / cosTheta;
  752. Real a = 1 / tanTheta;
  753. Real G1 = 2 / (1 + sqrt(1.f + 1.f / (a * a)));
  754.  
  755. // sample slope_x
  756. Real A = 2 * U1 / G1 - 1;
  757. Real tmp = 1.f / (A * A - 1.f);
  758. if (tmp > 1e10) tmp = 1e10;
  759. Real B = tanTheta;
  760. Real D = sqrt(max(Real(B * B * tmp * tmp - (A * A - B * B) * tmp), Real(0)));
  761. Real slope_x_1 = B * tmp - D;
  762. Real slope_x_2 = B * tmp + D;
  763. slope_x = (A < 0 || slope_x_2 > 1.f / tanTheta) ? slope_x_1 : slope_x_2;
  764.  
  765. // sample slope_y
  766. Real S;
  767. if (U2 > 0.5f) {
  768. S = 1.f;
  769. U2 = 2.f * (U2 - .5f);
  770. } else {
  771. S = -1.f;
  772. U2 = 2.f * (.5f - U2);
  773. }
  774. Real z =
  775. (U2 * (U2 * (U2 * 0.27385f - 0.73369f) + 0.46341f)) /
  776. (U2 * (U2 * (U2 * 0.093073f + 0.309420f) - 1.000000f) + 0.597999f);
  777. slope_y = S * z * sqrt(1.f + slope_x * slope_x);
  778. }
  779.  
  780. DEVICE
  781. inline Vector3 TrowbridgeReitzSample(const Vector3 &wi, Real alpha_x,
  782. Real alpha_y, Real U1, Real U2) {
  783. // 1. stretch wi
  784. Vector3 wiStretched = normalize(Vector3(alpha_x * wi.x, alpha_y * wi.y, wi.z));
  785.  
  786. // 2. simulate P22_{wi}(x_slope, y_slope, 1, 1)
  787. Real slope_x, slope_y;
  788. TrowbridgeReitzSample11(CosTheta(wiStretched), U1, U2, slope_x, slope_y);
  789.  
  790. // 3. rotate
  791. Real tmp = CosPhi(wiStretched) * slope_x - SinPhi(wiStretched) * slope_y;
  792. slope_y = SinPhi(wiStretched) * slope_x + CosPhi(wiStretched) * slope_y;
  793. slope_x = tmp;
  794.  
  795. // 4. unstretch
  796. slope_x = alpha_x * slope_x;
  797. slope_y = alpha_y * slope_y;
  798.  
  799. // 5. compute normal
  800. return normalize(Vector3(-slope_x, -slope_y, 1.));
  801. }
  802.  
  803. DEVICE
  804. inline Vector3 SphericalDirection(Real sinTheta, Real cosTheta, Real phi) {
  805. return Vector3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
  806. }
  807.  
  808. DEVICE
  809. inline Vector3 Sample_wh(const Vector3 &wo, const Vector2 &uv, Real roughness) {
  810. Real alphax = RoughnessToAlpha(roughness);
  811. Real alphay = alphax;
  812.  
  813. Vector3 wh;
  814. if (!sampleVisibleArea) {
  815. Real cosTheta = 0, phi = (2 * M_PI) * uv[1];
  816. if (alphax == alphay) {
  817. Real tanTheta2 = alphax * alphax * uv[0] / (1.0f - uv[0]);
  818. cosTheta = 1 / sqrt(1 + tanTheta2);
  819. } else {
  820. phi = atan(alphay / alphax * tan(2 * M_PI * uv[1] + .5f * M_PI));
  821. if (uv[1] > .5f) phi += M_PI;
  822. Real sinPhi = sin(phi), cosPhi = cos(phi);
  823. const Real alphax2 = alphax * alphax, alphay2 = alphay * alphay;
  824. const Real alpha2 = 1 / (cosPhi * cosPhi / alphax2 + sinPhi * sinPhi / alphay2);
  825. Real tanTheta2 = alpha2 * uv[0] / (1 - uv[0]);
  826. cosTheta = 1 / sqrt(1 + tanTheta2);
  827. }
  828. Real sinTheta = sqrt(max((Real)0., (Real)1. - cosTheta * cosTheta));
  829. wh = SphericalDirection(sinTheta, cosTheta, phi);
  830. if (!SameHemisphere(wo, wh)) wh = -wh;
  831. } else {
  832. bool flip = wo.z < 0;
  833. wh = TrowbridgeReitzSample(flip ? -wo : wo, alphax, alphay, uv[0], uv[1]);
  834. if (flip) wh = -wh;
  835. }
  836. return wh;
  837. }
  838.  
  839.  
  840.  
  841.  
  842. DEVICE
  843. inline
  844. Vector3 bsdf(const Material &material,
  845. const SurfacePoint &shading_point,
  846. Vector3 wi,
  847. Vector3 wo,
  848. const Real min_roughness) {
  849.  
  850. auto shading_frame = shading_point.shading_frame;
  851. if (has_normal_map(material)) {
  852. // Perturb shading frame
  853. shading_frame = perturb_shading_frame(material, shading_point);
  854. }
  855.  
  856. auto n = normalize(to_local(shading_frame, shading_frame.n));
  857. wi = normalize(to_local(shading_frame, wi));
  858. wo = normalize(to_local(shading_frame, wo));
  859.  
  860. auto cosThetaO = dot(wo, n);
  861. auto cosThetaI = dot(wi, n);
  862.  
  863. if (fabs(cosThetaO) < 1e-3f || fabs(cosThetaI) < 1e-3f) {
  864. return {0, 0, 0};
  865. }
  866. Real eta = CosTheta(wo) > 0 ? (etaB / etaA) : (etaA / etaB);
  867.  
  868.  
  869. auto wh = normalize(wo + wi * eta);
  870. if (wh.z < 0) {
  871. wh = -wh;
  872. }
  873.  
  874. auto specular_reflectance = get_specular_reflectance(material, shading_point);
  875. auto F = schlick(specular_reflectance, dot(wo, wh));
  876.  
  877. auto sqrtDenom = fabs(dot(wo, wh)) + eta * fabs(dot(wi, wh));
  878.  
  879. auto roughness = max(get_roughness(material, shading_point), min_roughness);
  880.  
  881.  
  882. cosThetaI = fabs(cosThetaI);
  883. cosThetaO = fabs(cosThetaO);
  884.  
  885. auto res = (Vector3(1, 1, 1) - F) * fabs(D(roughness, wh) * G(wo, wi, roughness) * eta * eta * fabs(dot(wi, wh)) * fabs(dot(wo, wh))) /
  886. (cosThetaI * cosThetaO * sqrtDenom * sqrtDenom);
  887.  
  888.  
  889. return res;
  890. }
  891.  
  892. DEVICE
  893. inline
  894. void d_bsdf(const Material &material,
  895. const SurfacePoint &shading_point,
  896. const Vector3 &wi,
  897. const Vector3 &wo,
  898. const Real min_roughness,
  899. const Vector3 &d_output,
  900. DMaterial &d_material,
  901. SurfacePoint &d_shading_point,
  902. Vector3 &d_wi,
  903. Vector3 &d_wo) {
  904.  
  905. auto shading_frame = shading_point.shading_frame;
  906. if (has_normal_map(material)) {
  907. // Perturb shading frame
  908. shading_frame = perturb_shading_frame(material, shading_point);
  909. }
  910.  
  911. /* Derivatives of tangent space representations of n, wi, and wo w.r.t. their
  912. * world space representations. */
  913. auto d_n_local_d_n = d_normalize(to_local(shading_frame, shading_frame.n)) * d_to_local(shading_frame, shading_frame.n);
  914. auto d_wi_local_d_wi = d_normalize(to_local(shading_frame, wi)) * d_to_local(shading_frame, wi);
  915. auto d_wo_local_d_wo = d_normalize(to_local(shading_frame, wo)) * d_to_local(shading_frame, wo);
  916.  
  917. auto n_local = normalize(to_local(shading_frame, shading_frame.n));
  918. wi_local = normalize(to_local(shading_frame, wi));
  919. wo_local = normalize(to_local(shading_frame, wo));
  920.  
  921.  
  922.  
  923. auto cosThetaO = dot(wo_local, n);
  924. auto cosThetaI = dot(wi_local, n);
  925.  
  926. if (fabs(cosThetaO) < 1e-3f || fabs(cosThetaI) < 1e-3f) {
  927. return;
  928. }
  929.  
  930. Real eta = CosTheta(wo_local) > 0 ? (etaB / etaA) : (etaA / etaB);
  931.  
  932. auto wh_local = normalize(wo_local + wi_local * eta);
  933.  
  934. /* Derivative of wh w.r.t. wo. */
  935. d_wh_d_wo = d_normalize(wo_local + wi_local * eta) * d_wo_local_d_wo;
  936. /* Derivative of wh w.r.t. wi. */
  937. d_wh_d_wi = d_normalize(wo_local + wi_local * eta) * eta * d_wi_local_d_wi;
  938.  
  939. if (wh_local.z < 0) {
  940. wh_local = -wh_local;
  941.  
  942. /* diFfeREnTIaTioN iS liNEAr */
  943. d_wh_d_wo = -d_wh_d_wo;
  944. d_wh_d_wi = -d_wh_d_wi;
  945. }
  946.  
  947. /* Get specular reflectance from reflectance map. */
  948. auto specular_reflectance = get_specular_reflectance(material, shading_point);
  949.  
  950. /* Derivatives of specular reflectance will be 1, since we assume uniform specular
  951. * reflectance. */
  952.  
  953. Real wo_local_dot_wh_local = dot(wo_local, wh_local);
  954. auto F = schlick(specular_reflectance, wo_local_dot_wh_local);
  955.  
  956. /* Derivative of F w.r.t. dot(wo_local, wh_local). */
  957. Vector3 d_F_d_wo_local_dot_wh_local;
  958. d_schlick(specular_reflectance, wo_local_dot_wh_local, d_F_d_wo_local_dot_wh_local);
  959.  
  960. /* Derivative of dot(wo_local, wh_local) w.r.t wo */
  961. Vector3 d_wo_local_dot_wh_local_d_wo = wh + wo * d_wh_d_wo;
  962.  
  963. /* Derivative of F w.r.t. wo. */
  964. Vector3 d_F_d_wo = d_F_d_wo_local_dot_wh_local * d_wo_local_dot_wh_local_d_wo;
  965.  
  966. /* Derivative of F w.r.t. wi. */
  967. Vector3 d_F_d_wi = wh * d_wh_d_wi * d_F_d_wo_local_dot_wh_local;
  968.  
  969. auto sqrtDenom = fabs(dot(wo_local, wh_local)) + eta * fabs(dot(wi_local, wh_local));
  970.  
  971.  
  972. /* Derivative of sqrtDenom w.r.t. wo. */
  973. Vector3 d_sqrtDenom_d_wo = ((dot(wo_local, wh_local) > 0) ? 1 : -1) * d_wo_local_dot_wh_local_d_wo + eta * ((dot(wi_local, wh_local) > 0) ? 1 : -1) * ;
  974.  
  975. auto roughness = max(get_roughness(material, shading_point), min_roughness);
  976.  
  977.  
  978. cosThetaI = fabs(cosThetaI);
  979. cosThetaO = fabs(cosThetaO);
  980.  
  981. auto res = (Vector3(1, 1, 1) - F) * fabs(D(roughness, wh_local) * G(wo_local, wi, roughness) * eta * eta * fabs(dot(wi_local, wh_local)) * fabs(dot(wo_local, wh_local))) /
  982. (cosThetaI * cosThetaO * sqrtDenom * sqrtDenom);
  983.  
  984.  
  985. return res;
  986. }
  987.  
  988. DEVICE
  989. inline
  990. Vector3 bsdf_sample(const Material &material,
  991. const SurfacePoint &shading_point,
  992. Vector3 wi,
  993. const BSDFSample &bsdf_sample,
  994. const Real min_roughness,
  995. const RayDifferential &wi_differential,
  996. RayDifferential &wo_differential,
  997. Real *next_min_roughness = nullptr) {
  998.  
  999. auto shading_frame = shading_point.shading_frame;
  1000.  
  1001.  
  1002. if (has_normal_map(material)) {
  1003. // Perturb shading frame
  1004. shading_frame = perturb_shading_frame(material, shading_point);
  1005. }
  1006.  
  1007. auto n_local = Vector3{0, 0, 1};
  1008. auto n = to_world(shading_frame, n_local);
  1009.  
  1010. // metal/glass:
  1011. auto refl = 2.f * dot(wi, n) * n - wi;
  1012.  
  1013.  
  1014. wi = normalize(to_local(shading_frame, normalize(wi)));
  1015. if (wi.z == 0) return {0, 0, 0};
  1016.  
  1017. auto roughness = max(get_roughness(material, shading_point), min_roughness);
  1018. Vector3 wh = Sample_wh(wi, bsdf_sample.uv, roughness);
  1019. auto eta = CosTheta(wi) > 0 ? (etaA / etaB) : (etaB / etaA);
  1020.  
  1021. Vector3 wo;
  1022. if (!Refract(wi, wh, eta, wo)) {
  1023. return refl;
  1024. }
  1025.  
  1026. wo = normalize(to_world(shading_frame, wo));
  1027. return wo;
  1028.  
  1029.  
  1030.  
  1031.  
  1032.  
  1033. /*
  1034.  
  1035. // Propagate ray differentials
  1036. // HACK: we approximate the directional derivative dn_dx using dn_dx * n_local[2]
  1037. // i.e. we ignore the derivatives on the tangent plane
  1038. auto dn_dx = shading_point.dn_dx * n_local[2];
  1039. auto dn_dy = shading_point.dn_dy * n_local[2];
  1040. auto wi_dx = -wi_differential.dir_dx;
  1041. auto wi_dy = -wi_differential.dir_dy;
  1042.  
  1043. // Igehy 1999, Equation 15
  1044. auto widotn_dx = sum(wi_dx * n) + sum(wi * dn_dx);
  1045. auto widotn_dy = sum(wi_dy * n) + sum(wi * dn_dy);
  1046.  
  1047. if (radicand < 0) {
  1048. // Reflection
  1049.  
  1050. // Igehy 1999, Equation 14
  1051. wo_differential.org_dx = wi_differential.org_dx;
  1052. wo_differential.org_dy = wi_differential.org_dy;
  1053. wo_differential.dir_dx = 2 * (dot(wi, n) * dn_dx + widotn_dx * n) - wi_dx;
  1054. wo_differential.dir_dy = 2 * (dot(wi, n) * dn_dy + widotn_dy * n) - wi_dy;
  1055.  
  1056.  
  1057. //return refl;
  1058. }
  1059. else {
  1060.  
  1061.  
  1062. if (bsdf_sample.uv[0] < Rtheta) {
  1063. // Reflection
  1064.  
  1065. // Igehy 1999, Equation 14
  1066. wo_differential.org_dx = wi_differential.org_dx;
  1067. wo_differential.org_dy = wi_differential.org_dy;
  1068. wo_differential.dir_dx = 2 * (dot(wi, n) * dn_dx + widotn_dx * n) - wi_dx;
  1069. wo_differential.dir_dy = 2 * (dot(wi, n) * dn_dy + widotn_dy * n) - wi_dy;
  1070.  
  1071. return refl;
  1072. }
  1073.  
  1074. // Refraction
  1075.  
  1076. auto T = refr;
  1077. auto D = -wi;
  1078. auto N = n_oriented;
  1079.  
  1080. // Igehy 1999, Equation 17
  1081. auto mu = eta*dot(D,N) - dot(T,N);
  1082. auto TN = -sqrtf(1-eta*eta*(1-dot(D,N)*dot(D,N)));
  1083.  
  1084. // Igehy 1999, Equation 19
  1085. auto dmu_dx = (eta - (eta*eta*dot(D,N))/TN)*widotn_dx;
  1086. auto dmu_dy = (eta - (eta*eta*dot(D,N))/TN)*widotn_dy;
  1087.  
  1088.  
  1089. // Igehy 1999, Equation 18
  1090. wo_differential.org_dx = wi_differential.org_dx;
  1091. wo_differential.org_dy = wi_differential.org_dy;
  1092. wo_differential.dir_dx = eta * wi_dx - (mu * dn_dx + dmu_dx * N);
  1093. wo_differential.dir_dy = eta * wi_dy - (mu * dn_dy + dmu_dy * N);
  1094. }
  1095. return Vector3 {0, 0, 0};
  1096.  
  1097. */
  1098. }
  1099.  
  1100. DEVICE
  1101. inline
  1102. void d_bsdf_sample(const Material &material,
  1103. const SurfacePoint &shading_point,
  1104. Vector3 wi,
  1105. const BSDFSample &bsdf_sample,
  1106. const Real min_roughness,
  1107. const RayDifferential &wi_differential,
  1108. const Vector3 &d_wo,
  1109. const RayDifferential &d_wo_differential,
  1110. DMaterial &d_material,
  1111. SurfacePoint &d_shading_point,
  1112. Vector3 &d_wi,
  1113. RayDifferential &d_wi_differential) {
  1114. auto shading_frame = shading_point.shading_frame;
  1115. if (has_normal_map(material)) {
  1116. // Perturb shading frame
  1117. shading_frame = perturb_shading_frame(material, shading_point);
  1118. }
  1119.  
  1120. bool inward = false;
  1121. auto geom_wi = dot(shading_point.geom_normal, wi);
  1122. auto n_local = Vector3{0, 0, 1};
  1123. auto n = to_world(shading_frame, n_local);
  1124.  
  1125. if (material.two_sided && geom_wi < 0.f) {
  1126. shading_frame = -shading_frame;
  1127. geom_wi = -geom_wi;
  1128. inward = true;
  1129. }
  1130. if (geom_wi <= 0.f) {
  1131. return;
  1132. }
  1133.  
  1134.  
  1135. // local normal
  1136. //auto n_local = to_local(shading_frame, n);
  1137.  
  1138. auto d_shading_frame = Frame{ Vector3{0, 0, 0},
  1139. Vector3{0, 0, 0},
  1140. Vector3{0, 0, 0} };
  1141.  
  1142.  
  1143. // Propagate ray differentials
  1144. // HACK: we approximate the directional derivative dmdx using dndx * n_local[2]
  1145. // i.e. we ignore the derivatives on the tangent plane
  1146. auto dn_dx = shading_point.dn_dx * n_local[2];
  1147. auto dn_dy = shading_point.dn_dy * n_local[2];
  1148. auto wi_dx = -wi_differential.dir_dx;
  1149. auto wi_dy = -wi_differential.dir_dy;
  1150.  
  1151. // Igehy 1999, Equation 15
  1152. auto widotn_dx = sum(wi_dx * n) + sum(wi * dn_dx);
  1153. auto widotn_dy = sum(wi_dy * n) + sum(wi * dn_dy);
  1154.  
  1155.  
  1156. d_wi_differential.org_dx += d_wo_differential.org_dx;
  1157. d_wi_differential.org_dy += d_wo_differential.org_dy;
  1158. d_wi_differential.dir_dx += d_wo_differential.dir_dx;
  1159. d_wi_differential.dir_dy += d_wo_differential.dir_dy;
  1160.  
  1161. auto d_dot_wi_n = 2 * sum(d_wo_differential.dir_dx * dn_dx) + 2 * sum(d_wo_differential.dir_dy * dn_dy);
  1162. auto d_dndx = d_wo_differential.dir_dx * 2 * dot(wi, n);
  1163. auto d_dndy = d_wo_differential.dir_dy * 2 * dot(wi, n);
  1164. auto d_widotn_dx = 2 * sum(d_wo_differential.dir_dx * n);
  1165. auto d_widotn_dy = 2 * sum(d_wo_differential.dir_dy * n);
  1166. auto d_n = d_wo_differential.dir_dx * 2 * widotn_dx + d_wo_differential.dir_dy * 2 * widotn_dy;
  1167.  
  1168. // widotm_dx = sum(wi_dx * n) + sum(wi * dn_dx)
  1169. auto d_wi_dx = d_widotn_dx * n;
  1170. d_n += d_widotn_dx * wi_dx;
  1171. d_wi += d_widotn_dx * dn_dx;
  1172. d_dndx += d_widotn_dx * wi;
  1173. // widotm_dy = sum(wi_dy * n) + sum(wi * dn_dy)
  1174. auto d_wi_dy = d_widotn_dy * n;
  1175. d_n += d_widotn_dy * wi_dy;
  1176. d_wi += d_widotn_dy * dn_dy;
  1177. d_dndy += d_widotn_dy * wi;
  1178.  
  1179. // wi_dx = -wi_differential.dir_dx
  1180. // wi_dy = -wi_differential.dir_dy
  1181. d_wi_differential.dir_dx -= d_wi_dx;
  1182. d_wi_differential.dir_dy -= d_wi_dy;
  1183. // dmdx = shading_point.dn_dx * n_local[2]
  1184. // dmdy = shading_point.dn_dy * n_local[2]
  1185. d_shading_point.dn_dx += d_dndx * n_local[2];
  1186. d_shading_point.dn_dy += d_dndy * n_local[2];
  1187. auto d_m_local = Vector3{ 0, 0, 0 };
  1188. d_m_local[2] += sum(d_dndx * shading_point.dn_dx) + sum(d_dndy * shading_point.dn_dy);
  1189.  
  1190. // wo = 2.f * dot(wi, m) * m - wi
  1191. d_dot_wi_n += 2.f * sum(d_wo * n);
  1192. d_n += d_wo * (2.f * dot(wi, n));
  1193. d_wi += -d_wo;
  1194. // dot_wi_m = dot(wi, m)
  1195. d_wi += d_dot_wi_n * n;
  1196. d_n += d_dot_wi_n * wi;
  1197.  
  1198. // m = to_world(shading_frame, m_local)
  1199. d_to_world(shading_frame, n_local, d_n, d_shading_frame, d_m_local);
  1200.  
  1201. if (inward) {
  1202. d_shading_frame = -d_shading_frame;
  1203. }
  1204.  
  1205. if (has_normal_map(material)) {
  1206. d_perturb_shading_frame(material,
  1207. shading_point,
  1208. d_shading_frame,
  1209. d_material,
  1210. d_shading_point);
  1211. }
  1212. else {
  1213. d_shading_point.shading_frame += d_shading_frame;
  1214. }
  1215. }
  1216.  
  1217. DEVICE
  1218. inline Real bsdf_pdf(const Material &material,
  1219. const SurfacePoint &shading_point,
  1220. Vector3 wi,
  1221. Vector3 wo,
  1222. const Real min_roughness) {
  1223.  
  1224. auto shading_frame = shading_point.shading_frame;
  1225. wi = normalize(to_local(shading_frame, wi));
  1226. wo = normalize(to_local(shading_frame, wo));
  1227.  
  1228. if (SameHemisphere(wo, wi)) return 0;
  1229. // Compute $\wh$ from $\wo$ and $\wi$ for microfacet transmission
  1230. auto eta = CosTheta(wo) > 0 ? (etaB / etaA) : (etaA / etaB);
  1231. auto wh = normalize(wo + wi * eta);
  1232.  
  1233. // Compute change of variables _dwh\_dwi_ for microfacet transmission
  1234. auto sqrtDenom = fabs(dot(wo, wh)) + eta * fabs(dot(wi, wh));
  1235. auto dwh_dwi = fabs((eta * eta * dot(wi, wh)) / (sqrtDenom * sqrtDenom));
  1236. auto roughness = max(get_roughness(material, shading_point), min_roughness);
  1237. auto pdf_val = Pdf(roughness, wo, wh) * dwh_dwi;
  1238.  
  1239. return pdf_val;
  1240. }
  1241.  
  1242. DEVICE
  1243. inline void d_bsdf_pdf(const Material &material,
  1244. const SurfacePoint &shading_point,
  1245. const Vector3 &wi,
  1246. const Vector3 &wo,
  1247. const Real min_roughness,
  1248. const Real d_pdf,
  1249. DMaterial &d_material,
  1250. SurfacePoint &d_shading_point,
  1251. Vector3 &d_wi,
  1252. Vector3 &d_wo) {
  1253.  
  1254.  
  1255.  
  1256. }
  1257.  
  1258. void test_d_bsdf();
  1259. void test_d_bsdf_sample();
  1260. void test_d_bsdf_pdf();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement