rect-area-light.chunk 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
  2. mat3 transposeMat3 (mat3 v) {
  3. mat3 tmp;
  4. tmp[0] = vec3(v[0].x, v[1].x, v[2].x);
  5. tmp[1] = vec3(v[0].y, v[1].y, v[2].y);
  6. tmp[2] = vec3(v[0].z, v[1].z, v[2].z);
  7. return tmp;
  8. }
  9. void ClipQuadToHorizon (inout vec3 L[5], out int n) {
  10. // detect clipping config
  11. int config = 0;
  12. if (L[0].z > 0.0) config += 1;
  13. if (L[1].z > 0.0) config += 2;
  14. if (L[2].z > 0.0) config += 4;
  15. if (L[3].z > 0.0) config += 8;
  16. config = 15;
  17. // clip
  18. n = 0;
  19. if (config == 0)
  20. {
  21. // clip all
  22. }
  23. else if (config == 1) { // V1 clip V2 V3 V4
  24. n = 3;
  25. L[1] = -L[1].z * L[0] + L[0].z * L[1];
  26. L[2] = -L[3].z * L[0] + L[0].z * L[3];
  27. }
  28. else if (config == 2) { // V2 clip V1 V3 V4
  29. n = 3;
  30. L[0] = -L[0].z * L[1] + L[1].z * L[0];
  31. L[2] = -L[2].z * L[1] + L[1].z * L[2];
  32. }
  33. else if (config == 3) { // V1 V2 clip V3 V4
  34. n = 4;
  35. L[2] = -L[2].z * L[1] + L[1].z * L[2];
  36. L[3] = -L[3].z * L[0] + L[0].z * L[3];
  37. }
  38. else if (config == 4) { // V3 clip V1 V2 V4
  39. n = 3;
  40. L[0] = -L[3].z * L[2] + L[2].z * L[3];
  41. L[1] = -L[1].z * L[2] + L[2].z * L[1];
  42. }
  43. else if (config == 5) { // V1 V3 clip V2 V4) impossible
  44. n = 0;
  45. }
  46. else if (config == 6) { // V2 V3 clip V1 V4
  47. n = 4;
  48. L[0] = -L[0].z * L[1] + L[1].z * L[0];
  49. L[3] = -L[3].z * L[2] + L[2].z * L[3];
  50. }
  51. else if (config == 7) { // V1 V2 V3 clip V4
  52. n = 5;
  53. L[4] = -L[3].z * L[0] + L[0].z * L[3];
  54. L[3] = -L[3].z * L[2] + L[2].z * L[3];
  55. }
  56. else if (config == 8) { // V4 clip V1 V2 V3
  57. n = 3;
  58. L[0] = -L[0].z * L[3] + L[3].z * L[0];
  59. L[1] = -L[2].z * L[3] + L[3].z * L[2];
  60. L[2] = L[3];
  61. }
  62. else if (config == 9) { // V1 V4 clip V2 V3
  63. n = 4;
  64. L[1] = -L[1].z * L[0] + L[0].z * L[1];
  65. L[2] = -L[2].z * L[3] + L[3].z * L[2];
  66. }
  67. else if (config == 10) { // V2 V4 clip V1 V3) impossible
  68. n = 0;
  69. }
  70. else if (config == 11) { // V1 V2 V4 clip V3
  71. n = 5;
  72. L[4] = L[3];
  73. L[3] = -L[2].z * L[3] + L[3].z * L[2];
  74. L[2] = -L[2].z * L[1] + L[1].z * L[2];
  75. }
  76. else if (config == 12) { // V3 V4 clip V1 V2
  77. n = 4;
  78. L[1] = -L[1].z * L[2] + L[2].z * L[1];
  79. L[0] = -L[0].z * L[3] + L[3].z * L[0];
  80. }
  81. else if (config == 13) { // V1 V3 V4 clip V2
  82. n = 5;
  83. L[4] = L[3];
  84. L[3] = L[2];
  85. L[2] = -L[1].z * L[2] + L[2].z * L[1];
  86. L[1] = -L[1].z * L[0] + L[0].z * L[1];
  87. }
  88. else if (config == 14) { // V2 V3 V4 clip V1
  89. n = 5;
  90. L[4] = -L[0].z * L[3] + L[3].z * L[0];
  91. L[0] = -L[0].z * L[1] + L[1].z * L[0];
  92. }
  93. else if (config == 15) { // V1 V2 V3 V4
  94. n = 4;
  95. }
  96. if (n == 3) L[3] = L[0];
  97. if (n == 4) L[4] = L[0];
  98. }
  99. // https://eheitzresearch.wordpress.com/415-2/
  100. float IntegrateEdge (vec3 v1, vec3 v2) {
  101. float cosTheta = dot(v1, v2);
  102. float theta = acos(cosTheta);
  103. return cross(v1, v2).z * ((theta > 0.001) ? theta/sin(theta) : 4.0);
  104. }
  105. // https://blog.magnum.graphics/guest-posts/area-lights-with-ltcs/
  106. vec3 LTC_Evaluate (vec3 N, vec3 V, vec3 P, mat3 Minv, vec3 points[4]) {
  107. // construct orthonormal basis around N
  108. vec3 T1, T2;
  109. T1 = normalize(V - N*dot(V, N));
  110. T2 = cross(N, T1);
  111. // rotate area light in (T1, T2, N) basis
  112. Minv = Minv * transposeMat3(mat3(T1, T2, N));
  113. // polygon (allocate 5 vertices for clipping)
  114. vec3 L[5];
  115. L[0] = Minv * (points[0] - P);
  116. L[1] = Minv * (points[1] - P);
  117. L[2] = Minv * (points[2] - P);
  118. L[3] = Minv * (points[3] - P);
  119. int n;
  120. ClipQuadToHorizon(L, n);
  121. if (n == 0) return vec3(0, 0, 0);
  122. // project onto sphere
  123. L[0] = normalize(L[0]);
  124. L[1] = normalize(L[1]);
  125. L[2] = normalize(L[2]);
  126. L[3] = normalize(L[3]);
  127. L[4] = normalize(L[4]);
  128. // integrate
  129. float sum = 0.0;
  130. sum += IntegrateEdge(L[0], L[1]);
  131. sum += IntegrateEdge(L[1], L[2]);
  132. sum += IntegrateEdge(L[2], L[3]);
  133. if (n >= 4) sum += IntegrateEdge(L[3], L[4]);
  134. if (n == 5) sum += IntegrateEdge(L[4], L[0]);
  135. sum = max(0.0, sum);
  136. vec3 Lo_i = vec3(sum, sum, sum);
  137. return Lo_i;
  138. }