1 
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9 // Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29 
30 #pragma once
31 
32 // appleseed.renderer headers.
33 #include "renderer/global/globaltypes.h"
34 #include "renderer/kernel/intersection/intersector.h"
35 #include "renderer/kernel/shading/shadingpoint.h"
36 #include "renderer/kernel/shading/shadingray.h"
37 #include "renderer/modeling/scene/visibilityflags.h"
38 
39 // appleseed.foundation headers.
40 #include "foundation/core/concepts/noncopyable.h"
41 #include "foundation/math/vector.h"
42 
43 // Standard headers.
44 #include <cstddef>
45 
46 // Forward declarations.
47 namespace renderer  { class Material;}
48 namespace renderer  { class OSLShaderGroupExec; }
49 namespace renderer  { class Scene; }
50 namespace renderer  { class ShadingContext; }
51 
52 namespace renderer
53 {
54 
55 //
56 // The Tracer class wraps the Intersector class and allows to compute
57 // visibility from a given point along a given direction, as well as
58 // point-to-point visibility. It automatically takes into account alpha
59 // transparency.
60 //
61 
62 class Tracer
63   : public foundation::NonCopyable
64 {
65   public:
66     // Constructors.
67     Tracer(
68         const Scene&                    scene,
69         const Intersector&              intersector,
70         OSLShaderGroupExec&             shadergroup_exec,
71         const float                     transparency_threshold = 0.001f,
72         const size_t                    max_iterations = 1000,
73         const bool                      print_details = true);
74 
75     // Compute the transmission in a given direction.
76     // Returns the transmission factor up to (but excluding) this occluder.
77     void trace_simple(
78         const ShadingContext&           shading_context,
79         const ShadingRay&               ray,
80         Spectrum&                       transmission);
81     void trace_simple(
82         const ShadingContext&           shading_context,
83         const ShadingPoint&             origin,
84         const ShadingRay&               ray,
85         Spectrum&                       transmission);
86 
87     // Compute the transmission between two points.
88     // Returns the transmission factor up to (but excluding) this occluder.
89     void trace_between_simple(
90         const ShadingContext&           shading_context,
91         const ShadingPoint&             origin,
92         const foundation::Vector3d&     target,
93         const VisibilityFlags::Type     ray_flags,
94         Spectrum&                       transmission);
95     void trace_between_simple(
96         const ShadingContext&           shading_context,
97         const ShadingPoint&             origin,
98         const foundation::Vector3d&     target,
99         const ShadingRay&               parent_ray,
100         const VisibilityFlags::Type     ray_flags,
101         Spectrum&                       transmission);
102     void trace_between_simple(
103         const ShadingContext&           shading_context,
104         const foundation::Vector3d&     origin,
105         const foundation::Vector3d&     target,
106         const ShadingRay&               parent_ray,
107         const VisibilityFlags::Type     ray_flags,
108         Spectrum&                       transmission);
109     void trace_between_simple(
110         const ShadingContext&           shading_context,
111         const foundation::Vector3d&     origin,
112         const foundation::Vector3d&     target,
113         const ShadingRay::Time&         ray_time,
114         const VisibilityFlags::Type     ray_flags,
115         const ShadingRay::DepthType     ray_depth,
116         Spectrum&                       transmission);
117 
118     // Compute the transmission in a given direction.
119     // Returns the intersection with the closest fully opaque occluder
120     // and the transmission factor up to (but excluding) this occluder,
121     // or a miss if there is no fully opaque occluder in this direction.
122     const ShadingPoint& trace_full(
123         const ShadingContext&           shading_context,
124         const ShadingRay&               ray,
125         Spectrum&                       transmission);
126     const ShadingPoint& trace_full(
127         const ShadingContext&           shading_context,
128         const ShadingPoint&             origin,
129         const ShadingRay&               ray,
130         Spectrum&                       transmission);
131 
132     // Compute the transmission between two points.
133     // Returns the intersection with the closest fully opaque occluder
134     // and the transmission factor up to (but excluding) this occluder,
135     // or a miss if there is no fully opaque occluder in the segment [origin, target).
136     const ShadingPoint& trace_between_full(
137         const ShadingContext&           shading_context,
138         const ShadingPoint&             origin,
139         const foundation::Vector3d&     target,
140         const VisibilityFlags::Type     ray_flags,
141         Spectrum&                       transmission);
142     const ShadingPoint& trace_between_full(
143         const ShadingContext&           shading_context,
144         const ShadingPoint&             origin,
145         const foundation::Vector3d&     target,
146         const ShadingRay&               parent_ray,
147         const VisibilityFlags::Type     ray_flags,
148         Spectrum&                       transmission);
149     const ShadingPoint& trace_between_full(
150         const ShadingContext&           shading_context,
151         const foundation::Vector3d&     origin,
152         const foundation::Vector3d&     target,
153         const ShadingRay&               parent_ray,
154         const VisibilityFlags::Type     ray_flags,
155         Spectrum&                       transmission);
156     const ShadingPoint& trace_between_full(
157         const ShadingContext&           shading_context,
158         const foundation::Vector3d&     origin,
159         const foundation::Vector3d&     target,
160         const ShadingRay::Time&         ray_time,
161         const VisibilityFlags::Type     ray_flags,
162         const ShadingRay::DepthType     ray_depth,
163         Spectrum&                       transmission);
164 
165   private:
166     const Intersector&                  m_intersector;
167     OSLShaderGroupExec&                 m_shadergroup_exec;
168     const bool                          m_assume_no_alpha_mapping;
169     const bool                          m_assume_no_participating_media;
170     const float                         m_transmission_threshold;
171     const size_t                        m_max_iterations;
172     ShadingPoint                        m_shading_points[2];
173 
174     const ShadingPoint& do_trace(
175         const ShadingContext&           shading_context,
176         const ShadingRay&               ray,
177         Spectrum&                       transmission,
178         const ShadingPoint*             parent_shading_point);
179 
180     const ShadingPoint& do_trace_between(
181         const ShadingContext&           shading_context,
182         const foundation::Vector3d&     target,
183         const ShadingRay&               ray,
184         Spectrum&                       transmission,
185         const ShadingPoint*             parent_shading_point);
186 
187     void evaluate_alpha(
188         const Material&                 material,
189         const ShadingPoint&             shading_point,
190         Alpha&                          alpha) const;
191 };
192 
193 
194 //
195 // Tracer class implementation.
196 //
197 
trace_simple(const ShadingContext & shading_context,const ShadingRay & ray,Spectrum & transmission)198 inline void Tracer::trace_simple(
199     const ShadingContext&               shading_context,
200     const ShadingRay&                   ray,
201     Spectrum&                           transmission)
202 {
203     if (m_assume_no_alpha_mapping && m_assume_no_participating_media)
204         transmission.set(m_intersector.trace_probe(ray) ? 0.0f : 1.0f);
205     else
206     {
207         const ShadingPoint& shading_point =
208             trace_full(
209                 shading_context,
210                 ray,
211                 transmission);
212 
213         if (shading_point.hit_surface())
214             transmission.set(0.0f);
215     }
216 }
217 
trace_simple(const ShadingContext & shading_context,const ShadingPoint & origin,const ShadingRay & ray,Spectrum & transmission)218 inline void Tracer::trace_simple(
219     const ShadingContext&               shading_context,
220     const ShadingPoint&                 origin,
221     const ShadingRay&                   ray,
222     Spectrum&                           transmission)
223 {
224     if (m_assume_no_alpha_mapping && m_assume_no_participating_media)
225         transmission.set(m_intersector.trace_probe(ray, &origin) ? 0.0f : 1.0f);
226     else
227     {
228         const ShadingPoint& shading_point =
229             trace_full(
230                 shading_context,
231                 origin,
232                 ray,
233                 transmission);
234 
235         if (shading_point.hit_surface())
236             transmission.set(0.0f);
237     }
238 }
239 
trace_between_simple(const ShadingContext & shading_context,const ShadingPoint & origin,const foundation::Vector3d & target,const VisibilityFlags::Type ray_flags,Spectrum & transmission)240 inline void Tracer::trace_between_simple(
241     const ShadingContext&               shading_context,
242     const ShadingPoint&                 origin,
243     const foundation::Vector3d&         target,
244     const VisibilityFlags::Type         ray_flags,
245     Spectrum&                           transmission)
246 {
247     if (m_assume_no_alpha_mapping && m_assume_no_participating_media)
248     {
249         const foundation::Vector3d direction = target - origin.get_point();
250         const double dist = foundation::norm(direction);
251 
252         const ShadingRay ray(
253             origin.get_biased_point(direction),
254             direction / dist,
255             0.0,                        // ray tmin
256             dist * (1.0 - 1.0e-6),      // ray tmax
257             origin.get_time(),
258             ray_flags,
259             origin.get_ray().m_depth + 1);
260 
261         transmission.set(m_intersector.trace_probe(ray, &origin) ? 0.0f : 1.0f);
262     }
263     else
264     {
265         const ShadingPoint& shading_point =
266             trace_between_full(
267                 shading_context,
268                 origin,
269                 target,
270                 ray_flags,
271                 transmission);
272 
273         if (shading_point.hit_surface())
274             transmission.set(0.0f);
275     }
276 }
277 
trace_between_simple(const ShadingContext & shading_context,const ShadingPoint & origin,const foundation::Vector3d & target,const ShadingRay & parent_ray,const VisibilityFlags::Type ray_flags,Spectrum & transmission)278 inline void Tracer::trace_between_simple(
279     const ShadingContext&               shading_context,
280     const ShadingPoint&                 origin,
281     const foundation::Vector3d&         target,
282     const ShadingRay&                   parent_ray,
283     const VisibilityFlags::Type         ray_flags,
284     Spectrum&                           transmission)
285 {
286     if (m_assume_no_alpha_mapping && m_assume_no_participating_media)
287     {
288         const foundation::Vector3d direction = target - origin.get_point();
289         const double dist = foundation::norm(direction);
290 
291         const ShadingRay ray(
292             origin.get_biased_point(direction),
293             direction / dist,
294             0.0,                        // ray tmin
295             dist * (1.0 - 1.0e-6),      // ray tmax
296             parent_ray.m_time,
297             ray_flags,
298             parent_ray.m_depth);
299 
300         transmission.set(m_intersector.trace_probe(ray, &origin) ? 0.0f : 1.0f);
301     }
302     else
303     {
304         const ShadingPoint& shading_point =
305             trace_between_full(
306                 shading_context,
307                 origin,
308                 target,
309                 parent_ray,
310                 ray_flags,
311                 transmission);
312 
313         if (shading_point.hit_surface())
314             transmission.set(0.0f);
315     }
316 }
317 
trace_between_simple(const ShadingContext & shading_context,const foundation::Vector3d & origin,const foundation::Vector3d & target,const ShadingRay & parent_ray,const VisibilityFlags::Type ray_flags,Spectrum & transmission)318 inline void Tracer::trace_between_simple(
319     const ShadingContext&               shading_context,
320     const foundation::Vector3d&         origin,
321     const foundation::Vector3d&         target,
322     const ShadingRay&                   parent_ray,
323     const VisibilityFlags::Type         ray_flags,
324     Spectrum&                           transmission)
325 {
326     if (m_assume_no_alpha_mapping && m_assume_no_participating_media)
327     {
328         const foundation::Vector3d direction = target - origin;
329         const double dist = foundation::norm(direction);
330 
331         const ShadingRay ray(
332             origin,
333             direction / dist,
334             0.0,                        // ray tmin
335             dist * (1.0 - 1.0e-6),      // ray tmax
336             parent_ray.m_time,
337             ray_flags,
338             parent_ray.m_depth);
339 
340         transmission.set(m_intersector.trace_probe(ray) ? 0.0f : 1.0f);
341     }
342     else
343     {
344         const ShadingPoint& shading_point =
345             trace_between_full(
346                 shading_context,
347                 origin,
348                 target,
349                 parent_ray,
350                 ray_flags,
351                 transmission);
352 
353         if (shading_point.hit_surface())
354             transmission.set(0.0f);
355     }
356 }
357 
trace_between_simple(const ShadingContext & shading_context,const foundation::Vector3d & origin,const foundation::Vector3d & target,const ShadingRay::Time & ray_time,const VisibilityFlags::Type ray_flags,const ShadingRay::DepthType ray_depth,Spectrum & transmission)358 inline void Tracer::trace_between_simple(
359     const ShadingContext&               shading_context,
360     const foundation::Vector3d&         origin,
361     const foundation::Vector3d&         target,
362     const ShadingRay::Time&             ray_time,
363     const VisibilityFlags::Type         ray_flags,
364     const ShadingRay::DepthType         ray_depth,
365     Spectrum&                           transmission)
366 {
367     if (m_assume_no_alpha_mapping && m_assume_no_participating_media)
368     {
369         const foundation::Vector3d direction = target - origin;
370         const double dist = foundation::norm(direction);
371 
372         const ShadingRay ray(
373             origin,
374             direction / dist,
375             0.0,                        // ray tmin
376             dist * (1.0 - 1.0e-6),      // ray tmax
377             ray_time,
378             ray_flags,
379             ray_depth);
380 
381         transmission.set(m_intersector.trace_probe(ray) ? 0.0f : 1.0f);
382     }
383     else
384     {
385         const ShadingPoint& shading_point =
386             trace_between_full(
387                 shading_context,
388                 origin,
389                 target,
390                 ray_time,
391                 ray_flags,
392                 ray_depth,
393                 transmission);
394 
395         if (shading_point.hit_surface())
396             transmission.set(0.0f);
397     }
398 }
399 
trace_full(const ShadingContext & shading_context,const ShadingRay & ray,Spectrum & transmission)400 inline const ShadingPoint& Tracer::trace_full(
401     const ShadingContext&               shading_context,
402     const ShadingRay&                   ray,
403     Spectrum&                           transmission)
404 {
405     return
406         do_trace(
407             shading_context,
408             ray,
409             transmission,
410             nullptr);
411 }
412 
trace_full(const ShadingContext & shading_context,const ShadingPoint & origin,const ShadingRay & ray,Spectrum & transmission)413 inline const ShadingPoint& Tracer::trace_full(
414     const ShadingContext&               shading_context,
415     const ShadingPoint&                 origin,
416     const ShadingRay&                   ray,
417     Spectrum&                           transmission)
418 {
419     return
420         do_trace(
421             shading_context,
422             ray,
423             transmission,
424             &origin);
425 }
426 
trace_between_full(const ShadingContext & shading_context,const ShadingPoint & origin,const foundation::Vector3d & target,const VisibilityFlags::Type ray_flags,Spectrum & transmission)427 inline const ShadingPoint& Tracer::trace_between_full(
428     const ShadingContext&               shading_context,
429     const ShadingPoint&                 origin,
430     const foundation::Vector3d&         target,
431     const VisibilityFlags::Type         ray_flags,
432     Spectrum&                           transmission)
433 {
434     const foundation::Vector3d direction = target - origin.get_point();
435     const double dist = foundation::norm(direction);
436 
437     ShadingRay ray(
438         origin.get_biased_point(direction),
439         direction / dist,
440         0.0,
441         dist * (1.0 - 1.0e-6),
442         origin.get_ray().m_time,
443         ray_flags,
444         origin.get_ray().m_depth + 1);
445 
446     return
447         do_trace_between(
448             shading_context,
449             target,
450             ray,
451             transmission,
452             &origin);
453 }
454 
trace_between_full(const ShadingContext & shading_context,const ShadingPoint & origin,const foundation::Vector3d & target,const ShadingRay & parent_ray,const VisibilityFlags::Type ray_flags,Spectrum & transmission)455 inline const ShadingPoint& Tracer::trace_between_full(
456     const ShadingContext&               shading_context,
457     const ShadingPoint&                 origin,
458     const foundation::Vector3d&         target,
459     const ShadingRay&                   parent_ray,
460     const VisibilityFlags::Type         ray_flags,
461     Spectrum&                           transmission)
462 {
463     const foundation::Vector3d direction = target - origin.get_point();
464     const double dist = foundation::norm(direction);
465 
466     ShadingRay ray(
467         origin.get_biased_point(direction),
468         direction / dist,
469         0.0,
470         dist * (1.0 - 1.0e-6),
471         parent_ray.m_time,
472         ray_flags,
473         parent_ray.m_depth + 1);
474 
475     ray.copy_media_from(parent_ray);
476 
477     return
478         do_trace_between(
479             shading_context,
480             target,
481             ray,
482             transmission,
483             &origin);
484 }
485 
trace_between_full(const ShadingContext & shading_context,const foundation::Vector3d & origin,const foundation::Vector3d & target,const ShadingRay & parent_ray,const VisibilityFlags::Type ray_flags,Spectrum & transmission)486 inline const ShadingPoint& Tracer::trace_between_full(
487     const ShadingContext&               shading_context,
488     const foundation::Vector3d&         origin,
489     const foundation::Vector3d&         target,
490     const ShadingRay&                   parent_ray,
491     const VisibilityFlags::Type         ray_flags,
492     Spectrum&                           transmission)
493 {
494     const double dist = foundation::norm(target - origin);
495 
496     ShadingRay ray(
497         origin,
498         (target - origin) / dist,
499         0.0,
500         dist * (1.0 - 1.0e-6),
501         parent_ray.m_time,
502         ray_flags,
503         parent_ray.m_depth + 1);
504 
505     ray.copy_media_from(parent_ray);
506 
507     return
508         do_trace_between(
509             shading_context,
510             target,
511             ray,
512             transmission,
513             nullptr);
514 }
515 
trace_between_full(const ShadingContext & shading_context,const foundation::Vector3d & origin,const foundation::Vector3d & target,const ShadingRay::Time & ray_time,const VisibilityFlags::Type ray_flags,const ShadingRay::DepthType ray_depth,Spectrum & transmission)516 inline const ShadingPoint& Tracer::trace_between_full(
517     const ShadingContext&               shading_context,
518     const foundation::Vector3d&         origin,
519     const foundation::Vector3d&         target,
520     const ShadingRay::Time&             ray_time,
521     const VisibilityFlags::Type         ray_flags,
522     const ShadingRay::DepthType         ray_depth,
523     Spectrum&                           transmission)
524 {
525     const double dist = foundation::norm(target - origin);
526 
527     const ShadingRay ray(
528         origin,
529         (target - origin) / dist,
530         dist * 1.0e-6,
531         dist * (1.0 - 1.0e-6),
532         ray_time,
533         ray_flags,
534         ray_depth + 1);
535 
536     return
537         do_trace_between(
538             shading_context,
539             target,
540             ray,
541             transmission,
542             nullptr);
543 }
544 
545 }   // namespace renderer
546