Fermat
ltc.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2016, NVIDIA Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of NVIDIA Corporation nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
34 #pragma once
35 
36 #include <cugar/linalg/vector.h>
37 #include <cugar/linalg/matrix.h>
38 #include <cugar/basic/numbers.h>
39 #include <cugar/bsdf/differential_geometry.h>
41 
42 #ifndef ONE_OVER_PIf
43 #define ONE_OVER_PIf 0.31830988618f
44 #endif
45 
46 #ifndef ONE_OVER_TWO_PIf
47 #define ONE_OVER_TWO_PIf 0.15915494309f
48 #endif
49 
50 #ifndef HALF_PIf
51 #define HALF_PIf 1.57079632679f
52 #endif
53 
54 #ifndef ONE_OVER_HALF_PIf
55 #define ONE_OVER_HALF_PIf 0.63661977236f
56 #endif
57 
58 #define LTC_USE_INVDET
59 
60 namespace cugar {
61 
64 CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
66 
71 struct LTCBsdf
80 {
81  inline
82  static void preprocess(const uint32 size, const Matrix3x3f* tabM, float4* tab, float4* tab_inv)
83  {
84  for (uint32 j = 0; j < size; ++j)
85  for (uint32 i = 0; i < size; ++i)
86  {
87  Matrix3x3f M = transpose(tabM[i + j*size]);
88 
89  float a = M[0][0];
90  float b = M[2][0];
91  float c = M[1][1];
92  float d = M[0][2];
93 
94  tab[i + j*size] = make_float4(a, b, c, d);
95 
96  // Rescaled inverse of m:
97  // a 0 b inverse 1 0 -b
98  // 0 c 0 ==> 0 (a - b*d)/c 0
99  // d 0 1 -d 0 a
100 
101  // Store the variable terms
102  tab_inv[i + j*size] = make_float4(
103  a,
104  -b,
105  (a - b*d) / c,
106  -d);
107  }
108  }
109 
110  struct LTC
111  {
112  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
113  LTC(const float cosTheta, const float4* tabM, const float4* tabMinv, const float* tabA, const uint32 size)
114  {
115  const float theta = acos(fabsf(cosTheta));
116 
117  const float theta_unit = theta * ONE_OVER_HALF_PIf * size;
118  const float theta_floor = floorf(theta_unit); // NOTE:
119  const float theta_c1 = theta_unit - theta_floor; // tex fetch logic that
120  const float theta_c0 = 1.0f - theta_c1; // can be done in HW
121 
122  const int t1 = max(0, min((int)size - 1, (int)theta_floor));
123  const int t2 = min((int)size - 1, t1 + 1);
124 
125  amplitude = tabA[t1*size] * theta_c0 + // 1 TEX fetch
126  tabA[t2*size] * theta_c1; // with interpolation
127 
128  m = Vector4f(tabM[t1*size]) * theta_c0 +
129  Vector4f(tabM[t2*size]) * theta_c1;
130 
131  //M[0][0] = m.x; M[1][0] = 0; M[2][0] = m.y;
132  //M[0][1] = 0; M[1][1] = m.z; M[2][1] = 0;
133  //M[0][2] = m.w; M[1][2] = 0; M[2][2] = 1;
134 
135  #if 1
136  m_inv = Vector4f(tabMinv[t1*size]) * theta_c0 + // 1 TEX fetch
137  Vector4f(tabMinv[t2*size]) * theta_c1; // with interpolation
138  #else
139  const float a = m.x;
140  const float b = m.y;
141  const float c = m.z;
142  const float d = m.w;
143 
144  // Rescaled inverse of m:
145  // a 0 b inverse 1 0 -b
146  // 0 c 0 ==> 0 (a - b*d)/c 0
147  // d 0 1 -d 0 a
148 
149  // Store the variable terms
150  m_inv = Vector4f(
151  a,
152  -b,
153  (a - b*d) / c,
154  -d);
155  #endif
156 
157  //invM[0][0] = 1; invM[1][0] = 0; invM[2][0] = m_inv.y;
158  //invM[0][1] = 0; invM[1][1] = m_inv.z; invM[2][1] = 0;
159  //invM[0][2] = m_inv.w; invM[1][2] = 0; invM[2][2] = m_inv.x;
160 
161  #if defined(LTC_USE_INVDET)
162  //detMinv = fabsf(cugar::det(invM));
163  detMinv = fabsf(m_inv.x * m_inv.z - m_inv.w * m_inv.z*m_inv.y); // 2 MULS + 1 MAD
164  #else
165  //detM = fabsf(cugar::det(M));
166  detM = fabsf(m.x * m.z - m.w * m.z*m.y); // 2 MULS + 1 MAD
167  #endif
168  }
169 
170  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
171  Vector3f transform(const Vector3f L) const
172  {
173  //return M * L;
174  return Vector3f(
175  m.x * L.x + m.w * L.z, // 1 MUL + 1 MAD
176  m.z * L.y, // 1 MUL
177  m.y * L.x + L.z); // 1 MAD
178  }
179 
180  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
181  Vector3f inv_transform(const Vector3f L) const
182  {
183  //return invM * L;
184  return Vector3f(
185  L.x + m_inv.w * L.z, // 1 MAD
186  m_inv.z * L.y, // 1 MUL
187  m_inv.y * L.x + m_inv.x * L.z); // 1 MUL + 1 MAD
188  }
189 
190  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
191  float p(const Vector3f L) const // 1 SQRT + 2 DIV + 2 MAD + 7 MUL + 2 ADD + 1 MAX
192  {
193  #if defined(LTC_USE_INVDET)
194  Vector3f Loriginal = inv_transform(L); // 2 MAD + 2 MUL
195  const float l = length(Loriginal); // 1 SQRT + 2 ADD
196 
197  const float InvJacobian = detMinv / (l*l*l); // 1 DIV + 3 MUL
198 
199  const float D = ONE_OVER_PIf * max(0.0f, Loriginal.z / l); // 1 DIV + 1 MUL + 1 MAX
200  return D * InvJacobian; // 1 MUL
201  #else
202  const Vector3f Loriginal = normalize(inv_transform(L)); // 1 SQRT + 2 ADD
203  const Vector3f L_ = transform(Loriginal);
204 
205  const float l = length(L_); // 1 SQRT + 2 ADD
206  const float InvJacobian = (l*l*l) / detM; // 1 DIV + 3 MUL
207  //const float Jacobian = detM / (l*l*l); // 1 DIV + 3 MUL
208 
209  const float D = ONE_OVER_PIf * max(0.0f, Loriginal.z);
210 
211  return D * InvJacobian; // 1 MUL
212  //return D / Jacobian; // 1 DIV
213  #endif
214  }
215 
216 
219  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
220  float clipped_edge_integral(const cugar::Vector3f p0, const cugar::Vector3f p1) const
221  {
222  return acosf(dot(p0,p1)) * dot( normalize(cross(p0,p1)), Vector3f(0,0,1) );
223  }
224 
227  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
228  float clipped_polygon_integral(const uint32 n, const cugar::Vector3f p[5]) const
229  {
230  // use equation 11 from:
231  // Real-Time Polygonal-Light Shading with Linearly Transformed Cosines,
232  // Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt
233  float r = 0.0f;
234  r += clipped_edge_integral(p[0],p[1]);
235  r += clipped_edge_integral(p[1],p[2]);
236  r += clipped_edge_integral(p[2],p[3]);
237  if (n >= 4) r += clipped_edge_integral(p[3],p[4]);
238  if (n >= 5) r += clipped_edge_integral(p[4],p[0]);
239  return fabsf(r) * ONE_OVER_TWO_PIf;
240  }
241 
244  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
245  float small_hemispherical_sector_integral(const Matrix3x3f& T, const float2 theta, const float2 phi) const
246  {
247  // compute the spherical polygon corresponding to the sector, and transform it by the inverse LTC transform
248  Vector3f p[5];
249  p[0] = inv_transform( T * from_spherical_coords( cugar::Vector2f(phi.x, theta.x) ) );
250  p[1] = inv_transform( T * from_spherical_coords( cugar::Vector2f(phi.y, theta.x) ) );
251  p[2] = inv_transform( T * from_spherical_coords( cugar::Vector2f(phi.y, theta.y) ) );
252  p[3] = inv_transform( T * from_spherical_coords( cugar::Vector2f(phi.x, theta.y) ) );
253 
254  const uint32 n = clip_quad_to_horizon( p );
255 
256  return clipped_polygon_integral( n, p );
257 
258  }
259 
262  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
263  float hemispherical_sector_integral(const Matrix3x3f& T, const float2 theta, const float2 phi) const
264  {
265  if (phi.y - phi.x == 2.0f*M_PIf)
266  {
267  // divide the domain in four parts
268  const float phi_1 = phi.x*0.75f + phi.y*0.25f;
269  const float phi_2 = (phi.x + phi.y)*0.5f;
270  const float phi_3 = phi.x*0.5f + phi.y*0.75f;
271 
272  return
273  small_hemispherical_sector_integral(T, theta, make_float2(phi.x, phi_1) ) +
274  small_hemispherical_sector_integral(T, theta, make_float2(phi_1, phi_2) ) +
275  small_hemispherical_sector_integral(T, theta, make_float2(phi_2, phi_3) ) +
276  small_hemispherical_sector_integral(T, theta, make_float2(phi_3, phi.y) );
277  }
278  else if (phi.y - phi.x >= M_PIf)
279  {
280  // divide the domain in two parts
281  const float phi_2 = (phi.x + phi.y)*0.5f;
282 
283  return
284  small_hemispherical_sector_integral(T, theta, make_float2(phi.x, phi_2) ) +
285  small_hemispherical_sector_integral(T, theta, make_float2(phi_2, phi.y) );
286  }
287  else
288  return small_hemispherical_sector_integral(T, theta, phi);
289  }
290 
291  Vector4f m;
292  Vector4f m_inv;
293 
294  //Matrix3x3f M;
295  //Matrix3x3f invM;
296  #if defined(LTC_USE_INVDET)
297  float detMinv;
298  #else
299  float detM;
300  #endif
301  float amplitude;
302  };
303 
304  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
305  LTCBsdf(const float _roughness, const float4* _tabM, const float4* _tabMinv, const float* _tabA, const uint32 _size) :
306  roughness(_roughness),
307  tabM(_tabM),
308  tabMinv(_tabMinv),
309  tabA(_tabA),
310  size(_size)
311  {
312  const int a = max(0, min((int)size - 1, (int)floorf(sqrtf(roughness) * size)));
313 
314  tabM += a;
315  tabMinv += a;
316  tabA += a;
317  }
318 
321  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
322  Vector3f f(const DifferentialGeometry& geometry, const Vector3f V, const Vector3f L) const
323  {
324  const Vector3f N = geometry.normal_s;
325 
326  const float NoV = dot(N, V);
327  const float NoL = dot(N, L);
328 
329  if (NoV * NoL <= 0.0f)
330  return Vector3f(0.0f);
331 
332  // use a coordinate system in which V has coordinates (sin(theta), 0, cos(theta))
333  //const Vector3f T = normalize(V - N*dot(V, N));
334  //const Vector3f B = cross(N, T);
335  const Vector3f B = normalize(cross(N, V));
336  const Vector3f T = cross(B, N);
337  const cugar::Vector3f local_L(
338  dot(T, L),
339  dot(B, L),
340  fabsf(NoL));
341 
342  LTC ltc(fabsf(NoV), tabM, tabMinv, tabA, size);
343 
344  return ltc.amplitude * ltc.p(local_L) / fabsf(NoL); // The LTC already contains NoL - hence we must de-multiply it out
345  }
346 
349  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
350  Vector3f f_over_p(const DifferentialGeometry& geometry, const Vector3f V, const Vector3f L) const
351  {
352  const Vector3f N = geometry.normal_s;
353 
354  const float NoV = dot(N, V);
355  const float NoL = dot(N, L);
356 
357  if (NoV * NoL <= 0.0f)
358  return Vector3f(0.0f);
359 
360  // use a coordinate system in which V has coordinates (sin(theta), 0, cos(theta))
361  const Vector3f B = normalize(cross(N, V));
362  const Vector3f T = cross(B, N);
363  const cugar::Vector3f local_L(
364  dot(T, L),
365  dot(B, L),
366  fabsf(NoL));
367 
368  LTC ltc(fabsf(NoV), tabM, tabMinv, tabA, size);
369 
370  const float p = ltc.p(local_L);
371 
372  return p > 0.0f ? ltc.amplitude : 0.0f; // f/p wrt projected solid angle
373  }
374 
377  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
378  void f_and_p(const DifferentialGeometry& geometry, const Vector3f V, const Vector3f L, Vector3f& f, float& p, const SphericalMeasure measure = kProjectedSolidAngle) const
379  {
380  const Vector3f N = geometry.normal_s;
381 
382  const float NoV = dot(N, V);
383  const float NoL = dot(N, L);
384 
385  // use a coordinate system in which V has coordinates (sin(theta), 0, cos(theta))
386  const Vector3f B = normalize(cross(N, V));
387  const Vector3f T = cross(B, N);
388  const cugar::Vector3f local_L(
389  dot(T, L),
390  dot(B, L),
391  fabsf(NoL));
392 
393  LTC ltc(fabsf(NoV), tabM, tabMinv, tabA, size);
394 
395  p = ltc.p(local_L);
396  f = (NoV * NoL <= 0.0f) ?
397  Vector3f(0.0f) :
398  ltc.amplitude * p / fabsf(NoL); // The LTC already contains NoL - hence we must de-multiply it out
399 
400  if (measure == kProjectedSolidAngle)
401  p /= fabsf(NoL);
402  }
403 
406  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
407  float p(const DifferentialGeometry& geometry, const Vector3f V, const Vector3f L, const SphericalMeasure measure = kProjectedSolidAngle) const
408  {
409  const Vector3f N = geometry.normal_s;
410 
411  const float NoV = dot(N, V);
412  const float NoL = dot(N, L);
413 
414  // use a coordinate system in which V has coordinates (sin(theta), 0, cos(theta))
415  const Vector3f B = normalize(cross(N, V));
416  const Vector3f T = cross(B, N);
417  const cugar::Vector3f local_L(
418  dot(T, L),
419  dot(B, L),
420  fabsf(NoL));
421 
422  LTC ltc(fabsf(NoV), tabM, tabMinv, tabA, size);
423 
424  float p = ltc.p(local_L);
425 
426  return (measure == kProjectedSolidAngle) ? p / fabsf(NoL) : p;
427  }
428 
431  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
432  void sample(
433  const Vector3f u,
434  const DifferentialGeometry& geometry,
435  const Vector3f V,
436  Vector3f& L,
437  Vector3f& g,
438  float& p,
439  float& p_proj) const
440  {
441  const Vector3f N = geometry.normal_s;
442 
443  const float NoV = dot(N, V);
444 
445  LTC ltc(fabsf(NoV), tabM, tabMinv, tabA, size);
446 
447  //const float theta = acosf(sqrtf(u.x));
448  //const float phi = 2.0f*3.14159f * u.y;
449  //printf("S: %f, %f, %f\n", sinf(theta)*cosf(phi), sinf(theta)*sinf(phi), cosf(theta));
450  //Vector3f local_L = normalize(ltc.transform( Vector3f(sinf(theta)*cosf(phi), sinf(theta)*sinf(phi), cosf(theta)) ));
451  Vector3f local_L = normalize(ltc.transform( square_to_cosine_hemisphere(u.xy()) ));
452  //printf("S -> L: %f, %f, %f\n", local_L.x, local_L.y, local_L.z);
453 
454  // reverse the sign bit
455  if (NoV < 0.0f)
456  local_L.z = -local_L.z;
457 
458  // use a coordinate system in which V has coordinates (sin(theta), 0, cos(theta))
459  const Vector3f B = normalize(cross(N, V));
460  const Vector3f T = cross(B, N);
461  L = local_L.x * T +
462  local_L.y * B +
463  local_L.z * N;
464 
465  const float NoL = dot(N, L);
466 
467  // reset the sign bit
468  if (NoV < 0.0f)
469  local_L.z = -local_L.z;
470 
471  p = ltc.p(local_L);
472  p_proj = p / fabsf(local_L.z);
473 
474  g = (NoV * NoL <= 0.0f || p == 0.0f) ?
475  Vector3f(0.0f) :
476  ltc.amplitude; // g = f/p wrt projected solid angle
477  }
478 
481  template <typename RandomGeneratorT>
482  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
483  bool invert(
484  const DifferentialGeometry& geometry,
485  const Vector3f V,
486  const Vector3f L,
487  RandomGeneratorT& random,
488  Vector3f& z,
489  float& p,
490  float& p_proj) const
491  {
492  return 0;
493  }
494 
497  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
499  const DifferentialGeometry& geometry,
500  const Vector3f V,
501  const Vector3f L,
502  const Vector3f u,
503  float& p,
504  float& p_proj) const
505  {
506  }
507 
510  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
512  const DifferentialGeometry& geometry,
513  const Vector3f V) const
514  {
515  const Vector3f N = geometry.normal_s;
516 
517  const float NoV = dot(N, V);
518 
519  return LTC(fabsf(NoV), tabM, tabMinv, tabA, size);
520  }
521 
524  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
526  const DifferentialGeometry& geometry,
527  const Vector3f V,
528  const float2 theta,
529  const float2 phi) const
530  {
531  //
532  // compute the transformation from the local frame defined by
533  // geometry.(tangent,binormal,N) to the LTC's frame (T,B,N);
534  // this is equivalent to right-multiplying the matrix to go in world space
535  // from local geometry coorinates, by the matrix to go from world space
536  // into the LTC's frame.
537  //
538 
539  // use a coordinate system in which V has coordinates (sin(theta), 0, cos(theta))
540  const Vector3f N = geometry.normal_s;
541  const Vector3f B = normalize(cross(N, V));
542  const Vector3f T = cross(B, N);
543 
544  Matrix3x3f M;
545  M[0][0] = dot(T, geometry.tangent);
546  M[0][1] = dot(T, geometry.binormal);
547  M[0][2] = 0.0f;
548  M[1][0] = dot(B, geometry.tangent);
549  M[1][1] = dot(B, geometry.binormal);
550  M[1][2] = 0.0f;
551  M[2][0] = 0.0f; // dot(N, geometry.tangent)
552  M[2][1] = 0.0f; // dot(N, geometry.binormal)
553  M[2][2] = 1.0f; // dot(N, N)
554 
555  return get_ltc(geometry, V).hemispherical_sector_integral( M, theta, phi );
556  }
557 
558 public:
559  float roughness;
560  const float4* tabM;
561  const float4* tabMinv;
562  const float* tabA;
563  uint32 size;
564 };
565 
566 
567 // clip a quad to the plane z = 0
568 //
569 CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
571 {
572  // detect clipping config
573  int config = 0;
574  if (L[0].z > 0.0) config += 1;
575  if (L[1].z > 0.0) config += 2;
576  if (L[2].z > 0.0) config += 4;
577  if (L[3].z > 0.0) config += 8;
578 
579  // clip
580  uint32 n = 0;
581 
582  if (config == 0)
583  {
584  // clip all
585  }
586  else if (config == 1) // V1 clip V2 V3 V4
587  {
588  n = 3;
589  L[1] = -L[1].z * L[0] + L[0].z * L[1];
590  L[2] = -L[3].z * L[0] + L[0].z * L[3];
591  }
592  else if (config == 2) // V2 clip V1 V3 V4
593  {
594  n = 3;
595  L[0] = -L[0].z * L[1] + L[1].z * L[0];
596  L[2] = -L[2].z * L[1] + L[1].z * L[2];
597  }
598  else if (config == 3) // V1 V2 clip V3 V4
599  {
600  n = 4;
601  L[2] = -L[2].z * L[1] + L[1].z * L[2];
602  L[3] = -L[3].z * L[0] + L[0].z * L[3];
603  }
604  else if (config == 4) // V3 clip V1 V2 V4
605  {
606  n = 3;
607  L[0] = -L[3].z * L[2] + L[2].z * L[3];
608  L[1] = -L[1].z * L[2] + L[2].z * L[1];
609  }
610  else if (config == 5) // V1 V3 clip V2 V4) impossible
611  {
612  n = 0;
613  }
614  else if (config == 6) // V2 V3 clip V1 V4
615  {
616  n = 4;
617  L[0] = -L[0].z * L[1] + L[1].z * L[0];
618  L[3] = -L[3].z * L[2] + L[2].z * L[3];
619  }
620  else if (config == 7) // V1 V2 V3 clip V4
621  {
622  n = 5;
623  L[4] = -L[3].z * L[0] + L[0].z * L[3];
624  L[3] = -L[3].z * L[2] + L[2].z * L[3];
625  }
626  else if (config == 8) // V4 clip V1 V2 V3
627  {
628  n = 3;
629  L[0] = -L[0].z * L[3] + L[3].z * L[0];
630  L[1] = -L[2].z * L[3] + L[3].z * L[2];
631  L[2] = L[3];
632  }
633  else if (config == 9) // V1 V4 clip V2 V3
634  {
635  n = 4;
636  L[1] = -L[1].z * L[0] + L[0].z * L[1];
637  L[2] = -L[2].z * L[3] + L[3].z * L[2];
638  }
639  else if (config == 10) // V2 V4 clip V1 V3) impossible
640  {
641  n = 0;
642  }
643  else if (config == 11) // V1 V2 V4 clip V3
644  {
645  n = 5;
646  L[4] = L[3];
647  L[3] = -L[2].z * L[3] + L[3].z * L[2];
648  L[2] = -L[2].z * L[1] + L[1].z * L[2];
649  }
650  else if (config == 12) // V3 V4 clip V1 V2
651  {
652  n = 4;
653  L[1] = -L[1].z * L[2] + L[2].z * L[1];
654  L[0] = -L[0].z * L[3] + L[3].z * L[0];
655  }
656  else if (config == 13) // V1 V3 V4 clip V2
657  {
658  n = 5;
659  L[4] = L[3];
660  L[3] = L[2];
661  L[2] = -L[1].z * L[2] + L[2].z * L[1];
662  L[1] = -L[1].z * L[0] + L[0].z * L[1];
663  }
664  else if (config == 14) // V2 V3 V4 clip V1
665  {
666  n = 5;
667  L[4] = -L[0].z * L[3] + L[3].z * L[0];
668  L[0] = -L[0].z * L[1] + L[1].z * L[0];
669  }
670  else if (config == 15) // V1 V2 V3 V4
671  {
672  n = 4;
673  }
674 
675  if (n == 3) L[3] = L[0];
676  if (n == 4) L[4] = L[0];
677 
678  return n;
679 }
680 
684 } // namespace cugar
SphericalMeasure
Definition: differential_geometry.h:50
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE float hemispherical_sector_integral(const Matrix3x3f &T, const float2 theta, const float2 phi) const
Definition: ltc.h:263
Definition: matrix.h:54
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE void f_and_p(const DifferentialGeometry &geometry, const Vector3f V, const Vector3f L, Vector3f &f, float &p, const SphericalMeasure measure=kProjectedSolidAngle) const
Definition: ltc.h:378
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE float small_hemispherical_sector_integral(const Matrix3x3f &T, const float2 theta, const float2 phi) const
Definition: ltc.h:245
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE float hemispherical_sector_integral(const DifferentialGeometry &geometry, const Vector3f V, const float2 theta, const float2 phi) const
Definition: ltc.h:525
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE Vector3f f(const DifferentialGeometry &geometry, const Vector3f V, const Vector3f L) const
Definition: ltc.h:322
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE bool invert(const DifferentialGeometry &geometry, const Vector3f V, const Vector3f L, RandomGeneratorT &random, Vector3f &z, float &p, float &p_proj) const
Definition: ltc.h:483
Definition: ltc.h:110
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE uint32 clip_quad_to_horizon(cugar::Vector3f L[5])
Definition: ltc.h:570
Defines various spherical mappings.
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE float clipped_polygon_integral(const uint32 n, const cugar::Vector3f p[5]) const
Definition: ltc.h:228
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE void inverse_pdf(const DifferentialGeometry &geometry, const Vector3f V, const Vector3f L, const Vector3f u, float &p, float &p_proj) const
Definition: ltc.h:498
Definition: differential_geometry.h:59
float random()
Definition: tiled_sampling.h:44
Define a vector_view POD type and plain_view() for std::vector.
Definition: diff.h:38
CUGAR_HOST CUGAR_DEVICE Vector3f from_spherical_coords(const Vector2f &uv)
Definition: mappings_inline.h:33
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE float clipped_edge_integral(const cugar::Vector3f p0, const cugar::Vector3f p1) const
Definition: ltc.h:220
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE LTC get_ltc(const DifferentialGeometry &geometry, const Vector3f V) const
Definition: ltc.h:511
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE void sample(const Vector3f u, const DifferentialGeometry &geometry, const Vector3f V, Vector3f &L, Vector3f &g, float &p, float &p_proj) const
Definition: ltc.h:432
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE Vector3f f_over_p(const DifferentialGeometry &geometry, const Vector3f V, const Vector3f L) const
Definition: ltc.h:350
Definition: ltc.h:79
CUGAR_HOST CUGAR_DEVICE Vector3f square_to_cosine_hemisphere(const Vector2f &uv)
Definition: mappings_inline.h:119
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE uint32 length(const vector_view< Iterator > &vec)
Definition: vector_view.h:228
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE float p(const DifferentialGeometry &geometry, const Vector3f V, const Vector3f L, const SphericalMeasure measure=kProjectedSolidAngle) const
Definition: ltc.h:407