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