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 // Interface header.
31 #include "triangletree.h"
32 
33 // appleseed.renderer headers.
34 #include "renderer/global/globallogger.h"
35 #include "renderer/kernel/intersection/intersectionfilter.h"
36 #include "renderer/kernel/intersection/triangleencoder.h"
37 #include "renderer/kernel/intersection/triangleitemhandler.h"
38 #include "renderer/kernel/intersection/trianglevertexinfo.h"
39 #include "renderer/kernel/shading/shadingpoint.h"
40 #include "renderer/kernel/shading/shadingray.h"
41 #include "renderer/kernel/tessellation/statictessellation.h"
42 #include "renderer/kernel/texturing/texturecache.h"
43 #include "renderer/kernel/texturing/texturestore.h"
44 #include "renderer/modeling/entity/entity.h"
45 #include "renderer/modeling/material/material.h"
46 #include "renderer/modeling/object/meshobject.h"
47 #include "renderer/modeling/object/object.h"
48 #include "renderer/modeling/object/triangle.h"
49 #include "renderer/modeling/scene/assembly.h"
50 #include "renderer/modeling/scene/containers.h"
51 #include "renderer/modeling/scene/objectinstance.h"
52 #include "renderer/utility/bbox.h"
53 #include "renderer/utility/messagecontext.h"
54 #include "renderer/utility/paramarray.h"
55 
56 // appleseed.foundation headers.
57 #include "foundation/math/area.h"
58 #include "foundation/math/intersection/aabbtriangle.h"
59 #include "foundation/math/scalar.h"
60 #include "foundation/math/transform.h"
61 #include "foundation/math/treeoptimizer.h"
62 #include "foundation/math/vector.h"
63 #include "foundation/platform/system.h"
64 #include "foundation/platform/timers.h"
65 #include "foundation/utility/alignedallocator.h"
66 #include "foundation/utility/api/apistring.h"
67 #include "foundation/utility/foreach.h"
68 #include "foundation/utility/makevector.h"
69 #include "foundation/utility/memory.h"
70 #include "foundation/utility/statistics.h"
71 #include "foundation/utility/stopwatch.h"
72 #include "foundation/utility/string.h"
73 
74 // Standard headers.
75 #include <algorithm>
76 #include <cassert>
77 #include <set>
78 #include <string>
79 
80 using namespace foundation;
81 using namespace std;
82 
83 namespace renderer
84 {
85 
86 //
87 // TriangleTree class implementation.
88 //
89 
90 namespace
91 {
92     template <typename Vector>
increase_capacity(Vector * vec,const size_t count)93     void increase_capacity(Vector* vec, const size_t count)
94     {
95         if (vec)
96             vec->reserve(vec->capacity() + count);
97     }
98 
99     template <typename Vector>
assert_empty(Vector * vec)100     void assert_empty(Vector* vec)
101     {
102         assert(vec == 0 || vec->empty());
103     }
104 
105     template <typename AABBType>
collect_static_triangles(const GAABB3 & tree_bbox,const ObjectInstance & object_instance,const size_t object_instance_index,const StaticTriangleTess & tess,const bool save_memory,vector<TriangleKey> * triangle_keys,vector<TriangleVertexInfo> * triangle_vertex_infos,vector<GVector3> * triangle_vertices,vector<AABBType> * triangle_bboxes,size_t & triangle_vertex_count)106     void collect_static_triangles(
107         const GAABB3&                   tree_bbox,
108         const ObjectInstance&           object_instance,
109         const size_t                    object_instance_index,
110         const StaticTriangleTess&       tess,
111         const bool                      save_memory,
112         vector<TriangleKey>*            triangle_keys,
113         vector<TriangleVertexInfo>*     triangle_vertex_infos,
114         vector<GVector3>*               triangle_vertices,
115         vector<AABBType>*               triangle_bboxes,
116         size_t&                         triangle_vertex_count)
117     {
118         const Transformd& transform = object_instance.get_transform();
119         const size_t triangle_count = tess.m_primitives.size();
120 
121         if (save_memory)
122         {
123             // Reserve memory.
124             increase_capacity(triangle_keys, triangle_count);
125             increase_capacity(triangle_vertex_infos, triangle_count);
126             increase_capacity(triangle_vertices, triangle_count * 3);
127             increase_capacity(triangle_bboxes, triangle_count);
128         }
129 
130         for (size_t i = 0; i < triangle_count; ++i)
131         {
132             // Fetch the triangle.
133             const Triangle& triangle = tess.m_primitives[i];
134 
135             // Retrieve the object space vertices of the triangle.
136             const GVector3& v0_os = tess.m_vertices[triangle.m_v0];
137             const GVector3& v1_os = tess.m_vertices[triangle.m_v1];
138             const GVector3& v2_os = tess.m_vertices[triangle.m_v2];
139 
140             // Ignore degenerate triangles.
141             if (square_area(v0_os, v1_os, v2_os) == GScalar(0.0))
142                 continue;
143 
144             // Transform triangle vertices to assembly space.
145             const GVector3 v0 = transform.point_to_parent(v0_os);
146             const GVector3 v1 = transform.point_to_parent(v1_os);
147             const GVector3 v2 = transform.point_to_parent(v2_os);
148 
149             // Ignore degenerate triangles.
150             if (square_area(v0, v1, v2) == GScalar(0.0))
151                 continue;
152 
153             // Compute the bounding box of the triangle.
154             GAABB3 triangle_bbox;
155             triangle_bbox.invalidate();
156             triangle_bbox.insert(v0);
157             triangle_bbox.insert(v1);
158             triangle_bbox.insert(v2);
159 
160             // Ignore triangles that don't intersect the tree.
161             if (!intersect(tree_bbox, v0, v1, v2))
162                 continue;
163 
164             // Store the triangle key.
165             if (triangle_keys)
166             {
167                 triangle_keys->push_back(
168                     TriangleKey(
169                         object_instance_index,
170                         i,
171                         triangle.m_pa));
172             }
173 
174             // Store the index of the first triangle vertex and the number of motion segments.
175             if (triangle_vertex_infos)
176             {
177                 triangle_vertex_infos->push_back(
178                     TriangleVertexInfo(
179                         triangle_vertex_count,
180                         0,
181                         object_instance.get_vis_flags()));
182             }
183 
184             // Store the triangle vertices.
185             if (triangle_vertices)
186             {
187                 triangle_vertices->push_back(v0);
188                 triangle_vertices->push_back(v1);
189                 triangle_vertices->push_back(v2);
190             }
191             triangle_vertex_count += 3;
192 
193             // Store the triangle bounding box.
194             if (triangle_bboxes)
195                 triangle_bboxes->push_back(AABBType(triangle_bbox));
196         }
197     }
198 
199     template <typename AABBType>
collect_moving_triangles(const GAABB3 & tree_bbox,const ObjectInstance & object_instance,const size_t object_instance_index,const StaticTriangleTess & tess,const double time,const bool save_memory,vector<TriangleKey> * triangle_keys,vector<TriangleVertexInfo> * triangle_vertex_infos,vector<GVector3> * triangle_vertices,vector<AABBType> * triangle_bboxes,size_t & triangle_vertex_count)200     void collect_moving_triangles(
201         const GAABB3&                   tree_bbox,
202         const ObjectInstance&           object_instance,
203         const size_t                    object_instance_index,
204         const StaticTriangleTess&       tess,
205         const double                    time,
206         const bool                      save_memory,
207         vector<TriangleKey>*            triangle_keys,
208         vector<TriangleVertexInfo>*     triangle_vertex_infos,
209         vector<GVector3>*               triangle_vertices,
210         vector<AABBType>*               triangle_bboxes,
211         size_t&                         triangle_vertex_count)
212     {
213         const Transformd& transform = object_instance.get_transform();
214         const size_t motion_segment_count = tess.get_motion_segment_count();
215         const size_t triangle_count = tess.m_primitives.size();
216 
217         if (save_memory)
218         {
219             // Reserve memory.
220             increase_capacity(triangle_keys, triangle_count);
221             increase_capacity(triangle_vertex_infos, triangle_count);
222             increase_capacity(triangle_vertices, triangle_count * 3 * (motion_segment_count + 1));
223             increase_capacity(triangle_bboxes, triangle_count);
224         }
225 
226         vector<GAABB3> tri_pose_bboxes(motion_segment_count + 1);
227 
228         for (size_t i = 0; i < triangle_count; ++i)
229         {
230             // Fetch the triangle.
231             const Triangle& triangle = tess.m_primitives[i];
232 
233             // Retrieve the object space vertices of the triangle.
234             const GVector3& v0_os = tess.m_vertices[triangle.m_v0];
235             const GVector3& v1_os = tess.m_vertices[triangle.m_v1];
236             const GVector3& v2_os = tess.m_vertices[triangle.m_v2];
237 
238             // Transform triangle vertices to assembly space.
239             const GVector3 v0 = transform.point_to_parent(v0_os);
240             const GVector3 v1 = transform.point_to_parent(v1_os);
241             const GVector3 v2 = transform.point_to_parent(v2_os);
242 
243             // Compute the bounding box of the triangle for each of its pose.
244             tri_pose_bboxes[0].invalidate();
245             tri_pose_bboxes[0].insert(v0);
246             tri_pose_bboxes[0].insert(v1);
247             tri_pose_bboxes[0].insert(v2);
248             for (size_t m = 0; m < motion_segment_count; ++m)
249             {
250                 tri_pose_bboxes[m + 1].invalidate();
251                 tri_pose_bboxes[m + 1].insert(transform.point_to_parent(tess.get_vertex_pose(triangle.m_v0, m)));
252                 tri_pose_bboxes[m + 1].insert(transform.point_to_parent(tess.get_vertex_pose(triangle.m_v1, m)));
253                 tri_pose_bboxes[m + 1].insert(transform.point_to_parent(tess.get_vertex_pose(triangle.m_v2, m)));
254             }
255 
256             // Compute the bounding box of the triangle over its entire motion.
257             const GAABB3 triangle_motion_bbox =
258                 compute_union<GAABB3>(tri_pose_bboxes.begin(), tri_pose_bboxes.end());
259 
260             // Ignore triangles that are degenerate over their entire motion.
261             if (triangle_motion_bbox.rank() < 2)
262                 continue;
263 
264             // Ignore triangles that don't ever intersect the tree.
265             if (!GAABB3::overlap(tree_bbox, triangle_motion_bbox))
266                 continue;
267 
268             // Compute the bounding box of the triangle for the time value passed in argument.
269             const GAABB3 triangle_midtime_bbox =
270                 interpolate<GAABB3>(tri_pose_bboxes.begin(), tri_pose_bboxes.end(), time);
271 
272             // Ignore triangles with an empty bounding box.
273             if (triangle_midtime_bbox.rank() < 2)
274                 continue;
275 
276             // Store the triangle key.
277             if (triangle_keys)
278             {
279                 triangle_keys->push_back(
280                     TriangleKey(
281                         object_instance_index,
282                         i,
283                         triangle.m_pa));
284             }
285 
286             // Store the index of the first triangle vertex and the number of motion segments.
287             if (triangle_vertex_infos)
288             {
289                 triangle_vertex_infos->push_back(
290                     TriangleVertexInfo(
291                         triangle_vertex_count,
292                         motion_segment_count,
293                         object_instance.get_vis_flags()));
294             }
295 
296             // Store the triangle vertices.
297             if (triangle_vertices)
298             {
299                 triangle_vertices->push_back(v0);
300                 triangle_vertices->push_back(v1);
301                 triangle_vertices->push_back(v2);
302                 for (size_t m = 0; m < motion_segment_count; ++m)
303                 {
304                     triangle_vertices->push_back(transform.point_to_parent(tess.get_vertex_pose(triangle.m_v0, m)));
305                     triangle_vertices->push_back(transform.point_to_parent(tess.get_vertex_pose(triangle.m_v1, m)));
306                     triangle_vertices->push_back(transform.point_to_parent(tess.get_vertex_pose(triangle.m_v2, m)));
307                 }
308             }
309             triangle_vertex_count += (motion_segment_count + 1) * 3;
310 
311             // Store the bounding box of the triangle for the time value passed in argument.
312             if (triangle_bboxes)
313                 triangle_bboxes->push_back(AABBType(triangle_midtime_bbox));
314         }
315     }
316 
317     template <typename AABBType>
collect_triangles(const TriangleTree::Arguments & arguments,const double time,const bool save_memory,vector<TriangleKey> * triangle_keys,vector<TriangleVertexInfo> * triangle_vertex_infos,vector<GVector3> * triangle_vertices,vector<AABBType> * triangle_bboxes)318     void collect_triangles(
319         const TriangleTree::Arguments&  arguments,
320         const double                    time,
321         const bool                      save_memory,
322         vector<TriangleKey>*            triangle_keys,
323         vector<TriangleVertexInfo>*     triangle_vertex_infos,
324         vector<GVector3>*               triangle_vertices,
325         vector<AABBType>*               triangle_bboxes)
326     {
327         assert_empty(triangle_keys);
328         assert_empty(triangle_vertex_infos);
329         assert_empty(triangle_vertices);
330         assert_empty(triangle_bboxes);
331 
332         size_t triangle_vertex_count = 0;
333 
334         for (size_t i = 0, e = arguments.m_assembly.object_instances().size(); i < e; ++i)
335         {
336             // Retrieve the object instance and its transformation.
337             const ObjectInstance* object_instance =
338                 arguments.m_assembly.object_instances().get_by_index(i);
339             assert(object_instance);
340 
341             // Retrieve the object.
342             Object& object = object_instance->get_object();
343 
344             // Process only mesh objects.
345             if (strcmp(object.get_model(), MeshObjectFactory().get_model()) != 0)
346                 continue;
347 
348             const MeshObject& mesh = static_cast<const MeshObject&>(object);
349             const StaticTriangleTess& tess = mesh.get_static_triangle_tess();
350 
351             // Collect the triangles from this tessellation.
352             if (tess.get_motion_segment_count() > 0)
353             {
354                 collect_moving_triangles(
355                     arguments.m_bbox,
356                     *object_instance,
357                     i,
358                     tess,
359                     time,
360                     save_memory,
361                     triangle_keys,
362                     triangle_vertex_infos,
363                     triangle_vertices,
364                     triangle_bboxes,
365                     triangle_vertex_count);
366             }
367             else
368             {
369                 collect_static_triangles(
370                     arguments.m_bbox,
371                     *object_instance,
372                     i,
373                     tess,
374                     save_memory,
375                     triangle_keys,
376                     triangle_vertex_infos,
377                     triangle_vertices,
378                     triangle_bboxes,
379                     triangle_vertex_count);
380             }
381         }
382     }
383 }
384 
Arguments(const Scene & scene,const UniqueID triangle_tree_uid,const GAABB3 & bbox,const Assembly & assembly)385 TriangleTree::Arguments::Arguments(
386     const Scene&            scene,
387     const UniqueID          triangle_tree_uid,
388     const GAABB3&           bbox,
389     const Assembly&         assembly)
390   : m_scene(scene)
391   , m_triangle_tree_uid(triangle_tree_uid)
392   , m_bbox(bbox)
393   , m_assembly(assembly)
394 {
395 }
396 
TriangleTree(const Arguments & arguments)397 TriangleTree::TriangleTree(const Arguments& arguments)
398   : TreeType(AlignedAllocator<void>(System::get_l1_data_cache_line_size()))
399   , m_arguments(arguments)
400 {
401     // Retrieve construction parameters.
402     const MessageContext message_context(
403         format("while building triangle tree for assembly \"{0}\"", m_arguments.m_assembly.get_path()));
404     const ParamArray& params = m_arguments.m_assembly.get_parameters().child("acceleration_structure");
405     const string algorithm = params.get_optional<string>("algorithm", "bvh", make_vector("bvh", "sbvh"), message_context);
406     const double time = params.get_optional<double>("time", 0.5);
407     const bool save_memory = params.get_optional<bool>("save_temporary_memory", false);
408 
409     // Start stopwatch.
410     Stopwatch<DefaultWallclockTimer> stopwatch;
411     stopwatch.start();
412 
413     // Build the tree.
414     Statistics statistics;
415     if (algorithm == "bvh")
416         build_bvh(params, time, save_memory, statistics);
417     else build_sbvh(params, time, save_memory, statistics);
418     statistics.insert_time("total build time", stopwatch.measure().get_seconds());
419     statistics.insert_size("nodes alignment", alignment(&m_nodes[0]));
420 
421 #ifdef RENDERER_TRIANGLE_TREE_REORDER_NODES
422     // Optimize the tree layout in memory.
423     TreeOptimizer<NodeVectorType> tree_optimizer(m_nodes);
424     tree_optimizer.optimize_node_layout(TriangleTreeSubtreeDepth);
425     assert(m_nodes.size() == m_nodes.capacity());
426 #endif
427 
428     // Print triangle tree statistics.
429     RENDERER_LOG_DEBUG("%s",
430         StatisticsVector::make(
431             "triangle tree #" + to_string(m_arguments.m_triangle_tree_uid) + " statistics",
432             statistics).to_string().c_str());
433 }
434 
~TriangleTree()435 TriangleTree::~TriangleTree()
436 {
437     RENDERER_LOG_INFO(
438         "deleting triangle tree #" FMT_UNIQUE_ID "...",
439         m_arguments.m_triangle_tree_uid);
440 
441     delete_intersection_filters();
442 }
443 
update_non_geometry(const bool enable_intersection_filters)444 void TriangleTree::update_non_geometry(const bool enable_intersection_filters)
445 {
446     if (enable_intersection_filters &&
447         m_arguments.m_assembly.get_parameters().get_optional<bool>("enable_intersection_filters", true))
448         update_intersection_filters();
449     else delete_intersection_filters();
450 }
451 
get_memory_size() const452 size_t TriangleTree::get_memory_size() const
453 {
454     return
455           TreeType::get_memory_size()
456         - sizeof(*static_cast<const TreeType*>(this))
457         + sizeof(*this)
458         + m_triangle_keys.capacity() * sizeof(TriangleKey)
459         + m_leaf_data.capacity() * sizeof(uint8);
460 }
461 
462 namespace
463 {
464     template <typename Vector>
print_vector_stats(const char * label,const Vector & vec)465     void print_vector_stats(const char* label, const Vector& vec)
466     {
467         const size_t ItemSize = sizeof(typename Vector::value_type);
468         const size_t overhead = vec.capacity() - vec.size();
469 
470         RENDERER_LOG_DEBUG(
471             "%s: size %s (%s)  capacity %s (%s)  overhead %s (%s)",
472             label,
473             pretty_uint(vec.size()).c_str(),
474             pretty_size(vec.size() * ItemSize).c_str(),
475             pretty_uint(vec.capacity()).c_str(),
476             pretty_size(vec.capacity() * ItemSize).c_str(),
477             pretty_uint(overhead).c_str(),
478             pretty_size(overhead * ItemSize).c_str());
479     }
480 
481     #define RENDERER_LOG_VECTOR_STATS(vec) print_vector_stats(#vec, vec)
482 
count_static_triangles(const vector<TriangleVertexInfo> & info)483     size_t count_static_triangles(const vector<TriangleVertexInfo>& info)
484     {
485         size_t count = 0;
486 
487         for (size_t i = 0; i < info.size(); ++i)
488         {
489             if (info[i].m_motion_segment_count == 0)
490                 ++count;
491         }
492 
493         return count;
494     }
495 }
496 
build_bvh(const ParamArray & params,const double time,const bool save_memory,Statistics & statistics)497 void TriangleTree::build_bvh(
498     const ParamArray&   params,
499     const double        time,
500     const bool          save_memory,
501     Statistics&         statistics)
502 {
503     Stopwatch<DefaultWallclockTimer> stopwatch;
504 
505     // Collect triangles intersecting the bounding box of this tree.
506     RENDERER_LOG_INFO(
507         "collecting geometry for triangle tree #" FMT_UNIQUE_ID " from assembly \"%s\"...",
508         m_arguments.m_triangle_tree_uid,
509         m_arguments.m_assembly.get_path().c_str());
510     stopwatch.start();
511     vector<TriangleKey> triangle_keys;
512     vector<TriangleVertexInfo> triangle_vertex_infos;
513     vector<GAABB3> triangle_bboxes;
514     collect_triangles(
515         m_arguments,
516         time,
517         save_memory,
518         &triangle_keys,
519         &triangle_vertex_infos,
520         nullptr,
521         &triangle_bboxes);
522     const double collection_time = stopwatch.measure().get_seconds();
523 
524     // Store the number of static and moving triangles.
525     m_static_triangle_count = count_static_triangles(triangle_vertex_infos);
526     m_moving_triangle_count = triangle_vertex_infos.size() - m_static_triangle_count;
527 
528     // Print statistics about the input geometry.
529     RENDERER_LOG_INFO(
530         "building triangle tree #" FMT_UNIQUE_ID " (bvh, %s %s, %s %s)...",
531         m_arguments.m_triangle_tree_uid,
532         pretty_uint(m_static_triangle_count).c_str(),
533         plural(m_static_triangle_count, "static triangle").c_str(),
534         pretty_uint(m_moving_triangle_count).c_str(),
535         plural(m_moving_triangle_count, "moving triangle").c_str());
536 
537     // Retrieving the partitioner parameters.
538     const size_t max_leaf_size = params.get_optional<size_t>("max_leaf_size", TriangleTreeDefaultMaxLeafSize);
539     const GScalar interior_node_traversal_cost = params.get_optional<GScalar>("interior_node_traversal_cost", TriangleTreeDefaultInteriorNodeTraversalCost);
540     const GScalar triangle_intersection_cost = params.get_optional<GScalar>("triangle_intersection_cost", TriangleTreeDefaultTriangleIntersectionCost);
541 
542     // Create the partitioner.
543     typedef bvh::SAHPartitioner<vector<GAABB3>> Partitioner;
544     Partitioner partitioner(
545         triangle_bboxes,
546         max_leaf_size,
547         interior_node_traversal_cost,
548         triangle_intersection_cost);
549 
550     // Build the tree.
551     typedef bvh::Builder<TriangleTree, Partitioner> Builder;
552     Builder builder;
553     builder.build<DefaultWallclockTimer>(
554         *this,
555         partitioner,
556         triangle_keys.size(),
557         max_leaf_size);
558     statistics.merge(
559         bvh::TreeStatistics<TriangleTree>(*this, AABB3d(m_arguments.m_bbox)));
560 
561     stopwatch.start();
562 
563     // Bounding boxes are no longer needed.
564     clear_release_memory(triangle_bboxes);
565 
566     // Collect triangle vertices.
567     vector<GVector3> triangle_vertices;
568     collect_triangles<GAABB3>(
569         m_arguments,
570         time,
571         save_memory,
572         nullptr,
573         nullptr,
574         &triangle_vertices,
575         nullptr);
576 
577     // Compute and propagate motion bounding boxes.
578     compute_motion_bboxes(
579         partitioner.get_item_ordering(),
580         triangle_vertex_infos,
581         triangle_vertices,
582         0);
583 
584     // Store triangles and triangle keys into the tree.
585     store_triangles(
586         partitioner.get_item_ordering(),
587         triangle_vertex_infos,
588         triangle_vertices,
589         triangle_keys,
590         statistics);
591 
592     const double store_time = stopwatch.measure().get_seconds();
593 
594     statistics.insert_time("collection time", collection_time);
595     statistics.insert_time("partition time", builder.get_build_time());
596     statistics.insert_time("store time", store_time);
597 }
598 
build_sbvh(const ParamArray & params,const double time,const bool save_memory,Statistics & statistics)599 void TriangleTree::build_sbvh(
600     const ParamArray&   params,
601     const double        time,
602     const bool          save_memory,
603     Statistics&         statistics)
604 {
605     Stopwatch<DefaultWallclockTimer> stopwatch;
606 
607     // Collect triangles intersecting the bounding box of this tree.
608     RENDERER_LOG_INFO(
609         "collecting geometry for triangle tree #" FMT_UNIQUE_ID " from assembly \"%s\"...",
610         m_arguments.m_triangle_tree_uid,
611         m_arguments.m_assembly.get_path().c_str());
612     vector<TriangleKey> triangle_keys;
613     vector<TriangleVertexInfo> triangle_vertex_infos;
614     vector<GVector3> triangle_vertices;
615     vector<AABB3d> triangle_bboxes;
616     stopwatch.start();
617     collect_triangles(
618         m_arguments,
619         time,
620         save_memory,
621         &triangle_keys,
622         &triangle_vertex_infos,
623         &triangle_vertices,
624         &triangle_bboxes);
625     const double collection_time = stopwatch.measure().get_seconds();
626 
627     // Store the number of static and moving triangles.
628     m_static_triangle_count = count_static_triangles(triangle_vertex_infos);
629     m_moving_triangle_count = triangle_vertex_infos.size() - m_static_triangle_count;
630 
631     // Print statistics about the input geometry.
632     RENDERER_LOG_INFO(
633         "building triangle tree #" FMT_UNIQUE_ID " (sbvh, %s %s, %s %s)...",
634         m_arguments.m_triangle_tree_uid,
635         pretty_uint(m_static_triangle_count).c_str(),
636         plural(m_static_triangle_count, "static triangle").c_str(),
637         pretty_uint(m_moving_triangle_count).c_str(),
638         plural(m_moving_triangle_count, "moving triangle").c_str());
639 
640     // Retrieving the partitioner parameters.
641     const size_t max_leaf_size = params.get_optional<size_t>("max_leaf_size", TriangleTreeDefaultMaxLeafSize);
642     const size_t bin_count = params.get_optional<size_t>("bin_count", TriangleTreeDefaultBinCount);
643     const GScalar interior_node_traversal_cost = params.get_optional<GScalar>("interior_node_traversal_cost", TriangleTreeDefaultInteriorNodeTraversalCost);
644     const GScalar triangle_intersection_cost = params.get_optional<GScalar>("triangle_intersection_cost", TriangleTreeDefaultTriangleIntersectionCost);
645 
646     // Create the partitioner.
647     typedef bvh::SBVHPartitioner<TriangleItemHandler, vector<AABB3d>> Partitioner;
648     TriangleItemHandler triangle_handler(
649         triangle_vertex_infos,
650         triangle_vertices,
651         triangle_bboxes);
652     Partitioner partitioner(
653         triangle_handler,
654         triangle_bboxes,
655         max_leaf_size,
656         bin_count,
657         interior_node_traversal_cost,
658         triangle_intersection_cost);
659 
660     // Create the root leaf.
661     Partitioner::LeafType* root_leaf = partitioner.create_root_leaf();
662     const AABB3d root_leaf_bbox = partitioner.compute_leaf_bbox(*root_leaf);
663 
664     // Build the tree.
665     typedef bvh::SpatialBuilder<TriangleTree, Partitioner> Builder;
666     Builder builder;
667     builder.build<DefaultWallclockTimer>(
668         *this,
669         partitioner,
670         root_leaf,
671         root_leaf_bbox);
672     statistics.merge(bvh::TreeStatistics<TriangleTree>(*this, AABB3d(m_arguments.m_bbox)));
673 
674     // Add splits statistics.
675     const size_t spatial_splits = partitioner.get_spatial_split_count();
676     const size_t object_splits = partitioner.get_object_split_count();
677     const size_t total_splits = spatial_splits + object_splits;
678     statistics.insert(
679         "splits",
680         "spatial " + pretty_uint(spatial_splits) + " (" + pretty_percent(spatial_splits, total_splits) + ")  "
681         "object " + pretty_uint(object_splits) + " (" + pretty_percent(object_splits, total_splits) + ")");
682 
683     stopwatch.start();
684 
685     // Bounding boxes are no longer needed.
686     clear_release_memory(triangle_bboxes);
687 
688     // Compute and propagate motion bounding boxes.
689     compute_motion_bboxes(
690         partitioner.get_item_ordering(),
691         triangle_vertex_infos,
692         triangle_vertices,
693         0);
694 
695     // Store triangles and triangle keys into the tree.
696     store_triangles(
697         partitioner.get_item_ordering(),
698         triangle_vertex_infos,
699         triangle_vertices,
700         triangle_keys,
701         statistics);
702 
703     const double store_time = stopwatch.measure().get_seconds();
704 
705     statistics.insert_time("collection time", collection_time);
706     statistics.insert_time("partition time", builder.get_build_time());
707     statistics.insert_time("store time", store_time);
708 }
709 
710 namespace
711 {
712 #ifdef APPLESEED_USE_SSE
713 
714     //
715     // If the bounding box is seen as a flat array of scalars, the swizzle()
716     // function converts the bounding box from
717     //
718     //   min.x  min.y  min.z  max.x  max.y  max.z
719     //
720     // to
721     //
722     //   min.x  max.x  min.y  max.y  min.z  max.z
723     //
724 
725     template <typename T, size_t N>
swizzle(const AABB<T,N> & bbox)726     AABB<T, N> swizzle(const AABB<T, N>& bbox)
727     {
728         AABB<T, N> result;
729         T* flat_result = &result[0][0];
730 
731         for (size_t i = 0; i < N; ++i)
732         {
733             flat_result[i * 2 + 0] = bbox[0][i];
734             flat_result[i * 2 + 1] = bbox[1][i];
735         }
736 
737         return result;
738     }
739 
740 #else
741 
742     //
743     // The swizzle() function has no effect when SSE is disabled.
744     //
745 
746     template <typename T, size_t N>
747     AABB<T, N> swizzle(const AABB<T, N>& bbox)
748     {
749         return bbox;
750     }
751 
752 #endif
753 }
754 
compute_motion_bboxes(const vector<size_t> & triangle_indices,const vector<TriangleVertexInfo> & triangle_vertex_infos,const vector<GVector3> & triangle_vertices,const size_t node_index)755 vector<GAABB3> TriangleTree::compute_motion_bboxes(
756     const vector<size_t>&               triangle_indices,
757     const vector<TriangleVertexInfo>&   triangle_vertex_infos,
758     const vector<GVector3>&             triangle_vertices,
759     const size_t                        node_index)
760 {
761     NodeType& node = m_nodes[node_index];
762 
763     if (node.is_interior())
764     {
765         const vector<GAABB3> left_bboxes =
766             compute_motion_bboxes(
767                 triangle_indices,
768                 triangle_vertex_infos,
769                 triangle_vertices,
770                 node.get_child_node_index() + 0);
771 
772         const vector<GAABB3> right_bboxes =
773             compute_motion_bboxes(
774                 triangle_indices,
775                 triangle_vertex_infos,
776                 triangle_vertices,
777                 node.get_child_node_index() + 1);
778 
779         node.set_left_bbox_count(left_bboxes.size());
780         node.set_right_bbox_count(right_bboxes.size());
781 
782         if (left_bboxes.size() > 1)
783         {
784             node.set_left_bbox_index(m_node_bboxes.size());
785 
786             for (vector<GAABB3>::const_iterator i = left_bboxes.begin(); i != left_bboxes.end(); ++i)
787                 m_node_bboxes.push_back(swizzle(AABB3d(*i)));
788         }
789 
790         if (right_bboxes.size() > 1)
791         {
792             node.set_right_bbox_index(m_node_bboxes.size());
793 
794             for (vector<GAABB3>::const_iterator i = right_bboxes.begin(); i != right_bboxes.end(); ++i)
795                 m_node_bboxes.push_back(swizzle(AABB3d(*i)));
796         }
797 
798         const size_t bbox_count = max(left_bboxes.size(), right_bboxes.size());
799         vector<GAABB3> bboxes(bbox_count);
800 
801         for (size_t i = 0; i < bbox_count; ++i)
802         {
803             bboxes[i] = left_bboxes[i * left_bboxes.size() / bbox_count];
804             bboxes[i].insert(right_bboxes[i * right_bboxes.size() / bbox_count]);
805         }
806 
807         return bboxes;
808     }
809     else
810     {
811         const size_t item_begin = node.get_item_index();
812         const size_t item_count = node.get_item_count();
813 
814         size_t max_motion_segment_count = 0;
815 
816         GAABB3 base_pose_bbox;
817         base_pose_bbox.invalidate();
818 
819         for (size_t i = 0; i < item_count; ++i)
820         {
821             const size_t triangle_index = triangle_indices[item_begin + i];
822             const TriangleVertexInfo& vertex_info = triangle_vertex_infos[triangle_index];
823 
824             assert(is_pow2(vertex_info.m_motion_segment_count + 1));
825 
826             if (max_motion_segment_count < vertex_info.m_motion_segment_count)
827                 max_motion_segment_count = vertex_info.m_motion_segment_count;
828 
829             base_pose_bbox.insert(triangle_vertices[vertex_info.m_vertex_index + 0]);
830             base_pose_bbox.insert(triangle_vertices[vertex_info.m_vertex_index + 1]);
831             base_pose_bbox.insert(triangle_vertices[vertex_info.m_vertex_index + 2]);
832         }
833 
834         vector<GAABB3> bboxes(max_motion_segment_count + 1);
835         bboxes[0] = base_pose_bbox;
836 
837         if (max_motion_segment_count > 0)
838         {
839             for (size_t m = 0; m < max_motion_segment_count - 1; ++m)
840             {
841                 bboxes[m + 1].invalidate();
842 
843                 const double time = static_cast<double>(m + 1) / max_motion_segment_count;
844 
845                 for (size_t i = 0; i < item_count; ++i)
846                 {
847                     const size_t triangle_index = triangle_indices[item_begin + i];
848                     const TriangleVertexInfo& vertex_info = triangle_vertex_infos[triangle_index];
849 
850                     const size_t prev_pose_index = truncate<size_t>(time * vertex_info.m_motion_segment_count);
851                     const size_t base_vertex_index = vertex_info.m_vertex_index + prev_pose_index * 3;
852                     const GScalar k = static_cast<GScalar>(time * vertex_info.m_motion_segment_count - prev_pose_index);
853 
854                     bboxes[m + 1].insert(lerp(triangle_vertices[base_vertex_index + 0], triangle_vertices[base_vertex_index + 3], k));
855                     bboxes[m + 1].insert(lerp(triangle_vertices[base_vertex_index + 1], triangle_vertices[base_vertex_index + 4], k));
856                     bboxes[m + 1].insert(lerp(triangle_vertices[base_vertex_index + 2], triangle_vertices[base_vertex_index + 5], k));
857                 }
858             }
859 
860             bboxes[max_motion_segment_count].invalidate();
861 
862             for (size_t i = 0; i < item_count; ++i)
863             {
864                 const size_t triangle_index = triangle_indices[item_begin + i];
865                 const TriangleVertexInfo& vertex_info = triangle_vertex_infos[triangle_index];
866                 const size_t base_vertex_index = vertex_info.m_vertex_index + vertex_info.m_motion_segment_count * 3;
867 
868                 bboxes[max_motion_segment_count].insert(triangle_vertices[base_vertex_index + 0]);
869                 bboxes[max_motion_segment_count].insert(triangle_vertices[base_vertex_index + 1]);
870                 bboxes[max_motion_segment_count].insert(triangle_vertices[base_vertex_index + 2]);
871             }
872         }
873 
874         return bboxes;
875     }
876 }
877 
store_triangles(const vector<size_t> & triangle_indices,const vector<TriangleVertexInfo> & triangle_vertex_infos,const vector<GVector3> & triangle_vertices,const vector<TriangleKey> & triangle_keys,Statistics & statistics)878 void TriangleTree::store_triangles(
879     const vector<size_t>&               triangle_indices,
880     const vector<TriangleVertexInfo>&   triangle_vertex_infos,
881     const vector<GVector3>&             triangle_vertices,
882     const vector<TriangleKey>&          triangle_keys,
883     Statistics&                         statistics)
884 {
885     const size_t node_count = m_nodes.size();
886 
887     // Gather statistics.
888 
889     size_t leaf_count = 0;
890     size_t fat_leaf_count = 0;
891     size_t leaf_data_size = 0;
892 
893     for (size_t i = 0; i < node_count; ++i)
894     {
895         const NodeType& node = m_nodes[i];
896 
897         if (node.is_leaf())
898         {
899             ++leaf_count;
900 
901             const size_t item_begin = node.get_item_index();
902             const size_t item_count = node.get_item_count();
903 
904             const size_t leaf_size =
905                 TriangleEncoder::compute_size(
906                     triangle_vertex_infos,
907                     triangle_indices,
908                     item_begin,
909                     item_count);
910 
911             if (leaf_size < NodeType::MaxUserDataSize)
912                 ++fat_leaf_count;
913             else leaf_data_size += leaf_size;
914         }
915     }
916 
917     // Store triangle keys and triangles.
918 
919     m_triangle_keys.reserve(triangle_indices.size());
920     m_leaf_data.resize(leaf_data_size);
921 
922     MemoryWriter leaf_data_writer(m_leaf_data.empty() ? nullptr : &m_leaf_data[0]);
923 
924     for (size_t i = 0; i < node_count; ++i)
925     {
926         NodeType& node = m_nodes[i];
927 
928         if (node.is_leaf())
929         {
930             const size_t item_begin = node.get_item_index();
931             const size_t item_count = node.get_item_count();
932 
933             node.set_item_index(m_triangle_keys.size());
934 
935             for (size_t j = 0; j < item_count; ++j)
936             {
937                 const size_t triangle_index = triangle_indices[item_begin + j];
938                 m_triangle_keys.push_back(triangle_keys[triangle_index]);
939             }
940 
941             const size_t leaf_size =
942                 TriangleEncoder::compute_size(
943                     triangle_vertex_infos,
944                     triangle_indices,
945                     item_begin,
946                     item_count);
947 
948             MemoryWriter user_data_writer(&node.get_user_data<uint8>());
949 
950             if (leaf_size <= NodeType::MaxUserDataSize - sizeof(uint32))
951             {
952                 user_data_writer.write<uint32>(~uint32(0));
953 
954                 TriangleEncoder::encode(
955                     triangle_vertex_infos,
956                     triangle_vertices,
957                     triangle_indices,
958                     item_begin,
959                     item_count,
960                     user_data_writer);
961             }
962             else
963             {
964                 user_data_writer.write(static_cast<uint32>(leaf_data_writer.offset()));
965 
966                 TriangleEncoder::encode(
967                     triangle_vertex_infos,
968                     triangle_vertices,
969                     triangle_indices,
970                     item_begin,
971                     item_count,
972                     leaf_data_writer);
973             }
974         }
975     }
976 
977     statistics.insert_percent("fat leaves", fat_leaf_count, leaf_count);
978 }
979 
980 namespace
981 {
982     struct FilterKey
983     {
984         Object*         m_object;
985         MaterialArray   m_materials;
986 
FilterKeyrenderer::__anonf8bee1ff0411::FilterKey987         FilterKey()
988         {
989         }
990 
FilterKeyrenderer::__anonf8bee1ff0411::FilterKey991         FilterKey(
992             Object*                 object,
993             const MaterialArray&    materials)
994           : m_object(object)
995           , m_materials(materials)
996         {
997         }
998 
operator ==renderer::__anonf8bee1ff0411::FilterKey999         bool operator==(const FilterKey& rhs) const
1000         {
1001             if (m_object != rhs.m_object)
1002                 return false;
1003 
1004             if (m_materials.size() != rhs.m_materials.size())
1005                 return false;
1006 
1007             const size_t material_count = m_materials.size();
1008 
1009             for (size_t i = 0; i < material_count; ++i)
1010             {
1011                 if (m_materials[i] != rhs.m_materials[i])
1012                     return false;
1013             }
1014 
1015             return true;
1016         }
1017 
operator <renderer::__anonf8bee1ff0411::FilterKey1018         bool operator<(const FilterKey& rhs) const
1019         {
1020             if (m_object < rhs.m_object)
1021                 return true;
1022             else if (m_object > rhs.m_object)
1023                 return false;
1024 
1025             if (m_materials.size() < rhs.m_materials.size())
1026                 return true;
1027             else if (m_materials.size() > rhs.m_materials.size())
1028                 return false;
1029 
1030             const size_t material_count = m_materials.size();
1031 
1032             for (size_t i = 0; i < material_count; ++i)
1033             {
1034                 if (m_materials[i] < rhs.m_materials[i])
1035                     return true;
1036                 else if (m_materials[i] > rhs.m_materials[i])
1037                     return false;
1038             }
1039 
1040             return false;
1041         }
1042 
has_alpha_mapsrenderer::__anonf8bee1ff0411::FilterKey1043         bool has_alpha_maps() const
1044         {
1045             // Use the uncached versions of get_alpha_map() since at this point
1046             // on_frame_begin() hasn't been called on the object or materials,
1047             // when intersection filters are updated on existing triangle trees
1048             // prior to rendering.
1049 
1050             if (m_object->get_uncached_alpha_map())
1051                 return true;
1052 
1053             const size_t material_count = m_materials.size();
1054 
1055             for (size_t i = 0; i < material_count; ++i)
1056             {
1057                 if (m_materials[i] && m_materials[i]->get_uncached_alpha_map())
1058                     return true;
1059             }
1060 
1061             return false;
1062         }
1063     };
1064 
1065     // Hash a filter key.
hash(const FilterKey & key)1066     uint64 hash(const FilterKey& key)
1067     {
1068         uint64 h = key.m_object->compute_signature();
1069 
1070         for (size_t i = 0; i < key.m_materials.size(); ++i)
1071         {
1072             const Material* material = key.m_materials[i];
1073 
1074             if (material)
1075                 h = Entity::combine_signatures(h, material->compute_signature());
1076         }
1077 
1078         return h;
1079     }
1080 
1081     typedef set<size_t> IndexSet;
1082     typedef set<FilterKey> FilterKeySet;
1083     typedef map<size_t, const FilterKey*> IndexToFilterKeyMap;
1084 
1085     // Collect the set of object instances contained in an assembly.
collect_object_instances(const Assembly & assembly,IndexSet & object_instances)1086     void collect_object_instances(
1087         const Assembly&                     assembly,
1088         IndexSet&                           object_instances)
1089     {
1090         for (size_t i = 0, e = assembly.object_instances().size(); i < e; ++i)
1091         {
1092             // Retrieve the object instance and its transformation.
1093             const ObjectInstance* object_instance =
1094                 assembly.object_instances().get_by_index(i);
1095             assert(object_instance);
1096 
1097             // Retrieve the object.
1098             Object& object = object_instance->get_object();
1099 
1100             // Process only mesh objects.
1101             if (strcmp(object.get_model(), MeshObjectFactory().get_model()) == 0)
1102                 object_instances.insert(i);
1103         }
1104     }
1105 
1106     // Create filter keys for a set of object instances, and establish an (object instance) -> (filter key) mapping.
create_filter_keys(const ObjectInstanceContainer & object_instances,const IndexSet & object_instance_indices,FilterKeySet & filter_keys,IndexToFilterKeyMap & object_instances_to_filter_keys)1107     void create_filter_keys(
1108         const ObjectInstanceContainer&      object_instances,
1109         const IndexSet&                     object_instance_indices,
1110         FilterKeySet&                       filter_keys,
1111         IndexToFilterKeyMap&                object_instances_to_filter_keys)
1112     {
1113         for (const_each<IndexSet> i = object_instance_indices; i; ++i)
1114         {
1115             const size_t object_instance_index = *i;
1116             const ObjectInstance* object_instance =
1117                 object_instances.get_by_index(object_instance_index);
1118 
1119             // We create intersection filters for front materials, assuming materials will be the same on the back
1120             // side of the object instance. This assumption is checked in renderer::ObjectInstance::on_frame_begin()
1121             // and a warning is issued if it does not appear to hold. The reason is that the direction of shadow
1122             // rays is unpredictable: an object with different alpha transparency on its front and back faces would
1123             // render differently with different light transport algorithms, or if the direction of shadow rays
1124             // (which is an implementation detail) changes.
1125             const FilterKeySet::const_iterator filter_key_it =
1126                 filter_keys.insert(
1127                     FilterKey(
1128                         &object_instance->get_object(),
1129                         object_instance->get_front_materials())).first;
1130 
1131             const FilterKey& filter_key = *filter_key_it;
1132             object_instances_to_filter_keys[object_instance_index] = &filter_key;
1133         }
1134     }
1135 
1136     // Create intersection filters for filter keys that don't already have one.
create_missing_intersection_filters(TextureCache & texture_cache,const FilterKeySet & filter_keys,IntersectionFilterRepository & filters)1137     void create_missing_intersection_filters(
1138         TextureCache&                       texture_cache,
1139         const FilterKeySet&                 filter_keys,
1140         IntersectionFilterRepository&       filters)
1141     {
1142         for (const_each<FilterKeySet> i = filter_keys; i; ++i)
1143         {
1144             const FilterKey& filter_key = *i;
1145 
1146             // Don't create intersection filters for keys that don't reference any alpha map.
1147             if (!filter_key.has_alpha_maps())
1148                 continue;
1149 
1150             // Update existing intersection filters.
1151             const uint64 filter_key_hash = hash(filter_key);
1152             const IntersectionFilterRepository::const_iterator it = filters.find(filter_key_hash);
1153             if (it != filters.end())
1154             {
1155                 it->second->update(*filter_key.m_object, filter_key.m_materials, texture_cache);
1156                 RENDERER_LOG_DEBUG(
1157                     "updated intersection filter with filter key hash 0x" FMT_UINT64_HEX ".",
1158                     filter_key_hash);
1159                 continue;
1160             }
1161 
1162             // Create an intersection filter for this key.
1163             unique_ptr<IntersectionFilter> intersection_filter(
1164                 new IntersectionFilter(
1165                     *filter_key.m_object,
1166                     filter_key.m_materials,
1167                     texture_cache));
1168 
1169             // Discard intersection filters that don't have any alpha masks.
1170             if (!intersection_filter->has_alpha_masks())
1171                 continue;
1172 
1173             RENDERER_LOG_DEBUG(
1174                 "created intersection filter for object \"%s\" with " FMT_SIZE_T " material%s "
1175                 "(masks: %s, uvs: %s, filter key hash: 0x" FMT_UINT64_HEX ").",
1176                 filter_key.m_object->get_path().c_str(),
1177                 filter_key.m_materials.size(),
1178                 filter_key.m_materials.size() > 1 ? "s" : "",
1179                 pretty_size(intersection_filter->get_masks_memory_size()).c_str(),
1180                 pretty_size(intersection_filter->get_masks_memory_size()).c_str(),
1181                 filter_key_hash);
1182 
1183             // Store this intersection filter.
1184             filters[filter_key_hash] = intersection_filter.release();
1185         }
1186     }
1187 
1188     // Delete and remove intersection filters that don't correspond to any filter key.
delete_unreferenced_intersection_filters(const FilterKeySet & filter_keys,IntersectionFilterRepository & repository)1189     void delete_unreferenced_intersection_filters(
1190         const FilterKeySet&                 filter_keys,
1191         IntersectionFilterRepository&       repository)
1192     {
1193         if (repository.empty())
1194             return;
1195 
1196         set<uint64> hashes;
1197 
1198         for (const_each<FilterKeySet> i = filter_keys; i; ++i)
1199             hashes.insert(hash(*i));
1200 
1201         for (IntersectionFilterRepository::iterator i = repository.begin(); i != repository.end(); )
1202         {
1203             const uint64 filter_key_hash = i->first;
1204 
1205             if (hashes.find(filter_key_hash) == hashes.end())
1206             {
1207                 delete i->second;
1208                 repository.erase(i++);
1209 
1210                 RENDERER_LOG_DEBUG(
1211                     "deleted intersection filter with filter key hash 0x" FMT_UINT64_HEX ".",
1212                     filter_key_hash);
1213             }
1214             else ++i;
1215         }
1216     }
1217 
map_object_instances_to_intersection_filters(const IndexSet & object_instances,const IndexToFilterKeyMap & object_instances_to_filter_keys,const IntersectionFilterRepository & repository,vector<const IntersectionFilter * > & filters)1218     void map_object_instances_to_intersection_filters(
1219         const IndexSet&                     object_instances,
1220         const IndexToFilterKeyMap&          object_instances_to_filter_keys,
1221         const IntersectionFilterRepository& repository,
1222         vector<const IntersectionFilter*>&  filters)
1223     {
1224         if (!object_instances.empty())
1225         {
1226             const size_t max_object_instance_index =
1227                 *max_element(object_instances.begin(), object_instances.end());
1228 
1229             filters.assign(max_object_instance_index + 1, nullptr);
1230 
1231             if (!repository.empty())
1232             {
1233                 for (const_each<IndexToFilterKeyMap> i = object_instances_to_filter_keys; i; ++i)
1234                 {
1235                     const size_t object_instance_index = i->first;
1236                     const FilterKey* filter_key = i->second;
1237 
1238                     const IntersectionFilterRepository::const_iterator it =
1239                         repository.find(hash(*filter_key));
1240 
1241                     if (it != repository.end())
1242                         filters[object_instance_index] = it->second;
1243                 }
1244             }
1245         }
1246     }
1247 }
1248 
update_intersection_filters()1249 void TriangleTree::update_intersection_filters()
1250 {
1251     // Collect object instances.
1252     IndexSet object_instances;
1253     collect_object_instances(m_arguments.m_assembly, object_instances);
1254 
1255     // Create filter keys and map object instances to filter keys.
1256     FilterKeySet filter_keys;
1257     IndexToFilterKeyMap object_instances_to_filter_keys;
1258     create_filter_keys(
1259         m_arguments.m_assembly.object_instances(),
1260         object_instances,
1261         filter_keys,
1262         object_instances_to_filter_keys);
1263 
1264     // Create missing intersection filters and update existing ones.
1265     TextureStore texture_store(m_arguments.m_scene);
1266     TextureCache texture_cache(texture_store);
1267     create_missing_intersection_filters(
1268         texture_cache,
1269         filter_keys,
1270         m_intersection_filters_repository);
1271 
1272     // Delete intersection filters that are no longer referenced.
1273     delete_unreferenced_intersection_filters(
1274         filter_keys,
1275         m_intersection_filters_repository);
1276 
1277     // Map object instances to intersection filters.
1278     map_object_instances_to_intersection_filters(
1279         object_instances,
1280         object_instances_to_filter_keys,
1281         m_intersection_filters_repository,
1282         m_intersection_filters);
1283 }
1284 
delete_intersection_filters()1285 void TriangleTree::delete_intersection_filters()
1286 {
1287     for (const_each<IntersectionFilterRepository> i = m_intersection_filters_repository; i; ++i)
1288         delete i->second;
1289 
1290     m_intersection_filters_repository.clear();
1291     m_intersection_filters.clear();
1292 }
1293 
1294 
1295 //
1296 // TriangleTreeFactory class implementation.
1297 //
1298 
TriangleTreeFactory(const TriangleTree::Arguments & arguments)1299 TriangleTreeFactory::TriangleTreeFactory(const TriangleTree::Arguments& arguments)
1300   : m_arguments(arguments)
1301 {
1302 }
1303 
create()1304 unique_ptr<TriangleTree> TriangleTreeFactory::create()
1305 {
1306     return unique_ptr<TriangleTree>(new TriangleTree(m_arguments));
1307 }
1308 
1309 
1310 //
1311 // Utility class to convert a triangle to the desired precision if necessary,
1312 // but avoid any work (in particular, no copy) if the source triangle already
1313 // has the desired precision and can be used in-place.
1314 //
1315 
1316 namespace
1317 {
1318     template <bool CompatibleTypes> struct TriangleReaderImpl;
1319 
1320     // Compatible types: no conversion or copy.
1321     template <> struct TriangleReaderImpl<true>
1322     {
1323         const TriangleType& m_triangle;
1324 
TriangleReaderImplrenderer::__anonf8bee1ff0511::TriangleReaderImpl1325         explicit TriangleReaderImpl(const TriangleType& triangle)
1326           : m_triangle(triangle)
1327         {
1328         }
1329     };
1330 
1331     // Incompatible types: perform a conversion.
1332     template <> struct TriangleReaderImpl<false>
1333     {
1334         const TriangleType m_triangle;
1335 
TriangleReaderImplrenderer::__anonf8bee1ff0511::TriangleReaderImpl1336         explicit TriangleReaderImpl(const GTriangleType& triangle)
1337           : m_triangle(triangle)
1338         {
1339         }
1340     };
1341 
1342     typedef TriangleReaderImpl<
1343         sizeof(GTriangleType::ValueType) == sizeof(TriangleType::ValueType)
1344     > TriangleReader;
1345 }
1346 
1347 
1348 //
1349 // TriangleLeafVisitor class implementation.
1350 //
1351 
visit(const TriangleTree::NodeType & node,const Ray3d & ray,const RayInfo3d & ray_info,double & distance,bvh::TraversalStatistics & stats)1352 bool TriangleLeafVisitor::visit(
1353     const TriangleTree::NodeType&           node,
1354     const Ray3d&                            ray,
1355     const RayInfo3d&                        ray_info,
1356     double&                                 distance
1357 #ifdef FOUNDATION_BVH_ENABLE_TRAVERSAL_STATS
1358     , bvh::TraversalStatistics&             stats
1359 #endif
1360     )
1361 {
1362     // Retrieve the pointer to the data of this leaf.
1363     const uint8* user_data = &node.get_user_data<uint8>();
1364     const uint32 leaf_data_index = *reinterpret_cast<const uint32*>(user_data);
1365     const uint8* leaf_data =
1366         leaf_data_index == ~uint32(0)
1367             ? user_data + sizeof(uint32)                // triangles are stored in the leaf node
1368             : &m_tree.m_leaf_data[leaf_data_index];     // triangles are stored in the tree
1369     MemoryReader reader(leaf_data);
1370 
1371     // Sequentially intersect all triangles of the leaf.
1372     for (size_t triangle_index = node.get_item_index(),
1373                 triangle_count = node.get_item_count();
1374                 triangle_count--;
1375                 triangle_index++)
1376     {
1377         FOUNDATION_BVH_TRAVERSAL_STATS(stats.m_intersected_items.insert(1));
1378 
1379         // Retrieve the triangle's visibility flags.
1380         const uint32 vis_flags = reader.read<uint32>();
1381 
1382         // Retrieve the number of motion segments for this triangle.
1383         const uint32 motion_segment_count = reader.read<uint32>();
1384 
1385         // todo: get rid of this test by sorting triangles by their number of motion segments.
1386         if (motion_segment_count == 0)
1387         {
1388             // Check visibility flags.
1389             if (!(vis_flags & m_shading_point.m_ray.m_flags))
1390             {
1391                 reader += sizeof(GTriangleType);
1392                 continue;
1393             }
1394 
1395             // Read the triangle, converting it to the right format if necessary.
1396             const GTriangleType& triangle = reader.read<GTriangleType>();
1397             const TriangleReader triangle_reader(triangle);
1398 
1399             // Intersect the triangle.
1400             double t, u, v;
1401             if (triangle_reader.m_triangle.intersect(ray, t, u, v))
1402             {
1403                 // Optionally filter intersections.
1404                 if (m_has_intersection_filters)
1405                 {
1406                     const TriangleKey& triangle_key = m_tree.m_triangle_keys[triangle_index];
1407                     const IntersectionFilter* filter =
1408                         m_tree.m_intersection_filters[triangle_key.get_object_instance_index()];
1409                     if (filter && !filter->accept(triangle_key, u, v))
1410                         continue;
1411                 }
1412 
1413                 m_hit_triangle = &triangle;
1414                 m_hit_triangle_index = triangle_index;
1415                 m_shading_point.m_ray.m_tmax = t;
1416                 m_shading_point.m_bary[0] = static_cast<float>(u);
1417                 m_shading_point.m_bary[1] = static_cast<float>(v);
1418             }
1419         }
1420         else
1421         {
1422             // Size in bytes of one motion step (i.e. one triangle).
1423             const size_t TriangleSize = 3 * sizeof(GVector3);
1424 
1425             // Check visibility flags.
1426             if (!(vis_flags & m_shading_point.m_ray.m_flags))
1427             {
1428                 reader += (motion_segment_count + 1) * TriangleSize;
1429                 continue;
1430             }
1431 
1432             // Advance to the motion step immediately before the ray time.
1433             const double base_time = m_shading_point.m_ray.m_time.m_normalized * motion_segment_count;
1434             const size_t base_index = truncate<size_t>(base_time);
1435             reader += base_index * TriangleSize;
1436 
1437             // Fetch and interpolate the triangle's vertices of the motion steps surrounding the ray time.
1438             const GScalar frac = static_cast<GScalar>(base_time - base_index);
1439             const GScalar one_minus_frac = GScalar(1.0) - frac;
1440             GVector3 v0 = reader.read<GVector3>() * one_minus_frac;
1441             GVector3 v1 = reader.read<GVector3>() * one_minus_frac;
1442             GVector3 v2 = reader.read<GVector3>() * one_minus_frac;
1443             v0 += reader.read<GVector3>() * frac;
1444             v1 += reader.read<GVector3>() * frac;
1445             v2 += reader.read<GVector3>() * frac;
1446 
1447             // Skip the remaining motion steps of this triangle.
1448             reader += (motion_segment_count - base_index - 1) * TriangleSize;
1449 
1450             // Build the triangle and convert it to the right format if necessary.
1451             const GTriangleType triangle(v0, v1, v2);
1452             const TriangleReader reader(triangle);
1453 
1454             // Intersect the triangle.
1455             double t, u, v;
1456             if (reader.m_triangle.intersect(ray, t, u, v))
1457             {
1458                 // Optionally filter intersections.
1459                 if (m_has_intersection_filters)
1460                 {
1461                     const TriangleKey& triangle_key = m_tree.m_triangle_keys[triangle_index];
1462                     const IntersectionFilter* filter =
1463                         m_tree.m_intersection_filters[triangle_key.get_object_instance_index()];
1464                     if (filter && !filter->accept(triangle_key, u, v))
1465                         continue;
1466                 }
1467 
1468                 m_interpolated_triangle = triangle;
1469                 m_hit_triangle = &m_interpolated_triangle;
1470                 m_hit_triangle_index = triangle_index;
1471                 m_shading_point.m_ray.m_tmax = t;
1472                 m_shading_point.m_bary[0] = static_cast<float>(u);
1473                 m_shading_point.m_bary[1] = static_cast<float>(v);
1474             }
1475         }
1476     }
1477 
1478     // Continue traversal.
1479     distance = m_shading_point.m_ray.m_tmax;
1480     return true;
1481 }
1482 
read_hit_triangle_data() const1483 void TriangleLeafVisitor::read_hit_triangle_data() const
1484 {
1485     if (m_hit_triangle)
1486     {
1487         // Record a hit.
1488         m_shading_point.m_primitive_type = ShadingPoint::PrimitiveTriangle;
1489 
1490         // Copy the triangle key.
1491         const TriangleKey& triangle_key = m_tree.m_triangle_keys[m_hit_triangle_index];
1492         m_shading_point.m_object_instance_index = triangle_key.get_object_instance_index();
1493         m_shading_point.m_primitive_index = triangle_key.get_triangle_index();
1494 
1495         // Compute and store the support plane of the hit triangle.
1496         const TriangleReader reader(*m_hit_triangle);
1497         m_shading_point.m_triangle_support_plane.initialize(reader.m_triangle);
1498     }
1499 }
1500 
1501 
1502 //
1503 // TriangleLeafProbeVisitor class implementation.
1504 //
1505 
visit(const TriangleTree::NodeType & node,const Ray3d & ray,const RayInfo3d & ray_info,double & distance,bvh::TraversalStatistics & stats)1506 bool TriangleLeafProbeVisitor::visit(
1507     const TriangleTree::NodeType&           node,
1508     const Ray3d&                            ray,
1509     const RayInfo3d&                        ray_info,
1510     double&                                 distance
1511 #ifdef FOUNDATION_BVH_ENABLE_TRAVERSAL_STATS
1512     , bvh::TraversalStatistics&             stats
1513 #endif
1514     )
1515 {
1516     // Retrieve the pointer to the data of this leaf.
1517     const uint8* user_data = &node.get_user_data<uint8>();
1518     const uint32 leaf_data_index = *reinterpret_cast<const uint32*>(user_data);
1519     const uint8* leaf_data =
1520         leaf_data_index == ~uint32(0)
1521             ? user_data + sizeof(uint32)                // triangles are stored in the leaf node
1522             : &m_tree.m_leaf_data[leaf_data_index];     // triangles are stored in the tree
1523     MemoryReader reader(leaf_data);
1524 
1525     // Sequentially intersect triangles until a hit is found.
1526     for (size_t triangle_count = node.get_item_count(); triangle_count--; )
1527     {
1528         FOUNDATION_BVH_TRAVERSAL_STATS(stats.m_intersected_items.insert(1));
1529 
1530         // Retrieve the triangle's visibility flags.
1531         const uint32 vis_flags = reader.read<uint32>();
1532 
1533         // Retrieve the number of motion segments for this triangle.
1534         const uint32 motion_segment_count = reader.read<uint32>();
1535 
1536         // todo: get rid of this test by sorting triangles by their number of motion segments.
1537         if (motion_segment_count == 0)
1538         {
1539             // Check visibility flags.
1540             if (!(vis_flags & m_ray_flags))
1541             {
1542                 reader += sizeof(GTriangleType);
1543                 continue;
1544             }
1545 
1546             // Read the triangle, converting it to the right format if necessary.
1547             const GTriangleType& triangle = reader.read<GTriangleType>();
1548             const TriangleReader triangle_reader(triangle);
1549 
1550             // Intersect the triangle.
1551             if (triangle_reader.m_triangle.intersect(ray))
1552             {
1553                 m_hit = true;
1554                 return false;
1555             }
1556         }
1557         else
1558         {
1559             // Size in bytes of one motion step (i.e. one triangle).
1560             const size_t TriangleSize = 3 * sizeof(GVector3);
1561 
1562             // Check visibility flags.
1563             if (!(vis_flags & m_ray_flags))
1564             {
1565                 reader += (motion_segment_count + 1) * TriangleSize;
1566                 continue;
1567             }
1568 
1569             // Advance to the motion step immediately before the ray time.
1570             const double base_time = m_ray_time * motion_segment_count;
1571             const size_t base_index = truncate<size_t>(base_time);
1572             reader += base_index * TriangleSize;
1573 
1574             // Fetch and interpolate the triangle's vertices of the motion steps surrounding the ray time.
1575             const GScalar frac = static_cast<GScalar>(base_time - base_index);
1576             const GScalar one_minus_frac = GScalar(1.0) - frac;
1577             GVector3 v0 = reader.read<GVector3>() * one_minus_frac;
1578             GVector3 v1 = reader.read<GVector3>() * one_minus_frac;
1579             GVector3 v2 = reader.read<GVector3>() * one_minus_frac;
1580             v0 += reader.read<GVector3>() * frac;
1581             v1 += reader.read<GVector3>() * frac;
1582             v2 += reader.read<GVector3>() * frac;
1583 
1584             // Build the triangle and convert it to the right format if necessary.
1585             const GTriangleType triangle(v0, v1, v2);
1586             const TriangleReader triangle_reader(triangle);
1587 
1588             // Intersect the triangle.
1589             if (triangle_reader.m_triangle.intersect(ray))
1590             {
1591                 m_hit = true;
1592                 return false;
1593             }
1594 
1595             // Skip the remaining motion steps of this triangle.
1596             reader += (motion_segment_count - base_index - 1) * TriangleSize;
1597         }
1598     }
1599 
1600     // Continue traversal.
1601     distance = ray.m_tmax;
1602     return true;
1603 }
1604 
1605 }   // namespace renderer
1606