ltc.glsl 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Linearly Transformed Cosines
  2. // https://eheitzresearch.wordpress.com/415-2/
  3. const float LUT_SIZE = 64.0;
  4. const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;
  5. const float LUT_BIAS = 0.5 / LUT_SIZE;
  6. vec3 L0;
  7. vec3 L1;
  8. vec3 L2;
  9. vec3 L3;
  10. vec3 L4;
  11. float integrateEdge(vec3 v1, vec3 v2) {
  12. float cosTheta = dot(v1, v2);
  13. float theta = acos(cosTheta);
  14. float res = cross(v1, v2).z * ((theta > 0.001) ? theta / sin(theta) : 1.0);
  15. return res;
  16. }
  17. int clipQuadToHorizon(/*inout vec3 L[5], out int n*/) {
  18. int n = 0;
  19. // Detect clipping config
  20. int config = 0;
  21. if (L0.z > 0.0) config += 1;
  22. if (L1.z > 0.0) config += 2;
  23. if (L2.z > 0.0) config += 4;
  24. if (L3.z > 0.0) config += 8;
  25. // Clip
  26. if (config == 0) {
  27. // Clip all
  28. }
  29. else if (config == 1) { // V1 clip V2 V3 V4
  30. n = 3;
  31. L1 = -L1.z * L0 + L0.z * L1;
  32. L2 = -L3.z * L0 + L0.z * L3;
  33. }
  34. else if (config == 2) { // V2 clip V1 V3 V4
  35. n = 3;
  36. L0 = -L0.z * L1 + L1.z * L0;
  37. L2 = -L2.z * L1 + L1.z * L2;
  38. }
  39. else if (config == 3) { // V1 V2 clip V3 V4
  40. n = 4;
  41. L2 = -L2.z * L1 + L1.z * L2;
  42. L3 = -L3.z * L0 + L0.z * L3;
  43. }
  44. else if (config == 4) { // V3 clip V1 V2 V4
  45. n = 3;
  46. L0 = -L3.z * L2 + L2.z * L3;
  47. L1 = -L1.z * L2 + L2.z * L1;
  48. }
  49. else if (config == 5) { // V1 V3 clip V2 V4) impossible
  50. n = 0;
  51. }
  52. else if (config == 6) { // V2 V3 clip V1 V4
  53. n = 4;
  54. L0 = -L0.z * L1 + L1.z * L0;
  55. L3 = -L3.z * L2 + L2.z * L3;
  56. }
  57. else if (config == 7) { // V1 V2 V3 clip V4
  58. n = 5;
  59. L4 = -L3.z * L0 + L0.z * L3;
  60. L3 = -L3.z * L2 + L2.z * L3;
  61. }
  62. else if (config == 8) { // V4 clip V1 V2 V3
  63. n = 3;
  64. L0 = -L0.z * L3 + L3.z * L0;
  65. L1 = -L2.z * L3 + L3.z * L2;
  66. L2 = L3;
  67. }
  68. else if (config == 9) { // V1 V4 clip V2 V3
  69. n = 4;
  70. L1 = -L1.z * L0 + L0.z * L1;
  71. L2 = -L2.z * L3 + L3.z * L2;
  72. }
  73. else if (config == 10) { // V2 V4 clip V1 V3) impossible
  74. n = 0;
  75. }
  76. else if (config == 11) { // V1 V2 V4 clip V3
  77. n = 5;
  78. L4 = L3;
  79. L3 = -L2.z * L3 + L3.z * L2;
  80. L2 = -L2.z * L1 + L1.z * L2;
  81. }
  82. else if (config == 12) { // V3 V4 clip V1 V2
  83. n = 4;
  84. L1 = -L1.z * L2 + L2.z * L1;
  85. L0 = -L0.z * L3 + L3.z * L0;
  86. }
  87. else if (config == 13) { // V1 V3 V4 clip V2
  88. n = 5;
  89. L4 = L3;
  90. L3 = L2;
  91. L2 = -L1.z * L2 + L2.z * L1;
  92. L1 = -L1.z * L0 + L0.z * L1;
  93. }
  94. else if (config == 14) { // V2 V3 V4 clip V1
  95. n = 5;
  96. L4 = -L0.z * L3 + L3.z * L0;
  97. L0 = -L0.z * L1 + L1.z * L0;
  98. }
  99. else if (config == 15) { // V1 V2 V3 V4
  100. n = 4;
  101. }
  102. if (n == 3) L3 = L0;
  103. if (n == 4) L4 = L0;
  104. return n;
  105. }
  106. float ltcEvaluate(vec3 N, vec3 V, float dotNV, vec3 P, mat3 Minv, vec3 points0, vec3 points1, vec3 points2, vec3 points3) {
  107. // Construct orthonormal basis around N
  108. vec3 T1, T2;
  109. T1 = normalize(V - N * dotNV);
  110. T2 = cross(N, T1);
  111. // Rotate area light in (T1, T2, R) basis
  112. Minv = Minv * transpose(mat3(T1, T2, N));
  113. // Polygon (allocate 5 vertices for clipping)
  114. // vec3 L[5];
  115. L0 = Minv * (points0 - P);
  116. L1 = Minv * (points1 - P);
  117. L2 = Minv * (points2 - P);
  118. L3 = Minv * (points3 - P);
  119. L4 = vec3(0.0);
  120. // int n;
  121. int n = clipQuadToHorizon(/*L, n*/);
  122. if (n == 0) return 0.0;
  123. // Project onto sphere
  124. L0 = normalize(L0);
  125. L1 = normalize(L1);
  126. L2 = normalize(L2);
  127. L3 = normalize(L3);
  128. L4 = normalize(L4);
  129. // Integrate
  130. float sum = 0.0;
  131. sum += integrateEdge(L0, L1);
  132. sum += integrateEdge(L1, L2);
  133. sum += integrateEdge(L2, L3);
  134. if (n >= 4) sum += integrateEdge(L3, L4);
  135. if (n == 5) sum += integrateEdge(L4, L0);
  136. #ifdef _TwoSidedAreaLight
  137. return abs(sum);
  138. #else
  139. return max(0.0, -sum);
  140. #endif
  141. }