Fermat
bpt_utils.h
1 /*
2  * Fermat
3  *
4  * Copyright (c) 2016-2019, NVIDIA CORPORATION. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the NVIDIA CORPORATION nor the
14  * names of its contributors may be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #pragma once
30 
31 #include <vertex.h>
32 #include <bsdf.h>
33 #include <edf.h>
34 #include <lights.h>
35 #include <camera.h>
36 #include <renderer.h>
37 #include <mesh_utils.h>
38 #include <cugar/linalg/vector.h>
40 #include <cugar/color/rgbe.h>
41 
44 
47 
50 
51 #define DEBUG_S -1
52 #define DEBUG_T -1
53 #define DEBUG_LENGTH 0
54 
55 #define MIN_G_DENOM 1.0e-8f
56 
57 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
58 float mis_selector(const uint32 s, const uint32 t, const float w)
59 {
60  return
61  DEBUG_LENGTH ? (DEBUG_LENGTH == s + t - 1 ? w : 0.0f) :
62  (DEBUG_S == -1 && DEBUG_T == -1) ? w :
63  (DEBUG_S == s && DEBUG_T == t) ? 1.0f :
64  (DEBUG_S == s && DEBUG_T == -1) ? 1.0f :
65  (DEBUG_S == -1 && DEBUG_T == t) ? 1.0f :
66  0.0f;
67 }
68 
69 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
70 float mis_power(const float w) { return w; }
71 
72 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
73 float bpt_mis(const float pGp, const float prev_pGp, const float next_pGp, const float pGp_sum)
74 {
75  return pGp && prev_pGp && next_pGp ? mis_power(1 / pGp) / (mis_power(1 / pGp) + mis_power(1 / prev_pGp) + mis_power(1 / next_pGp) + pGp_sum) : 0.0f;
76 }
77 
78 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
79 float bpt_mis(const float pGp, const float other_pGp, const float pGp_sum)
80 {
81  return pGp && other_pGp ? mis_power(1 / pGp) / (mis_power(1 / pGp) + mis_power(1 / other_pGp) + pGp_sum) : 0.0f;
82 }
83 
84 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
85 float pdf_product(const float p1, const float p2)
86 {
87  return
88  cugar::is_finite(p1) &&
89  cugar::is_finite(p2) ? p1 * p2 : cugar::float_infinity();
90 }
91 
92 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
93 float pdf_product(const float p1, const float p2, const float p3)
94 {
95  return
96  cugar::is_finite(p1) &&
97  cugar::is_finite(p2) &&
98  cugar::is_finite(p3) ? p1 * p2 * p3 : cugar::float_infinity();
99 }
100 
101 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
102 uint32 channel_selector(const Bsdf::ComponentType comp)
103 {
104  return (comp & Bsdf::kDiffuseMask) ? FBufferDesc::DIFFUSE_C : FBufferDesc::SPECULAR_C;
105 }
106 
111 {
112  FERMAT_HOST_DEVICE PathWeights() {}
113  FERMAT_HOST_DEVICE PathWeights(const float _pGp_sum, const float _pG) :
114  pGp_sum(_pGp_sum), pG(_pG) {}
115  FERMAT_HOST_DEVICE PathWeights(const float2 f) : vector_storage(f) {}
116 
117  FERMAT_HOST_DEVICE operator float2() const { return vector_storage; }
118 
119  union {
120  float2 vector_storage;
121  struct {
122  float pGp_sum;
123  float pG;
124  };
125  };
126 };
127 
132 {
133  FERMAT_HOST_DEVICE TempPathWeights() {}
134  FERMAT_HOST_DEVICE TempPathWeights(const PathWeights _weights, const float _out_p, const float _out_cos_theta) :
135  pGp_sum(_weights.pGp_sum), pG(_weights.pG), out_p(_out_p), out_cos_theta(_out_cos_theta) {}
136  FERMAT_HOST_DEVICE TempPathWeights(const float _pGp_sum, const float _pG, const float _out_p, const float _out_cos_theta) :
137  pGp_sum(_pGp_sum), pG(_pG), out_p(_out_p), out_cos_theta(_out_cos_theta) {}
138  FERMAT_HOST_DEVICE TempPathWeights(const float4 f) : vector_storage(f) {}
139 
140  template <typename EyeLightVertexType>
141  FERMAT_HOST_DEVICE TempPathWeights(const EyeLightVertexType _v, const cugar::Vector3f _out, const float _out_p) :
142  pGp_sum(_v.pGp_sum), // 1 / [p(i-2)g(i-2)p(i-1)] + 1 / [p(i-3)g(i-3)p(i-2)] + ... + 1 / [p(-1)g(-1)p(0)]
143  pG(_v.prev_pG), // p(i-1)g(i-1)
144  out_p(_out_p), // p(i)
145  out_cos_theta(fabsf(dot(_v.geom.normal_s, _out))) {} // cos(theta_i)
146 
147  // return the temporary weights for the second camera vertex (i.s. t=1)
148  FERMAT_HOST_DEVICE
149  static TempPathWeights eye_vertex_1(const float p_e, const float cos_theta_o, const float light_tracing_weight)
150  {
151  return TempPathWeights(
152  0.0f, // 1 / p(-2)g(-2)p(-1)
153  1.0e8f, // p(-1)g(-1) = +inf : hitting the camera is impossible
154  light_tracing_weight ? p_e / light_tracing_weight : 1.0f, // out_p = p(0)
155  light_tracing_weight ? cos_theta_o : 1.0e8f); // out_cos_theta : so that the term f_0 g_0 f_1 (i.e. connection to the lens) gets the proper weight
156  // +inf : so that the term f_0 g_0 f_1(i.e.connection to the lens) gets zero weight
157  }
158 
159  // return the temporary weights for the second light vertex (i.e. s=1)
160  FERMAT_HOST_DEVICE
161  static TempPathWeights light_vertex_1(const float p_A, const float p_proj, const float cos_theta_o)
162  {
163  return TempPathWeights(
164  0.0f, // p(-2)g(-2)p(-1)
165  1.0f * p_A, // p(-1)g(-1) = 1 : we want p(-1)g(-1)p(0) = p(0) - which will happen because we are setting p(0) = p_sigma(0) and g(-1) = p_A(0)
166  p_proj, // p(0)
167  cos_theta_o); // cos(theta_0)
168  }
169 
170  FERMAT_HOST_DEVICE operator PathWeights() const { return PathWeights(pGp_sum, pG); }
171  FERMAT_HOST_DEVICE operator float4() const { return vector_storage; }
172 
173  union {
174  float4 vector_storage;
175  struct
176  {
177  float pGp_sum;
178  float pG;
179  float out_p;
180  float out_cos_theta;
181  };
182  };
183 };
184 
188 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
189 uint4 pack_edf(const Edf& edf)
190 {
191  return make_uint4(
192  cugar::to_rgbe(edf.color),
193  0,
194  0,
195  0);
196 }
197 
201 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
202 uint4 pack_edf(const MeshMaterial& material)
203 {
204  return make_uint4(
205  cugar::to_rgbe(cugar::Vector4f(material.emissive).xyz()),
206  0,
207  0,
208  0);
209 }
210 
214 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
215 uint4 pack_bsdf(const MeshMaterial& material)
216 {
217  const uint32 roughness_i = (uint16)cugar::quantize( material.roughness, 65535u );
218  const uint32 opacity_i = (uint16)cugar::quantize( material.opacity, 255u );
219  const uint32 ior_i = (uint16)cugar::quantize( material.index_of_refraction / 3.0f, 255u );
220  return make_uint4(
221  cugar::to_rgbe(cugar::Vector4f(material.diffuse).xyz()),
222  cugar::to_rgbe(cugar::Vector4f(material.specular).xyz()),
223  roughness_i | (opacity_i << 16) | (ior_i << 24),
224  cugar::to_rgbe(cugar::Vector4f(material.diffuse_trans).xyz()));
225 }
226 
230 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
231 Edf unpack_edf(const uint4 packed_info)
232 {
233  return Edf(cugar::from_rgbe(packed_info.x));
234 }
235 
239 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
240 Bsdf unpack_bsdf(const RenderingContextView& renderer, const uint4 packed_info, const TransportType transport = kParticleTransport)
241 {
242  const float roughness = (packed_info.z & 65535u) / 65535.0f;
243  const float opacity = ((packed_info.z >> 16) & 255) / 255.0f;
244  const float ior = cugar::max( 3.0f * ((packed_info.z >> 24) / 255.0f), 0.00001f );
245 
246  return Bsdf(
247  transport,
248  renderer,
249  cugar::from_rgbe(packed_info.x),
250  cugar::from_rgbe(packed_info.y),
251  roughness,
252  cugar::from_rgbe(packed_info.w),
253  opacity,
254  ior);
255 }
256 
260 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
261 cugar::Vector3f unpack_bsdf_diffuse(const uint4 packed_info) { return cugar::from_rgbe(packed_info.x); }
262 
266 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
267 cugar::Vector3f unpack_bsdf_specular(const uint4 packed_info) { return cugar::from_rgbe(packed_info.y); }
268 
272 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
273 float unpack_bsdf_roughness(const uint4 packed_info) { return cugar::binary_cast<float>(packed_info.z); }
274 
278 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
279 cugar::Vector3f unpack_bsdf_diffuse_trans(const uint4 packed_info) { return cugar::from_rgbe(packed_info.w); }
280 
284 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
285 cugar::Vector3f bump_mapping(const VertexGeometryId& geom_id, const VertexGeometry& geom, const TextureReference& bump_map, const RenderingContextView& renderer)
286 {
287  // 1. lookup dh_dst using the bump map
288  const cugar::Vector2f dh_dst = diff_texture_lookup(geom.texture_coords, bump_map, renderer.textures, cugar::Vector2f(0.0f));
289 
290  if (dh_dst != cugar::Vector2f(0.0f))
291  {
292  // 2. compute dp_dst
293  const cugar::Matrix3x2f dp_dst = prim_dp_dst<kTextureCoords0>( renderer.mesh, geom_id.prim_id );
294 
295  cugar::Vector3f dp_ds( dp_dst[0][0], dp_dst[1][0], dp_dst[2][0] );
296  cugar::Vector3f dp_dt( dp_dst[0][1], dp_dst[1][1], dp_dst[2][1] );
297 
298  // 3. project dp_ds and dp_dt on the plane formed by the local interpolated normal
299  dp_ds = dp_ds - geom.normal_s * dot(dp_ds, geom.normal_s);
300  dp_dt = dp_dt - geom.normal_s * dot(dp_dt, geom.normal_s);
301 
302  // 4. recompute the new normal as: N + dh_dt * (dp_ds x N) + dh_ds * (dp_dt x N)
303  return dh_dst.y * cugar::cross(dp_ds, geom.normal_s) + dh_dst.x * cugar::cross(dp_dt, geom.normal_s);
304  }
305  return cugar::Vector3f(0.0f);
306 }
307 
312 {
313  FERMAT_HOST_DEVICE
314  void setup(
315  const cugar::Vector4f& _pos,
316  const uint2& _packed_info1,
317  const uint4& _packed_info2,
318  const PathWeights& _weights,
319  const uint32 _depth,
320  const RenderingContextView& renderer)
321  {
322  in = unpack_direction(_packed_info1.x);
323  alpha = cugar::from_rgbe(_packed_info1.y);
324  weights = _weights;
325  depth = _depth;
326 
327  geom.position = _pos.xyz();
328  geom.normal_s = unpack_direction(cugar::binary_cast<uint32>(_pos.w));
329  geom.normal_g = geom.normal_s;
330  geom.tangent = cugar::orthogonal(geom.normal_s);
331  geom.binormal = cugar::cross(geom.normal_s, geom.tangent);
332 
333  if (depth == 0)
334  edf = unpack_edf(_packed_info2);
335  else
336  bsdf = unpack_bsdf(renderer, _packed_info2);
337  }
338 
339  FERMAT_HOST_DEVICE
340  void setup(
341  const Ray& ray,
342  const Hit& hit,
343  const cugar::Vector3f& _alpha,
344  const PathWeights& _weights,
345  const uint32 _depth,
346  const RenderingContextView& renderer)
347  {
348  geom_id.prim_id = hit.triId;
349  geom_id.uv = cugar::Vector2f(hit.u, hit.v);
350 
351  alpha = _alpha;
352  weights = _weights;
353  depth = _depth;
354  //assert(depth);
355 
356  FERMAT_ASSERT(hit.triId < renderer.mesh.num_triangles);
357  setup_differential_geometry(renderer.mesh, hit.triId, hit.u, hit.v, &geom);
358 
359  #if !defined(BARYCENTRIC_HIT_POINT)
360  // reset the position using the ray
361  geom.position = cugar::Vector3f( ray.origin ) + hit.t * cugar::Vector3f( ray.dir );
362  #endif
363 
364  // fetch the material
365  const int material_id = renderer.mesh.material_indices[hit.triId];
366 
367  material = renderer.mesh.materials[material_id];
368 
369  // perform all texture lookups
370  material.diffuse *= bilinear_texture_lookup(geom.texture_coords, material.diffuse_map, renderer.textures, cugar::Vector4f(1.0f));
371  material.specular *= bilinear_texture_lookup(geom.texture_coords, material.specular_map, renderer.textures, cugar::Vector4f(1.0f));
372  material.emissive *= bilinear_texture_lookup(geom.texture_coords, material.emissive_map, renderer.textures, cugar::Vector4f(1.0f));
373  material.diffuse_trans *= bilinear_texture_lookup(geom.texture_coords, material.diffuse_trans_map, renderer.textures, cugar::Vector4f(1.0f));
374 
375  #if 0
376  // perform bump-mapping
377  geom.normal_s += 0.05f * bump_mapping( geom_id, geom, material.bump_map, renderer );
378  geom.normal_s = cugar::normalize( geom.normal_s );
379  #endif
380 
381  in = -cugar::normalize(cugar::Vector3f(ray.dir));
382 
383  //if (dot(geom.normal_s, in) < 0.0f)
384  // geom.normal_s = -geom.normal_s;
385 
386  bsdf = Bsdf(kParticleTransport, renderer, material);
387  }
388 
389  FERMAT_HOST_DEVICE
390  void setup(
391  const Ray& ray,
392  const Hit& hit,
393  const cugar::Vector3f& _alpha,
394  const TempPathWeights& _weights,
395  const uint32 _depth,
396  const RenderingContextView& renderer)
397  {
398  setup(ray, hit, _alpha, PathWeights(_weights), _depth, renderer);
399 
400  // compute the MIS terms for the next iteration
401  prev_G_prime = fabsf(dot(in, geom.normal_s)) / fmaxf(hit.t * hit.t, MIN_G_DENOM);
402 
403  prev_pG = pdf_product( _weights.out_p, _weights.out_cos_theta * prev_G_prime );
404  pGp_sum = _weights.pGp_sum + mis_power(1 / pdf_product(_weights.pG, _weights.out_p));
405  }
406 
407  FERMAT_HOST_DEVICE
408  void setup(
409  const cugar::Vector3f& _in,
410  const VertexGeometryId& _v,
411  const cugar::Vector3f& _alpha,
412  const PathWeights& _weights,
413  const uint32 _depth,
414  const RenderingContextView& renderer)
415  {
416  geom_id = _v;
417 
418  alpha = _alpha;
419  weights = _weights;
420  depth = _depth;
421  //assert(depth);
422 
423  FERMAT_ASSERT(_v.prim_id < (uint32)renderer.mesh.num_triangles);
424  setup_differential_geometry(renderer.mesh, _v, &geom);
425 
426  // fetch the material
427  const int material_id = renderer.mesh.material_indices[_v.prim_id];
428 
429  material = renderer.mesh.materials[material_id];
430 
431  // perform all texture lookups
432  material.diffuse *= bilinear_texture_lookup(geom.texture_coords, material.diffuse_map, renderer.textures, cugar::Vector4f(1.0f));
433  material.specular *= bilinear_texture_lookup(geom.texture_coords, material.specular_map, renderer.textures, cugar::Vector4f(1.0f));
434  material.emissive *= bilinear_texture_lookup(geom.texture_coords, material.emissive_map, renderer.textures, cugar::Vector4f(1.0f));
435  material.diffuse_trans *= bilinear_texture_lookup(geom.texture_coords, material.diffuse_trans_map, renderer.textures, cugar::Vector4f(1.0f));
436 
437  #if 0
438  // perform bump-mapping
439  geom.normal_s += 0.05f * bump_mapping( geom_id, geom, material.bump_map, renderer );
440  geom.normal_s = cugar::normalize( geom.normal_s );
441  #endif
442 
443  in = cugar::normalize( _in );
444 
445  //if (dot(geom.normal_s, in) < 0.0f)
446  // geom.normal_s = -geom.normal_s;
447 
448  bsdf = Bsdf(kParticleTransport, renderer, material);
449  }
450 
451  FERMAT_HOST_DEVICE
452  void setup(
453  const cugar::Vector3f& _in,
454  const VertexGeometryId& _v,
455  const cugar::Vector3f& _alpha,
456  const TempPathWeights& _weights,
457  const uint32 _depth,
458  const RenderingContextView& renderer)
459  {
460  geom_id = _v;
461 
462  alpha = _alpha;
463  weights = _weights;
464  depth = _depth;
465  //assert(depth);
466 
467  FERMAT_ASSERT(_v.prim_id < (uint32)renderer.mesh.num_triangles);
468  setup_differential_geometry(renderer.mesh, _v, &geom);
469 
470  // fetch the material
471  const int material_id = renderer.mesh.material_indices[_v.prim_id];
472 
473  material = renderer.mesh.materials[material_id];
474 
475  // perform all texture lookups
476  material.diffuse *= bilinear_texture_lookup(geom.texture_coords, material.diffuse_map, renderer.textures, cugar::Vector4f(1.0f));
477  material.specular *= bilinear_texture_lookup(geom.texture_coords, material.specular_map, renderer.textures, cugar::Vector4f(1.0f));
478  material.emissive *= bilinear_texture_lookup(geom.texture_coords, material.emissive_map, renderer.textures, cugar::Vector4f(1.0f));
479  material.diffuse_trans *= bilinear_texture_lookup(geom.texture_coords, material.diffuse_trans_map, renderer.textures, cugar::Vector4f(1.0f));
480 
481  #if 0
482  // perform bump-mapping
483  geom.normal_s += 0.05f * bump_mapping( geom_id, geom, material.bump_map, renderer );
484  geom.normal_s = cugar::normalize( geom.normal_s );
485  #endif
486 
487  in = cugar::normalize( _in );
488 
489  //if (dot(geom.normal_s, in) < 0.0f)
490  // geom.normal_s = -geom.normal_s;
491 
492  bsdf = Bsdf(kParticleTransport, renderer, material);
493 
494  // compute the MIS terms for the next iteration
495  prev_G_prime = fabsf(dot(in, geom.normal_s)) / fmaxf(cugar::square_length(_in), MIN_G_DENOM);
496 
497  prev_pG = pdf_product( _weights.out_p, _weights.out_cos_theta * prev_G_prime );
498  pGp_sum = _weights.pGp_sum + mis_power(1 / pdf_product(_weights.pG, _weights.out_p));
499  }
500 
501  FERMAT_HOST_DEVICE
502  LightVertex() {}
503 
504  FERMAT_HOST_DEVICE
505  LightVertex(
506  const cugar::Vector4f& _pos,
507  const uint2& _packed_info1,
508  const uint4& _packed_info2,
509  const PathWeights& _weights,
510  const uint32 _depth,
511  const RenderingContextView& renderer)
512  {
513  setup( _pos, _packed_info1, _packed_info2, _weights, _depth, renderer );
514  }
515 
516  FERMAT_HOST_DEVICE
517  LightVertex(
518  const Ray& _ray,
519  const Hit& _hit,
520  const cugar::Vector3f& _alpha,
521  const TempPathWeights& _weights,
522  const uint32 _depth,
523  const RenderingContextView& renderer)
524  {
525  setup( _ray, _hit, _alpha, _weights, _depth, renderer );
526  }
527 
528  FERMAT_HOST_DEVICE
529  LightVertex(
530  const cugar::Vector3f& _in,
531  const VertexGeometryId& _v,
532  const cugar::Vector3f& _alpha,
533  const TempPathWeights& _weights,
534  const uint32 _depth,
535  const RenderingContextView& renderer)
536  {
537  setup( _in, _v, _alpha, _weights, _depth, renderer );
538  }
539 
551  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
552  bool sample(
553  const float z[3],
554  Bsdf::ComponentType& out_comp,
555  cugar::Vector3f& out,
556  float& out_p,
557  float& out_p_proj,
558  cugar::Vector3f& out_g,
559  bool RR = true,
560  bool evaluate_full_bsdf = false,
561  const Bsdf::ComponentType components = Bsdf::kAllComponents) const
562  {
563  return bsdf.sample( geom, z, in, out_comp, out, out_p, out_p_proj, out_g, RR, evaluate_full_bsdf, components );
564  }
565 
566  VertexGeometryId geom_id;
567  VertexGeometry geom;
568  cugar::Vector3f in;
569  cugar::Vector3f alpha;
570  PathWeights weights;
571  uint32 depth;
572  MeshMaterial material;
573  Edf edf;
574  Bsdf bsdf;
575  float prev_G_prime;
576  float prev_pG;
577  float pGp_sum;
578 };
579 
583 struct EyeVertex
584 {
585  template <typename RayType>
586  FERMAT_HOST_DEVICE
587  void setup(
588  const RayType& ray,
589  const Hit& hit,
590  const cugar::Vector3f& _alpha,
591  const TempPathWeights& _weights,
592  const uint32 _depth,
593  const RenderingContextView& renderer,
594  const float min_roughness = 0.0f)
595  {
596  geom_id.prim_id = hit.triId;
597  geom_id.uv = cugar::Vector2f(hit.u, hit.v);
598 
599  alpha = _alpha;
600  weights = _weights;
601  depth = _depth;
602 
603  FERMAT_ASSERT(hit.triId < renderer.mesh.num_triangles);
604  setup_differential_geometry(renderer.mesh, hit.triId, hit.u, hit.v, &geom);
605 
606  #if !defined(BARYCENTRIC_HIT_POINT)
607  // reset the position using the ray
608  geom.position = cugar::Vector3f( ray.origin ) + hit.t * cugar::Vector3f( ray.dir );
609  #endif
610 
611  // fetch the material
612  const int material_id = renderer.mesh.material_indices[hit.triId];
613 
614  material = renderer.mesh.materials[material_id];
615 
616  // perform all texture lookups
617  material.diffuse *= bilinear_texture_lookup(geom.texture_coords, material.diffuse_map, renderer.textures, cugar::Vector4f(1.0f));
618  material.specular *= bilinear_texture_lookup(geom.texture_coords, material.specular_map, renderer.textures, cugar::Vector4f(1.0f));
619  material.emissive *= bilinear_texture_lookup(geom.texture_coords, material.emissive_map, renderer.textures, cugar::Vector4f(1.0f));
620  material.diffuse_trans *= bilinear_texture_lookup(geom.texture_coords, material.diffuse_trans_map, renderer.textures, cugar::Vector4f(1.0f));
621 
622  #if 0
623  // perform bump-mapping
624  geom.normal_s += 0.05f * bump_mapping( geom_id, geom, material.bump_map, renderer );
625  geom.normal_s = cugar::normalize( geom.normal_s );
626  #endif
627 
628  in = -cugar::normalize(cugar::Vector3f(ray.dir));
629 
630  //if (dot(geom.normal_s, in) < 0.0f)
631  // geom.normal_s = -geom.normal_s;
632 
633  const float mollification_factor = 1.0f; // depth ? float(1u << (4 + depth)) : 1.0f; // at the first bounce, we increase the roughness by a factor 32, at the second 64, and so on...
634  const float mollification_bias = 0.0f; // depth ? 0.05f : 0.0f;
635  bsdf = Bsdf(kRadianceTransport, renderer, material, mollification_factor, mollification_bias, min_roughness);
636 
637  // compute the MIS terms for the next iteration
638  prev_G_prime = fabsf(dot(in, geom.normal_s)) / (hit.t * hit.t); // the G' of the incoming edge
639 
640  prev_pG = pdf_product( weights.out_p, weights.out_cos_theta * prev_G_prime );
641  pGp_sum = weights.pGp_sum + mis_power(1 / pdf_product(weights.pG, weights.out_p));
642  }
643 
644  FERMAT_HOST_DEVICE
645  void setup(
646  const cugar::Vector3f& _in,
647  const VertexGeometryId& _v,
648  const cugar::Vector3f& _alpha,
649  const TempPathWeights& _weights,
650  const uint32 _depth,
651  const RenderingContextView& renderer)
652  {
653  geom_id = _v;
654  alpha = _alpha;
655  weights = _weights;
656  depth = _depth;
657  //assert(depth);
658 
659  FERMAT_ASSERT(_v.prim_id < uint32(renderer.mesh.num_triangles));
660  setup_differential_geometry(renderer.mesh, _v, &geom);
661 
662  // fetch the material
663  const int material_id = renderer.mesh.material_indices[_v.prim_id];
664 
665  material = renderer.mesh.materials[material_id];
666 
667  // perform all texture lookups
668  material.diffuse *= bilinear_texture_lookup(geom.texture_coords, material.diffuse_map, renderer.textures, cugar::Vector4f(1.0f));
669  material.specular *= bilinear_texture_lookup(geom.texture_coords, material.specular_map, renderer.textures, cugar::Vector4f(1.0f));
670  material.emissive *= bilinear_texture_lookup(geom.texture_coords, material.emissive_map, renderer.textures, cugar::Vector4f(1.0f));
671  material.diffuse_trans *= bilinear_texture_lookup(geom.texture_coords, material.diffuse_trans_map, renderer.textures, cugar::Vector4f(1.0f));
672 
673  #if 0
674  // perform bump-mapping
675  geom.normal_s += 0.05f * bump_mapping( geom_id, geom, material.bump_map, renderer );
676  geom.normal_s = cugar::normalize( geom.normal_s );
677  #endif
678 
679  in = cugar::normalize( _in );
680 
681  //if (dot(geom.normal_s, in) < 0.0f)
682  // geom.normal_s = -geom.normal_s;
683 
684  bsdf = Bsdf(kRadianceTransport, renderer, material);
685 
686  // compute the MIS terms for the next iteration
687  prev_G_prime = fabsf(dot(in, geom.normal_s)) / fmaxf(cugar::square_length(_in), MIN_G_DENOM);
688 
689  prev_pG = pdf_product( weights.out_p, weights.out_cos_theta * prev_G_prime );
690  pGp_sum = weights.pGp_sum + mis_power(1 / pdf_product(weights.pG, weights.out_p));
691  }
692 
693  FERMAT_HOST_DEVICE
694  EyeVertex() {}
695 
696  FERMAT_HOST_DEVICE
697  EyeVertex(
698  const Ray& _ray,
699  const Hit& _hit,
700  const cugar::Vector3f& _alpha,
701  const TempPathWeights& _weights,
702  const uint32 _depth,
703  const RenderingContextView& renderer)
704  {
705  setup( _ray, _hit, _alpha, _weights, _depth, renderer );
706  }
707 
708  FERMAT_HOST_DEVICE
709  EyeVertex(
710  const cugar::Vector3f& _in,
711  const VertexGeometryId& _v,
712  const cugar::Vector3f& _alpha,
713  const TempPathWeights& _weights,
714  const uint32 _depth,
715  const RenderingContextView& renderer)
716  {
717  setup( _in, _v, _alpha, _weights, _depth, renderer );
718  }
719 
731  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
732  bool sample(
733  const float z[3],
734  Bsdf::ComponentType& out_comp,
735  cugar::Vector3f& out,
736  float& out_p,
737  float& out_p_proj,
738  cugar::Vector3f& out_g,
739  bool RR = true,
740  bool evaluate_full_bsdf = false,
741  const Bsdf::ComponentType components = Bsdf::kAllComponents) const
742  {
743  return bsdf.sample( geom, z, in, out_comp, out, out_p, out_p_proj, out_g, RR, evaluate_full_bsdf, components );
744  }
745 
746  VertexGeometryId geom_id;
747  VertexGeometry geom;
748  cugar::Vector3f in;
749  cugar::Vector3f alpha;
750  TempPathWeights weights;
751  uint32 depth;
752  MeshMaterial material;
753  Bsdf bsdf;
754  float prev_G_prime;
755  float prev_pG;
756  float pGp_sum;
757 };
758 
767 FERMAT_HOST_DEVICE inline
768 void eval_connection_terms(const EyeVertex ev, const LightVertex& lv, cugar::Vector3f& out, cugar::Vector3f& f_conn, float& G, float& d)
769 {
770  // start evaluating the geometric term
771  const float d2 = fmaxf(MIN_G_DENOM, cugar::square_length(lv.geom.position - ev.geom.position));
772 
773  d = sqrtf(d2);
774 
775  // join the light sample with the current vertex
776  out = (lv.geom.position - ev.geom.position) / d;
777 
778  // evaluate the geometric term
779  G = fabsf(cugar::dot(out, ev.geom.normal_s) * cugar::dot(out, lv.geom.normal_s)) / d2;
780 
781  // evaluate the surface BSDF
782  const cugar::Vector3f f_s = ev.bsdf.f(ev.geom, ev.in, out);
783 
784  if (lv.depth == 0) // this is a primary VPL / light vertex
785  {
786  // build the local BSDF (EDF)
787  const Edf& light_bsdf = lv.edf;
788 
789  // evaluate the light's EDF and the surface BSDF
790  const cugar::Vector3f f_L = light_bsdf.f(lv.geom, lv.geom.position, -out);
791 
792  f_conn = f_L * f_s;
793  }
794  else
795  {
796  // build the local BSDF
797  const Bsdf& light_bsdf = lv.bsdf;
798 
799  // evaluate the light's EDF and the surface BSDF
800  const cugar::Vector3f f_L = light_bsdf.f(lv.geom, lv.in, -out);
801 
802  f_conn = f_L * f_s;
803  }
804 }
805 
815 FERMAT_HOST_DEVICE inline
816 void eval_connection_terms(const EyeVertex ev, const LightVertex& lv, cugar::Vector3f& out, cugar::Vector3f& f_conn, float& G, float& d, float& mis_w,
817  bool RR = true,
818  bool direct_lighting_nee = true,
819  bool direct_lighting_bsdf = true)
820 {
821  // start evaluating the geometric term
822  const float d2 = fmaxf(MIN_G_DENOM, cugar::square_length(lv.geom.position - ev.geom.position));
823 
824  d = sqrtf(d2);
825 
826  // join the light sample with the current vertex
827  out = (lv.geom.position - ev.geom.position) / d;
828 
829  // evaluate the geometric term
830  G = fabsf(cugar::dot(out, ev.geom.normal_s) * cugar::dot(out, lv.geom.normal_s)) / d2;
831 
832  // evaluate the surface BSDF
833  cugar::Vector3f f_s;
834  float p_s;
835  //f_s = ev.bsdf.f(ev.geom, ev.in, out);
836  //p_s = ev.bsdf.p(ev.geom, ev.in, out, cugar::kProjectedSolidAngle, RR);
837  ev.bsdf.f_and_p(ev.geom, ev.in, out, f_s, p_s, cugar::kProjectedSolidAngle, RR);
838 
839  const float prev_pGp = pdf_product( ev.prev_pG, p_s );
840 
841  if (lv.depth == 0) // this is a primary VPL / light vertex
842  {
843  // build the local BSDF (EDF)
844  const Edf& light_bsdf = lv.edf;
845 
846  // evaluate the light's EDF and the surface BSDF
847  const cugar::Vector3f f_L = light_bsdf.f(lv.geom, lv.geom.position, -out);
848  const float p_L = light_bsdf.p(lv.geom, lv.geom.position, -out, cugar::kProjectedSolidAngle);
849 
850  const float pGp = pdf_product( p_s, G, p_L ); // infinity checks are not really needed here... but just in case
851  const float next_pGp = pdf_product( p_L, lv.weights.pG );
852  mis_w =
853  mis_selector(
854  lv.depth + 1, ev.depth + 2,
855  (ev.depth == 0 && direct_lighting_bsdf == false) ? 1.0f :
856  bpt_mis(pGp, prev_pGp, next_pGp, ev.pGp_sum + lv.weights.pGp_sum));
857 
858  f_conn = f_L * f_s;
859  }
860  else
861  {
862  // build the local BSDF
863  const Bsdf& light_bsdf = lv.bsdf;
864 
865  // evaluate the light's EDF and the surface BSDF
866  cugar::Vector3f f_L;
867  float p_L;
868  //f_L = light_bsdf.f(lv.geom, lv.in, -out);
869  //p_L = light_bsdf.p(lv.geom, lv.in, -out, RR, cugar::kProjectedSolidAngle);
870  light_bsdf.f_and_p(lv.geom, lv.in, -out, f_L, p_L, cugar::kProjectedSolidAngle, RR);
871 
872  const float pGp = pdf_product( p_s, G, p_L ); // infinity checks are not really needed here... but just in case
873  const float next_pGp = pdf_product( p_L, lv.weights.pG );
874  mis_w =
875  mis_selector(
876  lv.depth + 1, ev.depth + 2,
877  bpt_mis(pGp, prev_pGp, next_pGp, ev.pGp_sum + lv.weights.pGp_sum));
878 
879  f_conn = f_L * f_s;
880  }
881 }
882 
892 FERMAT_HOST_DEVICE inline
893 void eval_connection_terms(const EyeVertex ev, const LightVertex& lv, cugar::Vector3f& out, cugar::Vector3f& f_s, cugar::Vector3f& f_L, float& G, float& d, float& mis_w,
894  bool RR = true,
895  bool direct_lighting_nee = true,
896  bool direct_lighting_bsdf = true)
897 {
898  // start evaluating the geometric term
899  const float d2 = fmaxf(MIN_G_DENOM, cugar::square_length(lv.geom.position - ev.geom.position));
900 
901  d = sqrtf(d2);
902 
903  // join the light sample with the current vertex
904  out = (lv.geom.position - ev.geom.position) / d;
905 
906  // evaluate the geometric term
907  G = fabsf(cugar::dot(out, ev.geom.normal_s) * cugar::dot(out, lv.geom.normal_s)) / d2;
908 
909  // evaluate the surface BSDF
910  float p_s;
911  //f_s = ev.bsdf.f(ev.geom, ev.in, out);
912  //p_s = ev.bsdf.p(ev.geom, ev.in, out, cugar::kProjectedSolidAngle, RR);
913  ev.bsdf.f_and_p(ev.geom, ev.in, out, f_s, p_s, cugar::kProjectedSolidAngle, RR);
914 
915  const float prev_pGp = pdf_product( ev.prev_pG, p_s );
916 
917  if (lv.depth == 0) // this is a primary VPL / light vertex
918  {
919  // build the local BSDF (EDF)
920  const Edf& light_bsdf = lv.edf;
921 
922  // evaluate the light's EDF and the surface BSDF
923  f_L = light_bsdf.f(lv.geom, lv.geom.position, -out);
924  const float p_L = light_bsdf.p(lv.geom, lv.geom.position, -out, cugar::kProjectedSolidAngle);
925 
926  const float pGp = pdf_product( p_s, G, p_L );
927  const float next_pGp = pdf_product( p_L, lv.weights.pG );
928  mis_w =
929  mis_selector(
930  lv.depth + 1, ev.depth + 2,
931  (ev.depth == 0 && direct_lighting_bsdf == false) ? 1.0f :
932  bpt_mis(pGp, prev_pGp, next_pGp, ev.pGp_sum + lv.weights.pGp_sum));
933  }
934  else
935  {
936  // build the local BSDF
937  const Bsdf& light_bsdf = lv.bsdf;
938 
939  // evaluate the light's EDF and the surface BSDF
940  float p_L;
941  //f_L = light_bsdf.f(lv.geom, lv.in, -out);
942  //p_L = light_bsdf.p(lv.geom, lv.in, -out, RR, cugar::kProjectedSolidAngle);
943  light_bsdf.f_and_p(lv.geom, lv.in, -out, f_L, p_L, cugar::kProjectedSolidAngle, RR);
944 
945  const float pGp = pdf_product( p_s, G, p_L );
946  const float next_pGp = pdf_product( p_L, lv.weights.pG );
947  mis_w =
948  mis_selector(
949  lv.depth + 1, ev.depth + 2,
950  bpt_mis(pGp, prev_pGp, next_pGp, ev.pGp_sum + lv.weights.pGp_sum));
951  }
952 }
953 
954 FERMAT_HOST_DEVICE inline
955 void eval_connection(
956  const EyeVertex ev, const LightVertex& lv, cugar::Vector3f& out, cugar::Vector3f& out_w, float& d,
957  bool RR = true,
958  bool direct_lighting_nee = true,
959  bool direct_lighting_bsdf = true)
960 {
961  // start evaluating the geometric term
962  const float d2 = fmaxf(MIN_G_DENOM, cugar::square_length(lv.geom.position - ev.geom.position));
963 
964  d = sqrtf(d2);
965 
966  // join the light sample with the current vertex
967  out = (lv.geom.position - ev.geom.position) / d;
968 
969  // evaluate the geometric term
970  const float G = fabsf(cugar::dot(out, ev.geom.normal_s) * cugar::dot(out, lv.geom.normal_s)) / d2;
971 
972  // evaluate the surface BSDF
973  cugar::Vector3f f_s;
974  float p_s;
975  //f_s = ev.bsdf.f(ev.geom, ev.in, out);
976  //p_s = ev.bsdf.p(ev.geom, ev.in, out, cugar::kProjectedSolidAngle, RR);
977  ev.bsdf.f_and_p(ev.geom, ev.in, out, f_s, p_s, cugar::kProjectedSolidAngle, RR);
978 
979  const float prev_pGp = pdf_product( ev.prev_pG, p_s );
980 
981  if (lv.depth == 0) // this is a primary VPL / light vertex
982  {
983  if (direct_lighting_nee == false)
984  out_w = cugar::Vector3f(0.0f);
985  else
986  {
987  // build the local BSDF (EDF)
988  const Edf& light_bsdf = lv.edf;
989 
990  // evaluate the light's EDF and the surface BSDF
991  const cugar::Vector3f f_L = light_bsdf.f(lv.geom, lv.geom.position, -out);
992  const float p_L = light_bsdf.p(lv.geom, lv.geom.position, -out, cugar::kProjectedSolidAngle);
993 
994  const float pGp = pdf_product( p_s, G, p_L );
995  const float next_pGp = pdf_product( p_L, lv.weights.pG );
996  const float mis_w =
997  mis_selector(
998  lv.depth + 1, ev.depth + 2,
999  (ev.depth == 0 && direct_lighting_bsdf == false) ? 1.0f :
1000  bpt_mis(pGp, prev_pGp, next_pGp, ev.pGp_sum + lv.weights.pGp_sum));
1001 
1002  // calculate the cumulative sample weight, equal to f_L * f_s * G / p
1003  out_w = ev.alpha * lv.alpha * f_L * f_s * G * mis_w;
1004  }
1005  }
1006  else
1007  {
1008  // build the local BSDF
1009  const Bsdf& light_bsdf = lv.bsdf;
1010 
1011  // evaluate the light's EDF and the surface BSDF
1012  cugar::Vector3f f_L;
1013  float p_L;
1014  //f_L = light_bsdf.f(lv.geom, lv.in, -out);
1015  //p_L = light_bsdf.p(lv.geom, lv.in, -out, RR, cugar::kProjectedSolidAngle);
1016  light_bsdf.f_and_p(lv.geom, lv.in, -out, f_L, p_L, cugar::kProjectedSolidAngle, RR);
1017 
1018  const float pGp = pdf_product( p_s, G, p_L );
1019  const float next_pGp = pdf_product( p_L, lv.weights.pG );
1020  const float mis_w =
1021  mis_selector(
1022  lv.depth + 1, ev.depth + 2,
1023  bpt_mis(pGp, prev_pGp, next_pGp, ev.pGp_sum + lv.weights.pGp_sum));
1024 
1025  // calculate the cumulative sample weight, equal to f_L * f_s * G / p
1026  out_w = ev.alpha * lv.alpha * f_L * f_s * G * mis_w;
1027  }
1028 }
1029 
1033 FERMAT_HOST_DEVICE inline
1035  const EyeVertex& ev, const RenderingContextView& renderer,
1036  bool direct_lighting_nee,
1037  bool indirect_lighting_nee,
1038  bool use_vpls)
1039 {
1040  VertexGeometry light_vertex_geom = ev.geom;
1041  float light_pdf;
1042  Edf light_edf;
1043 
1044  if (use_vpls)
1045  renderer.mesh_vpls.map(ev.geom_id.prim_id, ev.geom_id.uv, light_vertex_geom, &light_pdf, &light_edf);
1046  else
1047  renderer.mesh_light.map(ev.geom_id.prim_id, ev.geom_id.uv, light_vertex_geom, &light_pdf, &light_edf);
1048 
1049  // evaluate the edf's output along the incoming direction
1050  const cugar::Vector3f f_L = light_edf.f(light_vertex_geom, light_vertex_geom.position, ev.in);
1051  const float p_L = light_edf.p(light_vertex_geom, light_vertex_geom.position, ev.in, cugar::kProjectedSolidAngle);
1052 
1053  const float pGp = pdf_product( p_L, light_pdf );
1054  const float prev_pGp = pdf_product( ev.prev_pG, p_L );
1055  const float mis_w =
1056  mis_selector(
1057  0, ev.depth + 2,
1058  (ev.depth == 0 || pGp == 0.0f || (ev.depth == 1 && direct_lighting_nee == false) || (ev.depth > 1 && indirect_lighting_nee == false)) ? 1.0f :
1059  bpt_mis(pGp, prev_pGp, ev.pGp_sum));
1060 
1061  // and accumulate the weighted contribution
1062  return ev.alpha * f_L * mis_w;
1063 }
1064 
1068 template <typename VertexType>
1069 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
1070 bool scatter(
1071  const VertexType& v,
1072  const float z[3],
1073  Bsdf::ComponentType& out_component,
1074  cugar::Vector3f& out,
1075  float& out_p,
1076  float& out_p_proj,
1077  cugar::Vector3f& out_w,
1078  bool RR = true,
1079  bool output_alpha = true,
1080  bool evaluate_full_bsdf = false,
1081  Bsdf::ComponentType components = Bsdf::kAllComponents)
1082 {
1083  bool scattered = v.bsdf.sample(
1084  v.geom,
1085  z,
1086  v.in,
1087  out_component,
1088  out,
1089  out_p,
1090  out_p_proj,
1091  out_w,
1092  RR,
1093  evaluate_full_bsdf,
1094  components);
1095 
1096  if (output_alpha)
1097  out_w *= v.alpha;
1098 
1099  return scattered;
1100 }
1101 
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE float mis_power(const float w)
Definition: bpt_utils.h:70
CUGAR_HOST_DEVICE uint32 quantize(const float x, const uint32 n)
Definition: numbers.h:600
Definition: texture_reference.h:41
Definition: matrix.h:54
Definition: bpt_utils.h:110
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE uint4 pack_bsdf(const MeshMaterial &material)
Definition: bpt_utils.h:215
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE cugar::Vector3f bump_mapping(const VertexGeometryId &geom_id, const VertexGeometry &geom, const TextureReference &bump_map, const RenderingContextView &renderer)
Definition: bpt_utils.h:285
Definition: vertex.h:105
FERMAT_HOST_DEVICE cugar::Vector3f eval_incoming_emission(const EyeVertex &ev, const RenderingContextView &renderer, bool direct_lighting_nee, bool indirect_lighting_nee, bool use_vpls)
Definition: bpt_utils.h:1034
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE float unpack_bsdf_roughness(const uint4 packed_info)
Definition: bpt_utils.h:273
FERMAT_HOST_DEVICE void map(const uint32_t prim_id, const cugar::Vector2f &uv, VertexGeometry *geom, float *pdf, Edf *edf) const
Definition: lights.h:584
Defines various spherical mappings.
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE cugar::Vector3f unpack_bsdf_diffuse_trans(const uint4 packed_info)
Definition: bpt_utils.h:279
ComponentType
Definition: bsdf.h:139
Definition: MeshView.h:55
TransportType
Definition: bsdf.h:83
Definition: vertex.h:92
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE Bsdf unpack_bsdf(const RenderingContextView &renderer, const uint4 packed_info, const TransportType transport=kParticleTransport)
Definition: bpt_utils.h:240
FERMAT_HOST_DEVICE void setup_differential_geometry(const MeshView &mesh, const uint32 tri_id, const float u, const float v, VertexGeometry *geom, float *pdf=0)
Definition: mesh_utils.h:185
Definition: bpt_utils.h:131
Definition: bpt_utils.h:583
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE Vector3f f(const DifferentialGeometry &geometry, const Vector3f in, const Vector3f out) const
Definition: lambert_edf.h:60
FERMAT_FORCEINLINE FERMAT_HOST_DEVICE void f_and_p(const cugar::DifferentialGeometry &geometry, const cugar::Vector3f w_i, const cugar::Vector3f w_o, cugar::Vector3f *f, float *p, const cugar::SphericalMeasure measure=cugar::kProjectedSolidAngle, bool RR=true) const
Definition: bsdf.h:366
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE Edf unpack_edf(const uint4 packed_info)
Definition: bpt_utils.h:231
Definition: ray.h:42
Definition: ray.h:68
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE float p(const DifferentialGeometry &geometry, const Vector3f in, const Vector3f out, const SphericalMeasure measure=kProjectedSolidAngle) const
Definition: lambert_edf.h:80
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE bool scatter(const VertexType &v, const float z[3], Bsdf::ComponentType &out_component, cugar::Vector3f &out, float &out_p, float &out_p_proj, cugar::Vector3f &out_w, bool RR=true, bool output_alpha=true, bool evaluate_full_bsdf=false, Bsdf::ComponentType components=Bsdf::kAllComponents)
Definition: bpt_utils.h:1070
FERMAT_HOST_DEVICE void eval_connection_terms(const EyeVertex ev, const LightVertex &lv, cugar::Vector3f &out, cugar::Vector3f &f_conn, float &G, float &d)
Definition: bpt_utils.h:768
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE cugar::Vector3f unpack_bsdf_diffuse(const uint4 packed_info)
Definition: bpt_utils.h:261
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE Out binary_cast(const In in)
Definition: types.h:288
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE cugar::Vector3f unpack_direction(const uint32 packed_dir)
Definition: vertex.h:133
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE uint8 comp(const uchar2 a, const char c)
Definition: numbers.h:218
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE bool sample(const float z[3], Bsdf::ComponentType &out_comp, cugar::Vector3f &out, float &out_p, float &out_p_proj, cugar::Vector3f &out_g, bool RR=true, bool evaluate_full_bsdf=false, const Bsdf::ComponentType components=Bsdf::kAllComponents) const
Definition: bpt_utils.h:732
Definition: edf.h:49
Definition: bsdf.h:123
FERMAT_FORCEINLINE FERMAT_HOST_DEVICE cugar::Vector3f f(const cugar::DifferentialGeometry &geometry, const cugar::Vector3f w_i, const cugar::Vector3f w_o, const ComponentType components=kAllComponents) const
Definition: bsdf.h:312
Definition: renderer_view.h:80
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE cugar::Vector3f unpack_bsdf_specular(const uint4 packed_info)
Definition: bpt_utils.h:267
Definition: bpt_utils.h:311
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE bool sample(const float z[3], Bsdf::ComponentType &out_comp, cugar::Vector3f &out, float &out_p, float &out_p_proj, cugar::Vector3f &out_g, bool RR=true, bool evaluate_full_bsdf=false, const Bsdf::ComponentType components=Bsdf::kAllComponents) const
Definition: bpt_utils.h:552
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE uint4 pack_edf(const Edf &edf)
Definition: bpt_utils.h:189