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) 2018 Fedor Matantsev, The appleseedhq Organization
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 //
28 
29 // Interface header.
30 #include "embreescene.h"
31 
32 // appleseed.renderer headers.
33 #include "renderer/kernel/intersection/intersectionsettings.h"
34 #include "renderer/kernel/shading/shadingpoint.h"
35 #include "renderer/kernel/shading/shadingray.h"
36 #include "renderer/modeling/object/curveobject.h"
37 #include "renderer/modeling/object/meshobject.h"
38 #include "renderer/modeling/object/object.h"
39 #include "renderer/modeling/object/triangle.h"
40 #include "renderer/modeling/scene/assembly.h"
41 #include "renderer/modeling/scene/containers.h"
42 
43 // appleseed.foundation headers.
44 #include "foundation/math/area.h"
45 #include "foundation/math/fp.h"
46 #include "foundation/math/intersection/raytrianglemt.h"
47 #include "foundation/math/minmax.h"
48 #include "foundation/math/scalar.h"
49 #include "foundation/math/transform.h"
50 #include "foundation/platform/sse.h"
51 #include "foundation/utility/makevector.h"
52 #include "foundation/utility/statistics.h"
53 #include "foundation/utility/stopwatch.h"
54 
55 using namespace foundation;
56 using namespace renderer;
57 using namespace std;
58 
59 namespace renderer
60 {
61 
62 class EmbreeGeometryData
63   : public NonCopyable
64 {
65   public:
66     // Vertex data.
67     GVector3*               m_vertices;
68     unsigned int            m_vertices_count;
69     unsigned int            m_vertices_stride;
70 
71     // Primitive data.
72     uint32*                 m_primitives;
73     size_t                  m_primitives_count;
74     size_t                  m_primitives_stride;
75 
76     // Instance data.
77     size_t                  m_object_instance_idx;
78     uint32                  m_vis_flags;
79     unsigned int            m_motion_steps_count;
80 
81     RTCGeometryType         m_geometry_type;
82     RTCGeometry             m_geometry_handle;
83 
EmbreeGeometryData()84     EmbreeGeometryData()
85       : m_vertices(nullptr)
86       , m_primitives(nullptr)
87       , m_geometry_handle(nullptr)
88     {}
89 
~EmbreeGeometryData()90     ~EmbreeGeometryData()
91     {
92         delete[] m_vertices;
93         delete[] m_primitives;
94         rtcReleaseGeometry(m_geometry_handle);
95     }
96 };
97 
98 namespace
99 {
collect_triangle_data(const ObjectInstance & object_instance,EmbreeGeometryData & geometry_data)100     void collect_triangle_data(
101         const ObjectInstance&   object_instance,
102         EmbreeGeometryData&     geometry_data)
103     {
104         assert(geometry_data.m_geometry_type == RTC_GEOMETRY_TYPE_TRIANGLE);
105 
106         // Retrieve object space -> assembly space transform for the object instance.
107         const Transformd& transform = object_instance.get_transform();
108 
109         // Retrieve the object.
110         Object& object = object_instance.get_object();
111 
112         const MeshObject& mesh = static_cast<const MeshObject&>(object);
113         const StaticTriangleTess& tess = mesh.get_static_triangle_tess();
114 
115         const unsigned int motion_steps_count = static_cast<unsigned int>(tess.get_motion_segment_count()) + 1;
116         geometry_data.m_motion_steps_count = motion_steps_count;
117 
118         //
119         // Retrieve per vertex data.
120         //
121         const unsigned int vertices_count = static_cast<unsigned int>(tess.m_vertices.size());
122         geometry_data.m_vertices_count = vertices_count;
123         geometry_data.m_vertices_stride = sizeof(GVector3);
124 
125         // Allocate memory for the vertices. Keep one extra vertex for padding.
126         geometry_data.m_vertices = new GVector3[vertices_count * motion_steps_count + 1];
127 
128         // Retrieve assembly space vertices.
129         for (size_t i = 0; i < vertices_count; ++i)
130         {
131             const GVector3& vertex_os = tess.m_vertices[i];
132             geometry_data.m_vertices[i] = transform.point_to_parent(vertex_os);
133         }
134 
135         for (size_t m = 1; m < motion_steps_count; ++m)
136         {
137             for (size_t i = 0; i < vertices_count; ++i)
138             {
139                 const GVector3& vertex_os = tess.get_vertex_pose(i, m - 1);
140                 geometry_data.m_vertices[vertices_count * m + i] = transform.point_to_parent(vertex_os);
141             }
142         }
143 
144         //
145         // Retrieve per primitive data.
146         //
147         const size_t primitives_count = tess.m_primitives.size();
148 
149         geometry_data.m_primitives = new uint32[primitives_count * 3];
150         geometry_data.m_primitives_stride = sizeof(uint32) * 3;
151         geometry_data.m_primitives_count = primitives_count;
152 
153         for (size_t i = 0; i < primitives_count; ++i)
154         {
155             geometry_data.m_primitives[i * 3] = tess.m_primitives[i].m_v0;
156             geometry_data.m_primitives[i * 3 + 1] = tess.m_primitives[i].m_v1;
157             geometry_data.m_primitives[i * 3 + 2] = tess.m_primitives[i].m_v2;
158         }
159     };
160 
collect_curve_data(const ObjectInstance & object_instance,EmbreeGeometryData & geometry_data)161     void collect_curve_data(
162         const ObjectInstance&   object_instance,
163         EmbreeGeometryData&     geometry_data)
164     {
165         //const Transformd& transform = object_instance.get_transform();
166 
167         switch(geometry_data.m_geometry_type)
168         {
169         case RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE:
170             //
171             // [Note: Girish] Retrieve data from CurveObject here and push it to geometry_data.
172             //
173 
174             break;
175 
176         default:
177             assert(!"Unsupported geometry type.");
178             break;
179         }
180     }
181 
182     // Returns minimal tnear needed to compensate double to float transition of ray fields.
get_tnear_offset(const RTCRay & ray)183     float get_tnear_offset(const RTCRay& ray)
184     {
185         float max_dir_component = max(abs(ray.dir_x), abs(ray.dir_y), abs(ray.dir_z));
186         uint32 max_origin_exp = max(
187             FP<float>::exponent(ray.org_x),
188             FP<float>::exponent(ray.org_y),
189             FP<float>::exponent(ray.org_z));
190 
191         // Calculate exponent-adaptive offset.
192         // Note: float is represented in memory
193         // as 1 sign bit, 8 exponent bits and 23 mantissa bits.
194         // Higher 24th bit is always 1 in normalized form, hence it's ommited.
195         // Mantissa of constructed float will overlap no more than 11 last bits of
196         // origin components due to exponent shift.
197         // Mantissa of constructed float is just a
198         // sequence of 11 ones followed by zeroes.
199 
200         const float offset = FP<float>::construct(
201             0,
202             max(static_cast<int32>(max_origin_exp - 23 + 11), 0),
203             2047UL << (23 - 11));
204 
205         // Divide by max_dir_component to compensate inverse operation
206         // during intersection search. (Actual start point is org + dir * tnear)
207         return offset / max_dir_component;
208     }
209 
shading_ray_to_embree_ray(const ShadingRay & shading_ray,RTCRay & embree_ray)210     void shading_ray_to_embree_ray(
211         const ShadingRay&       shading_ray,
212         RTCRay&                 embree_ray)
213     {
214         embree_ray.org_x = static_cast<float>(shading_ray.m_org.x);
215         embree_ray.org_y = static_cast<float>(shading_ray.m_org.y);
216         embree_ray.org_z = static_cast<float>(shading_ray.m_org.z);
217 
218         embree_ray.dir_x = static_cast<float>(shading_ray.m_dir.x);
219         embree_ray.dir_y = static_cast<float>(shading_ray.m_dir.y);
220         embree_ray.dir_z = static_cast<float>(shading_ray.m_dir.z);
221 
222         embree_ray.tfar = static_cast<float>(shading_ray.m_tmax);
223         embree_ray.time = static_cast<float>(shading_ray.m_time.m_normalized);
224         embree_ray.mask = shading_ray.m_flags;
225 
226         const float tnear_offset = get_tnear_offset(embree_ray);
227 
228         embree_ray.tnear = static_cast<float>(shading_ray.m_tmin) + tnear_offset;
229     }
230 }
231 
232 
233 //
234 //  EmbreeDevice class implementation.
235 //
236 
EmbreeDevice()237 EmbreeDevice::EmbreeDevice()
238 {
239     // todo: set number of threads.
240     m_device = rtcNewDevice(nullptr);
241 };
242 
~EmbreeDevice()243 EmbreeDevice::~EmbreeDevice()
244 {
245     rtcReleaseDevice(m_device);
246 }
247 
248 
249 //
250 //  EmbreeScene class implementation.
251 //
252 
EmbreeScene(const EmbreeScene::Arguments & arguments)253 EmbreeScene::EmbreeScene(const EmbreeScene::Arguments& arguments)
254 {
255     // Start stopwatch.
256     Stopwatch<DefaultWallclockTimer> stopwatch;
257     stopwatch.start();
258 
259     Statistics statistics;
260 
261     m_device = arguments.m_device.m_device;
262     m_scene = rtcNewScene(m_device);
263 
264     rtcSetSceneBuildQuality(
265         m_scene,
266         RTCBuildQuality::RTC_BUILD_QUALITY_HIGH);
267 
268     const ObjectInstanceContainer& instance_container = arguments.m_assembly.object_instances();
269 
270     const size_t instance_count = instance_container.size();
271 
272     m_geometry_container.reserve(instance_count);
273 
274     for (size_t instance_idx = 0; instance_idx < instance_count; ++instance_idx)
275     {
276         const ObjectInstance* object_instance = instance_container.get_by_index(instance_idx);
277         assert(object_instance);
278 
279         RTCGeometry geometry_handle;
280 
281         // Set per instance data.
282         unique_ptr<EmbreeGeometryData> geometry_data(new EmbreeGeometryData());
283         geometry_data->m_object_instance_idx = instance_idx;
284         geometry_data->m_vis_flags = object_instance->get_vis_flags();
285 
286         //
287         // Collect geometry data for the instance.
288         //
289         const char* object_model = object_instance->get_object().get_model();
290 
291         if (strcmp(object_model, MeshObjectFactory().get_model()) == 0)
292         {
293             geometry_data->m_geometry_type = RTC_GEOMETRY_TYPE_TRIANGLE;
294 
295             // Retrieve triangle data.
296             collect_triangle_data(*object_instance, *geometry_data);
297 
298             geometry_handle = rtcNewGeometry(
299                 m_device,
300                 RTC_GEOMETRY_TYPE_TRIANGLE);
301 
302             rtcSetGeometryBuildQuality(
303                 geometry_handle,
304                 RTCBuildQuality::RTC_BUILD_QUALITY_HIGH);
305 
306             rtcSetGeometryTimeStepCount(
307                 geometry_handle,
308                 geometry_data->m_motion_steps_count);
309 
310             geometry_data->m_geometry_handle = geometry_handle;
311 
312             const unsigned int vertices_count = geometry_data->m_vertices_count;
313             const unsigned int vertices_stride = geometry_data->m_vertices_stride;
314 
315             for (unsigned int m = 0; m < geometry_data->m_motion_steps_count; ++m)
316             {
317                 // Byte offset for the current motion segment.
318                 const unsigned int vertices_offset = m * vertices_count * vertices_stride;
319 
320                 // Set vertices.
321                 rtcSetSharedGeometryBuffer(
322                     geometry_handle,                            // geometry
323                     RTC_BUFFER_TYPE_VERTEX,                     // buffer type
324                     m,                                          // slot
325                     RTC_FORMAT_FLOAT3,                          // format
326                     geometry_data->m_vertices,                  // buffer
327                     vertices_offset,                            // byte offset
328                     vertices_stride,                            // byte stride
329                     vertices_count);                            // item count
330             }
331 
332             // Set vertex indices.
333             rtcSetSharedGeometryBuffer(
334                 geometry_handle,                                // geometry
335                 RTC_BUFFER_TYPE_INDEX,                          // buffer type
336                 0,                                              // slot
337                 RTC_FORMAT_UINT3,                               // format
338                 geometry_data->m_primitives,                    // buffer
339                 0,                                              // byte offset
340                 geometry_data->m_primitives_stride,             // byte stride
341                 geometry_data->m_primitives_count);             // item count
342 
343             rtcSetGeometryMask(
344                 geometry_handle,
345                 geometry_data->m_vis_flags);
346 
347             rtcCommitGeometry(geometry_handle);
348         }
349         else if (strcmp(object_model, CurveObjectFactory().get_model()) == 0)
350         {
351             geometry_data->m_geometry_type = RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE;
352 
353             // Retrieve curve data.
354             collect_curve_data(*object_instance, *geometry_data);
355 
356             geometry_handle = rtcNewGeometry(
357                 m_device,
358                 RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE);
359 
360             rtcSetGeometryBuildQuality(
361                 geometry_handle,
362                 RTCBuildQuality::RTC_BUILD_QUALITY_HIGH);
363 
364             // Set vertices. (x_pos, y_pos, z_pos, radii)
365             rtcSetSharedGeometryBuffer(
366                 geometry_handle,                                // geometry
367                 RTC_BUFFER_TYPE_INDEX,                          // buffer type
368                 0,                                              // slot
369                 RTC_FORMAT_FLOAT4,                              // format
370                 geometry_data->m_vertices,                      // buffer
371                 0,                                              // byte offset
372                 geometry_data->m_vertices_stride,               // byte stride
373                 geometry_data->m_vertices_count);               // item count
374 
375             // Set vertex indices.
376             rtcSetSharedGeometryBuffer(
377                 geometry_handle,                                // geometry
378                 RTC_BUFFER_TYPE_INDEX,                          // buffer type
379                 0,                                              // slot
380                 RTC_FORMAT_UINT4,                               // format
381                 geometry_data->m_primitives,                    // buffer
382                 0,                                              // byte offset
383                 geometry_data->m_primitives_stride,             // byte stride
384                 geometry_data->m_primitives_count);             // item count
385 
386         }
387         else
388         {
389             // Unsupported object type.
390             continue;
391         }
392 
393         rtcAttachGeometryByID(m_scene, geometry_handle, static_cast<unsigned int>(instance_idx));
394         m_geometry_container.push_back(std::move(geometry_data));
395     }
396 
397     rtcCommitScene(m_scene);
398 
399     statistics.insert_time("total build time", stopwatch.measure().get_seconds());
400 
401     RENDERER_LOG_DEBUG("%s",
402         StatisticsVector::make(
403             "Embree scene #" + to_string(arguments.m_assembly.get_uid()) + " statistics",
404             statistics).to_string().c_str());
405 }
406 
~EmbreeScene()407 EmbreeScene::~EmbreeScene()
408 {
409     rtcReleaseScene(m_scene);
410 }
411 
intersect(ShadingPoint & shading_point) const412 void EmbreeScene::intersect(ShadingPoint& shading_point) const
413 {
414     RTCIntersectContext context;
415     rtcInitIntersectContext(&context);
416 
417     RTCRayHit rayhit;
418     shading_ray_to_embree_ray(shading_point.get_ray(), rayhit.ray);
419 
420     rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
421 
422     rtcIntersect1(m_scene, &context, &rayhit);
423 
424     if (rayhit.hit.geomID != RTC_INVALID_GEOMETRY_ID)
425     {
426         assert(rayhit.hit.geomID < m_geometry_container.size());
427 
428         const auto& geometry_data = m_geometry_container[rayhit.hit.geomID];
429         assert(geometry_data);
430 
431         shading_point.m_bary[0] = rayhit.hit.u;
432         shading_point.m_bary[1] = rayhit.hit.v;
433 
434         shading_point.m_object_instance_index = geometry_data->m_object_instance_idx;
435         // TODO: remove regions
436         shading_point.m_primitive_index = rayhit.hit.primID;
437         shading_point.m_primitive_type = ShadingPoint::PrimitiveTriangle;
438         shading_point.m_ray.m_tmax = rayhit.ray.tfar;
439 
440         const uint32 v0_idx = geometry_data->m_primitives[rayhit.hit.primID * 3];
441         const uint32 v1_idx = geometry_data->m_primitives[rayhit.hit.primID * 3 + 1];
442         const uint32 v2_idx = geometry_data->m_primitives[rayhit.hit.primID * 3 + 2];
443 
444         if (geometry_data->m_motion_steps_count > 1)
445         {
446             const uint32 last_motion_step_idx = geometry_data->m_motion_steps_count - 1;
447 
448             const uint32 motion_step_begin_idx = static_cast<uint32>(rayhit.ray.time * last_motion_step_idx);
449             const uint32 motion_step_end_idx = motion_step_begin_idx + 1;
450 
451             const uint32 motion_step_begin_offset = motion_step_begin_idx * geometry_data->m_vertices_count;
452             const uint32 motion_step_end_offset = motion_step_end_idx * geometry_data->m_vertices_count;
453 
454             const float motion_step_begin_time = static_cast<float>(motion_step_begin_idx) / last_motion_step_idx;
455 
456             // Linear interpolation coefficients.
457             const float p = (rayhit.ray.time - motion_step_begin_time) * last_motion_step_idx;
458             const float q = 1.0f - p;
459 
460             assert(p > 0.0f && p <= 1.0f);
461 
462             const TriangleType triangle(
463                 Vector3d(
464                     geometry_data->m_vertices[motion_step_begin_offset + v0_idx] * q
465                     + geometry_data->m_vertices[motion_step_end_offset + v0_idx] * p),
466                 Vector3d(
467                     geometry_data->m_vertices[motion_step_begin_offset + v1_idx] * q
468                     + geometry_data->m_vertices[motion_step_end_offset + v1_idx] * p),
469                 Vector3d(
470                     geometry_data->m_vertices[motion_step_begin_offset + v2_idx] * q
471                     + geometry_data->m_vertices[motion_step_end_offset + v2_idx] * p));
472 
473             shading_point.m_triangle_support_plane.initialize(triangle);
474         }
475         else
476         {
477             const TriangleType triangle(
478                 Vector3d(geometry_data->m_vertices[v0_idx]),
479                 Vector3d(geometry_data->m_vertices[v1_idx]),
480                 Vector3d(geometry_data->m_vertices[v2_idx]));
481 
482             shading_point.m_triangle_support_plane.initialize(triangle);
483         }
484     }
485 }
486 
occlude(const ShadingRay & shading_ray) const487 bool EmbreeScene::occlude(const ShadingRay& shading_ray) const
488 {
489     RTCIntersectContext context;
490     rtcInitIntersectContext(&context);
491 
492     RTCRay ray;
493     shading_ray_to_embree_ray(shading_ray, ray);
494 
495     rtcOccluded1(
496         m_scene,
497         &context,
498         &ray);
499 
500     if (ray.tfar < signed_min<float>())
501         return true;
502 
503     return false;
504 }
505 
EmbreeSceneFactory(const EmbreeScene::Arguments & arguments)506 EmbreeSceneFactory::EmbreeSceneFactory(const EmbreeScene::Arguments& arguments)
507   : m_arguments(arguments)
508 {
509 }
510 
create()511 unique_ptr<EmbreeScene> EmbreeSceneFactory::create()
512 {
513     return unique_ptr<EmbreeScene>(new EmbreeScene(m_arguments));
514 }
515 
516 }   // namespace renderer
517