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 = ▵
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