kernel_differential.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * Copyright 2011-2013 Blender Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. CCL_NAMESPACE_BEGIN
  17. /* See "Tracing Ray Differentials", Homan Igehy, 1999. */
  18. ccl_device void differential_transfer(ccl_addr_space differential3 *dP_,
  19. const differential3 dP,
  20. float3 D,
  21. const differential3 dD,
  22. float3 Ng,
  23. float t)
  24. {
  25. /* ray differential transfer through homogeneous medium, to
  26. * compute dPdx/dy at a shading point from the incoming ray */
  27. float3 tmp = D / dot(D, Ng);
  28. float3 tmpx = dP.dx + t * dD.dx;
  29. float3 tmpy = dP.dy + t * dD.dy;
  30. dP_->dx = tmpx - dot(tmpx, Ng) * tmp;
  31. dP_->dy = tmpy - dot(tmpy, Ng) * tmp;
  32. }
  33. ccl_device void differential_incoming(ccl_addr_space differential3 *dI, const differential3 dD)
  34. {
  35. /* compute dIdx/dy at a shading point, we just need to negate the
  36. * differential of the ray direction */
  37. dI->dx = -dD.dx;
  38. dI->dy = -dD.dy;
  39. }
  40. ccl_device void differential_dudv(ccl_addr_space differential *du,
  41. ccl_addr_space differential *dv,
  42. float3 dPdu,
  43. float3 dPdv,
  44. differential3 dP,
  45. float3 Ng)
  46. {
  47. /* now we have dPdx/dy from the ray differential transfer, and dPdu/dv
  48. * from the primitive, we can compute dudx/dy and dvdx/dy. these are
  49. * mainly used for differentials of arbitrary mesh attributes. */
  50. /* find most stable axis to project to 2D */
  51. float xn = fabsf(Ng.x);
  52. float yn = fabsf(Ng.y);
  53. float zn = fabsf(Ng.z);
  54. if (zn < xn || zn < yn) {
  55. if (yn < xn || yn < zn) {
  56. dPdu.x = dPdu.y;
  57. dPdv.x = dPdv.y;
  58. dP.dx.x = dP.dx.y;
  59. dP.dy.x = dP.dy.y;
  60. }
  61. dPdu.y = dPdu.z;
  62. dPdv.y = dPdv.z;
  63. dP.dx.y = dP.dx.z;
  64. dP.dy.y = dP.dy.z;
  65. }
  66. /* using Cramer's rule, we solve for dudx and dvdx in a 2x2 linear system,
  67. * and the same for dudy and dvdy. the denominator is the same for both
  68. * solutions, so we compute it only once.
  69. *
  70. * dP.dx = dPdu * dudx + dPdv * dvdx;
  71. * dP.dy = dPdu * dudy + dPdv * dvdy; */
  72. float det = (dPdu.x * dPdv.y - dPdv.x * dPdu.y);
  73. if (det != 0.0f)
  74. det = 1.0f / det;
  75. du->dx = (dP.dx.x * dPdv.y - dP.dx.y * dPdv.x) * det;
  76. dv->dx = (dP.dx.y * dPdu.x - dP.dx.x * dPdu.y) * det;
  77. du->dy = (dP.dy.x * dPdv.y - dP.dy.y * dPdv.x) * det;
  78. dv->dy = (dP.dy.y * dPdu.x - dP.dy.x * dPdu.y) * det;
  79. }
  80. ccl_device differential differential_zero()
  81. {
  82. differential d;
  83. d.dx = 0.0f;
  84. d.dy = 0.0f;
  85. return d;
  86. }
  87. ccl_device differential3 differential3_zero()
  88. {
  89. differential3 d;
  90. d.dx = make_float3(0.0f, 0.0f, 0.0f);
  91. d.dy = make_float3(0.0f, 0.0f, 0.0f);
  92. return d;
  93. }
  94. CCL_NAMESPACE_END