NVIDIA Index example code nvidia_logo_transpbg.gif Up
ray_sampling.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright 2023 NVIDIA Corporation. All rights reserved.
3 *****************************************************************************/
6
7
15
16
17// Include code shared by all examples.
18#define USE_NVINDEX_ACCESS
19#include "utility/example_shared.h"
20
21
22#include <nv/index/icamera.h>
23#include <nv/index/iindex.h>
24#include <nv/index/iscene.h>
25#include <nv/index/isession.h>
26#include <nv/index/icolormap.h>
27#include <nv/index/isampling_rays.h>
28#include <nv/index/iindex_debug_configuration.h>
29
30#include <nv/index/app/index_connect_.h> // FIXME should be updated to index_connect.h
31
32#include "utility/app_rendering_context.h"
33#include "utility/canvas_utility.h"
34#include "utility/example_performance_logger.h"
35
36#include <iostream>
37#include <sstream>
38#include <fstream>
39#include <iomanip>
40#include <vector>
41#include <algorithm>
42
43//----------------------------------------------------------------------
44namespace { // anonymous namespace for the local functions
45//----------------------------------------------------------------------
46class Create_ray_sampling_index_connect:
47 public nv::index::app::Index_connect
48{
49public:
50 Create_ray_sampling_index_connect()
51 :
52 Index_connect()
53 {
54 // INFO_LOG << "DEBUG: Create_ray_sampling_index_connect() ctor";
55 }
56
57 virtual ~Create_ray_sampling_index_connect()
58 {
59 // Note: Index_connect::~Index_connect() will be called after here.
60 // INFO_LOG << "DEBUG: ~Create_ray_sampling_index_connect() dtor";
61 }
62
63 // launch application
64 mi::Sint32 launch();
65
66protected:
67 // virtual bool evaluate_options(nv::index::app::String_dict& sdict) CPP11_OVERRIDE;
68 // override
69 virtual bool initialize_networking(
70 mi::neuraylib::INetwork_configuration* network_configuration,
71 nv::index::app::String_dict& options) CPP11_OVERRIDE
72 {
73 check_success(network_configuration != 0);
74
75 check_success(options.is_defined("unittest"));
76 const bool is_unittest = nv::index::app::get_bool(options.get("unittest"));
77 if (is_unittest)
78 {
79 info_cout("NETWORK: disabled networking mode.", options);
80 network_configuration->set_mode(mi::neuraylib::INetwork_configuration::MODE_OFF);
81 return true;
82 }
83
84 return initialize_networking_as_default_udp(network_configuration, options);
85 }
86protected:
87
88private:
89 // This session tag
90 mi::neuraylib::Tag m_session_tag;
91 // NVIDIA IndeX cluster configuration
92 mi::base::Handle<nv::index::ICluster_configuration> m_cluster_configuration;
93 // Application layer image file canvas (a render target)
94 mi::base::Handle<nv::index::app::canvas_infrastructure::IIndex_image_file_canvas> m_image_file_canvas;
95 // Create_icons options
96 std::string m_outfname;
97 bool m_is_unittest;
98 // std::string m_verify_image_fname_sequence;
99 // std::string m_verify_image_fname;
100
101};
102
103
104// //----------------------------------------------------------------------
105// mi::Sint32 launch()
106// {
107
108// }
109
110// //----------------------------------------------------------------------
111// bool evaluate_options(nv::index::app::String_dict& sdict)
112// {
113
114// }
115
116//----------------------------------------------------------------------
117
118// Generate rays from the camera.
119class Camera_ray_generator
120{
121public:
122 // Setup ray generator using current scene and camera and image resolution.
123 Camera_ray_generator(
124 const nv::index::IScene* scene,
125 const nv::index::ICamera* camera,
126 const mi::math::Vector<mi::Uint32, 2>& resolution);
127
128 // Generate a ray with origin at camera position and direction controlled
129 // by pixel coordinates (using the orientation and projection settings of the camera).
130 bool compute_ray(
131 float raster_x,
132 float raster_y,
133 mi::math::Vector<mi::Float32, 3>& ray_origin,
134 mi::math::Vector<mi::Float32, 3>& ray_direction) const;
135
136 const mi::math::Vector<mi::Uint32, 2>& resolution() const {
137 return m_resolution;
138 }
139
140private:
141 struct Params
142 {
143 mi::math::Vector<mi::Float32, 3> ray_origin;
144 mi::math::Vector<mi::Float32, 3> right;
145 mi::math::Vector<mi::Float32, 3> up;
146 mi::math::Vector<mi::Float32, 3> to;
147 float x_mult;
148 float y_mult;
149 mi::math::Vector<mi::Float32, 3> image_origin;
150 mi::math::Matrix<mi::Float32, 4, 4> object_to_world_inv;
151 bool orthographic;
152 };
153
154 Params m_params;
155 mi::math::Vector<mi::Uint32, 2> m_resolution;
156 bool m_valid;
157};
158
159mi::math::Matrix<mi::Float64, 4, 4> get_camera_matrix(
160 const nv::index::ICamera* camera,
161 const mi::math::Vector<mi::Float32, 3>& global_translate)
162{
163 mi::math::Vector<mi::Float64, 3> eyepos(camera->get_eye_point());
164 eyepos -= mi::math::Vector<mi::Float64, 3>(global_translate);
165 mi::math::Vector<mi::Float64, 3> up_direction(camera->get_up_direction());
166
167 // Camera orthonormal basis. gluLookat manner (right hand)
168 mi::math::Vector<mi::Float64, 3> zdir(camera->get_view_direction());
169 zdir = -zdir; // -view dir
170 zdir.normalize();
171 mi::math::Vector<mi::Float64, 3> xdir = mi::math::cross(up_direction, zdir);
172 xdir.normalize();
173 mi::math::Vector<mi::Float64, 3> ydir = mi::math::cross(zdir, xdir);
174 ydir.normalize();
175
176 mi::math::Matrix<mi::Float64, 4, 4> lookat_mat(
177 xdir.x, ydir.x, zdir.x, 0.,
178 xdir.y, ydir.y, zdir.y, 0.,
179 xdir.z, ydir.z, zdir.z, 0.,
180 // reverse translation of origin in camera basis.
181 -mi::math::dot(xdir, eyepos),
182 -mi::math::dot(ydir, eyepos),
183 -mi::math::dot(zdir, eyepos),
184 1.0);
185 return lookat_mat;
186}
187
188
189
190Camera_ray_generator::Camera_ray_generator(
191 const nv::index::IScene* scene,
192 const nv::index::ICamera* camera,
193 const mi::math::Vector<mi::Uint32, 2>& resolution)
194 : m_resolution(resolution)
195 , m_valid(false)
196{
197 const bool is_persp_camera = nv::index::IPerspective_camera::compare_iid(camera->get_iid());
198 const bool is_ortho_camera = nv::index::IOrthographic_camera::compare_iid(camera->get_iid());
199 if (!is_persp_camera && !is_ortho_camera) {
200 return;
201 }
202
203 m_params.orthographic = is_ortho_camera;
204
205 mi::Float32 focal_length = 1.f;
206 mi::Float32 aperture = 0.33f;
207 mi::Float32 aspect = 1.f;
208
209 if (is_persp_camera) {
210 mi::base::Handle<const nv::index::IPerspective_camera> p_camera;
211 p_camera = camera->get_interface<const nv::index::IPerspective_camera>();
212 focal_length = static_cast<mi::Float32>(p_camera->get_focal());
213 aperture = static_cast<mi::Float32>(p_camera->get_aperture());
214 aspect = static_cast<mi::Float32>(p_camera->get_aspect());
215 }
216 if (is_ortho_camera) {
217 mi::base::Handle<const nv::index::IOrthographic_camera> o_camera;
218 o_camera = camera->get_interface<const nv::index::IOrthographic_camera>();
219 focal_length = 1.f;
220 aperture = static_cast<mi::Float32>(o_camera->get_aperture());
221 aspect = static_cast<mi::Float32>(o_camera->get_aspect());
222 }
223 if (focal_length <= 0.f) { return; }
224 if (aperture <= 0.f) { return; }
225 if (aspect <= 0.f) { return; }
226 if ((resolution.x == 0) || (resolution.y == 0)) { return; }
227
228
229 const mi::math::Matrix<mi::Float32, 4, 4> scene_xform = scene->get_transform_matrix();
230 const mi::math::Vector<mi::Float32, 3> scene_translation(scene_xform.wx, scene_xform.wy, scene_xform.wz);
231 const mi::math::Matrix<mi::Float64, 4, 4> world_to_camera = get_camera_matrix(camera, scene_translation);
232 mi::math::Matrix<mi::Float64, 4, 4> world_to_camera_inv = world_to_camera;
233 world_to_camera_inv.invert();
234
235 // origin = row3
236 mi::math::Vector<mi::Float32, 3> origin(
237 static_cast<float>(world_to_camera_inv.wx),
238 static_cast<float>(world_to_camera_inv.wy),
239 static_cast<float>(world_to_camera_inv.wz));
240
241 // right = -row0
242 m_params.right.x = static_cast<float>(-world_to_camera_inv.xx);
243 m_params.right.y = static_cast<float>(-world_to_camera_inv.xy);
244 m_params.right.z = static_cast<float>(-world_to_camera_inv.xz);
245 m_params.right.normalize();
246
247 // up = -row1
248 m_params.up.x = static_cast<float>(-world_to_camera_inv.yx);
249 m_params.up.y = static_cast<float>(-world_to_camera_inv.yy);
250 m_params.up.z = static_cast<float>(-world_to_camera_inv.yz);
251 m_params.up.normalize();
252
253 // to = -row2
254 m_params.to.x = static_cast<float>(-world_to_camera_inv.zx);
255 m_params.to.y = static_cast<float>(-world_to_camera_inv.zy);
256 m_params.to.z = static_cast<float>(-world_to_camera_inv.zz);
257 m_params.to.normalize();
258 m_params.to *= focal_length;
259
260
261 // object_to_world is scene transform without translation
262 mi::math::Matrix<mi::Float32, 4, 4> object_to_world = scene_xform;
263 object_to_world.wx = 0.f;
264 object_to_world.wy = 0.f;
265 object_to_world.wz = 0.f;
266 m_params.object_to_world_inv = object_to_world;
267 m_params.object_to_world_inv.invert();
268
269 m_params.ray_origin = mi::math::transform_point(m_params.object_to_world_inv, origin);
270
271 const mi::Float32 frustumwidth = aperture;
272 const mi::Float32 frustumheight = frustumwidth / aspect;
273 m_params.x_mult = frustumwidth / static_cast<float>(resolution.x);
274 m_params.y_mult = frustumheight / static_cast<float>(resolution.y);
275 m_params.image_origin =
276 (-0.5f * frustumwidth) * m_params.right +
277 (-0.5f * frustumheight) * m_params.up;
278
279 m_valid = true;
280}
281
282
283bool Camera_ray_generator::compute_ray(
284 float raster_x,
285 float raster_y,
286 mi::math::Vector<mi::Float32, 3>& ray_origin,
287 mi::math::Vector<mi::Float32, 3>& ray_direction) const
288{
289 if (!m_valid) return false;
290
291 // Compute pixel index value in the viewing plane to compute the ray through the pixel
292 const mi::math::Vector<mi::Float32, 3> x = m_params.right * (m_params.x_mult * raster_x);
293 const mi::math::Vector<mi::Float32, 3> y = m_params.up * (m_params.y_mult * raster_y);
294
295 const mi::math::Vector<mi::Float32, 3> pixel = m_params.image_origin + x + y;
296
297 using mi::math::transform_vector;
298 if (m_params.orthographic) {
299 // Orthographic projection
300 // Ray origin in object space
301 ray_origin = m_params.ray_origin - transform_vector(m_params.object_to_world_inv, pixel);
302 ray_direction = transform_vector(m_params.object_to_world_inv, m_params.to);
303 }
304 else {
305 // Perspective projection
306 ray_origin = m_params.ray_origin;
307 // Ray direction: transform from world to object space
308 ray_direction = transform_vector(m_params.object_to_world_inv, m_params.to - pixel);
309 }
310 ray_direction.normalize();
311
312 return true;
313}
314
315//----------------------------------------------------------------------
316// Start IndeX service
318 Nvindex_access& nvindex_accessor,
319 std::map<std::string, std::string>& opt_map,
321{
322 info_cout(std::string("NVIDIA IndeX version: ") + nvindex_accessor.get_interface()->get_version(), opt_map);
323
324 initialize_log_module(nvindex_accessor, opt_map);
325
326 // Register serializable classes
327 scene_setup->register_classes(nvindex_accessor.get_interface().get());
328
329 // check the triangle mesh serializer/deserializer
330 // Do not use remote logging
331 mi::base::Handle<mi::neuraylib::IDebug_configuration> debug_configuration(
332 nvindex_accessor.get_interface()->get_api_component<mi::neuraylib::IDebug_configuration>());
333 check_success(debug_configuration.is_valid_interface());
334 debug_configuration->set_option("check_serializer_store=1");
335
336
337 mi::base::Handle<nv::index::IIndex_debug_configuration> index_debug_cfg(
338 nvindex_accessor.get_interface()->get_api_component<nv::index::IIndex_debug_configuration>());
339 check_success(index_debug_cfg.is_valid_interface());
340 if (has_key(opt_map, "cuda_rtc_print_kernel_info")) {
341 index_debug_cfg->set_option("cuda_rtc_print_kernel_info=1");
342 }
343 if (has_key(opt_map, "cuda_rtc_load_sources_from_file")) {
344 index_debug_cfg->set_option("cuda_rtc_load_sources_from_file=1");
345 }
346 if (has_key(opt_map, "cuda_rtc_debug_info")) {
347 index_debug_cfg->set_option("cuda_rtc_debug_info=1");
348 }
349 if (has_key(opt_map, "cuda_rtc_disable")) {
350 index_debug_cfg->set_option("cuda_rtc_disable=1");
351 }
352 if (nv::index::app::get_bool(opt_map["profile"]) == true) {
353 index_debug_cfg->set_option("performance_values_wait=1");
354 }
355
356 // Start IndeX library && application_layer
357 nvindex_accessor.start_service();
358}
359
360
361void dump_text(const std::string& filename, const std::string& text)
362{
363 if (filename.empty()) { return; }
364 WARN_LOG << "Dumping user program '" << filename << "'";
365 std::ofstream fs(filename.c_str());
366 if (fs) {
367 fs << text;
368 }
369 fs.close();
370}
371
372void load_text(const std::string& filename, std::string& text)
373{
374 if (filename.empty()) { return; }
375 WARN_LOG << "Loading user program '" << filename << "'";
376 std::ifstream fs(filename.c_str(), std::ios_base::binary);
377 if (fs) {
378 fs.seekg(0, std::ios_base::end);
379 const size_t text_size = static_cast<size_t>(fs.tellg());
380 fs.seekg(0);
381 std::vector<char> buf(text_size + 1, '\0');
382 fs.read(buf.data(), text_size);
383 text = buf.data();
384 }
385 fs.close();
386}
387
388
389nv::index::IColormap* create_colormap(nv::index::IScene* scene)
390{
391 nv::index::IColormap* colormap = scene->create_attribute<nv::index::IColormap>();
392 std::vector<mi::math::Color_struct> colormap_entries;
393
394 colormap_entries.resize(256);
395 for(mi::Uint32 i=0; i<256; ++i)
396 {
397 colormap_entries[i].r = (255.f-static_cast<mi::Float32>(i))/255.f;
398 colormap_entries[i].g = (255.f-static_cast<mi::Float32>(255 - i))/255.f;
399 colormap_entries[i].b = 1.f;
400 colormap_entries[i].a = 0.5f;
401 }
402
403 // Set colormap domain
404 colormap->set_domain_boundary_mode(nv::index::IColormap::CLAMP_TO_EDGE);
405 colormap->set_domain(0.2f, 1.0f);
406
407 // Set the the colormap values.
408 colormap->set_colormap(&(colormap_entries[0]), colormap_entries.size());
409 return colormap;
410}
411
412
413
414//----------------------------------------------------------------------
415void view_all_bbox(
416 const mi::math::Vector<mi::Float32, 3>& from,
417 const mi::math::Vector<mi::Float32, 3>& up,
418 const mi::math::Bbox< mi::Float32, 3>& bbox,
419 const mi::neuraylib::Tag& camera_tag,
420 const mi::neuraylib::Tag& scene_tag,
421 mi::neuraylib::IDice_transaction* dice_transaction)
422{
423 check_success(dice_transaction != 0);
424
425 if(bbox.empty())
426 {
427 WARN_LOG << "Un-initialized bounding box and not updating the camera settings.";
428 return;
429 }
430
431 {
432 mi::base::Handle<nv::index::IPerspective_camera>
433 camera(dice_transaction->edit<nv::index::IPerspective_camera>(camera_tag));
434 check_success(camera.is_valid_interface());
435
436 mi::base::Handle<const nv::index::IScene> scene(dice_transaction->access<const nv::index::IScene>(scene_tag));
437 check_success(scene.is_valid_interface());
438
439 // Compute the new camera parameters
440 const mi::math::Bbox< mi::Float32, 3>& global_roi_bbox = scene->get_clipped_bounding_box();
441 const mi::math::Matrix<mi::Float32, 4, 4>& transform_mat = scene->get_transform_matrix();
442 const mi::math::Vector<mi::Float32, 3> new_min(mi::math::transform_point(transform_mat, global_roi_bbox.min));
443 const mi::math::Vector<mi::Float32, 3> new_max(mi::math::transform_point(transform_mat, global_roi_bbox.max));
444 const mi::math::Bbox< mi::Float32, 3> transformed_bbox(new_min, new_max);
445 const mi::math::Vector<mi::Float32, 3>& center = transformed_bbox.center();
446 const mi::Float32 rad = mi::math::euclidean_distance(transformed_bbox.max, transformed_bbox.min) / 2.0f;
447
448 const mi::Float32 fov_rad_2 = static_cast<mi::Float32>(camera->get_fov_y_rad() / 2.0);
449 const mi::Float32 dist = rad / static_cast<mi::Float32>(tan(fov_rad_2));
450
451 const mi::Float32 clip_min = 0.1f * dist;
452 const mi::Float32 clip_max = 10.f * dist;
453 camera->set_clip_min(clip_min);
454 camera->set_clip_max(clip_max);
455
456 const mi::math::Vector<mi::Float32, 3> eyepos = -dist * from + center;
457 mi::math::Vector<mi::Float32, 3> viewdir = center - eyepos;
458 check_success(viewdir.normalize());
459
460 camera->set(eyepos, viewdir, up);
461
462 INFO_LOG << "view_all_box: " << eyepos << viewdir << up << " clip:" << clip_min << " " << clip_max;
463 }
464}
465
466//----------------------------------------------------------------------
467// render a frame
468//
469// \param[in] arc application rendering context
470// \param[in] output_fname output rendering image filename
471nv::index::IFrame_results* render_frame(
472 App_rendering_context& arc,
473 const std::string& output_fname)
474{
475 check_success(arc.m_iindex_rendering.is_valid_interface());
476
477 // set output filename, empty string is valid
478 arc.m_image_canvas->set_rgba_file_name(output_fname.c_str());
479
480 check_success(arc.m_session_tag.is_valid());
481
482 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(
483 arc.m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
484 check_success(dice_transaction.is_valid_interface());
485
486 arc.m_iindex_session->update(arc.m_session_tag, dice_transaction.get());
487
488 mi::base::Handle<nv::index::IFrame_results> frame_results(
489 arc.m_iindex_rendering->render(
490 arc.m_session_tag,
491 arc.m_image_canvas.get(),
492 dice_transaction.get()));
493 check_success(frame_results.is_valid_interface());
494
495 dice_transaction->commit();
496
497 frame_results->retain();
498 return frame_results.get();
499}
500
501
502//----------------------------------------------------------------------
503void setup_app_context(App_rendering_context& arc, Nvindex_access& nvindex_accessor)
504{
505 arc.m_database = nvindex_accessor.get_interface()->get_api_component<mi::neuraylib::IDatabase>();
506 check_success(arc.m_database.is_valid_interface());
507
508 arc.m_global_scope = arc.m_database->get_global_scope();
509 check_success(arc.m_global_scope.is_valid_interface());
510
511 // IIndex session to create a session
512 arc.m_iindex_session = nvindex_accessor.get_interface()->get_api_component<nv::index::IIndex_session>();
513 check_success(arc.m_iindex_session.is_valid_interface());
514
515 arc.m_iindex_rendering = nvindex_accessor.get_interface()->create_rendering_interface();
516 check_success(arc.m_iindex_rendering.is_valid_interface());
517
518 arc.m_icluster_configuration = nvindex_accessor.get_interface()->get_api_component<nv::index::ICluster_configuration>();
519 check_success(arc.m_icluster_configuration.is_valid_interface());
520
521 // create image canvas in application_layer
522 arc.m_image_canvas = nvindex_accessor.create_image_file_canvas();
523 check_success(arc.m_image_canvas.is_valid_interface());
524}
525
526
527const unsigned int num_scenes = 8;
529{
530 static const irregular_volume::Irregular_volume_setup ivol_setup;
531 static const sparse_volume::Sparse_volume_setup svol_setup;
532 static const heightfield::Heightfield_setup hfield_setup;
533 static const lod_heightfield::Lod_heightfield_setup lodhfield_setup;
534 static const trianglemesh::Trianglemesh_setup trimesh_setup;
535 static const simple_shapes::Simple_shapes_setup shapes_setup;
536 static const overlap::Overlapping_samples_setup overlap_setup;
537
538 const ray_sampling::IRay_sampling_scene_setup* scene_setup = &ivol_setup;
539
540 switch (i) {
541 // case 0 (regular volume) has been removed
542 case 1: scene_setup = &ivol_setup; break;
543 case 2: scene_setup = &svol_setup; break;
544 case 3: scene_setup = &hfield_setup; break;
545 case 4: scene_setup = &lodhfield_setup; break;
546 case 5: scene_setup = &trimesh_setup; break;
547 case 6: scene_setup = &shapes_setup; break;
548 case 7: scene_setup = &overlap_setup; break;
549 };
550 return scene_setup;
551}
552
553
554bool is_overlap_scene(/*const*/ std::map<std::string, std::string>& opt_map)
555{
556 return opt_map["scene"] == "7";
557}
558
559// const char* scene_name(int i)
560// {
561// if (const ray_sampling::IRay_sampling_scene_setup* stp = get_scene_setup(i)) {
562// return stp->name();
563// }
564// return "<Unknown Scene>";
565// }
566
567
568//----------------------------------------------------------------------
570 std::map<std::string, std::string>& opt_map,
571 int argc, char* argv[])
572{
573 const std::string com_name(argv[0]);
574 opt_map["user_program_mode"] = "2";
575 opt_map["user_values"] = "1";
576 opt_map["scene"] = "0";
577 opt_map["profile"] = "0"; // default: no profiling
578 opt_map["run_sampling"] = "1";
579
580 opt_map["dice::verbose"] = "3"; // log level
581 opt_map["roi"] = "0 0 0 0 0 0"; // input roi
582 opt_map["outfname"] = "frame_ray_sampling"; // output image file base name
583 opt_map["verify_image_fname"] = ""; // for unit test
584 opt_map["unittest"] = "0"; // default mode
585 opt_map["is_dump_comparison_image_when_failed"] = "1"; // default: dump images when failed.
586 opt_map["is_call_from_test"] = "0"; // default: not call from make check.
587 opt_map["export_sample_file"] = "";
588 opt_map["verify_sample_file"] = "";
589
590 for (unsigned int i = 0; i < num_scenes; ++i) {
591 get_scene_setup(i)->add_arguments(opt_map);
592 }
593
594 process_command_line(argc, argv, opt_map);
595
596 if (nv::index::app::get_bool(opt_map["unittest"]))
597 {
598 if (nv::index::app::get_bool(opt_map["is_call_from_test"]))
599 {
600 opt_map["is_dump_comparison_image_when_failed"] = "0";
601 }
602 opt_map["outfname"] = ""; // turn off file output in the unit test mode
603 opt_map["dice::verbose"] = "2";
604 }
605 info_cout(std::string("running ") + com_name, opt_map);
606 info_cout(std::string("outfname = [") + opt_map["outfname"] +
607 "], verify_image_fname = [" + opt_map["verify_image_fname"] +
608 "], dice::verbose = " + opt_map["dice::verbose"], opt_map);
609
610 // print help and exit if -h
611 if (opt_map.find("h") != opt_map.end()) {
612 const char* indent = " ";
613 std::cout
614 << "info: Usage: " << com_name << " [option]\n"
615 << "Option: [-h]\n"
616 << " Print this message\n\n";
617
618 std::cout
619 << indent << "[-scene n] \n"
620 << indent << " Choose scene type (default: " << opt_map["scene"] << ")\n"
621 << indent << " 0: regular volume ... removed\n"
622 << indent << " 1: irregular volume (ivol)\n"
623 << indent << " 2: sparse volume (svol)\n"
624 << indent << " 3: heightfield (hfield)\n"
625 << indent << " 4: lod heightfield (lodhfield)\n"
626 << indent << " 5: triangle mesh (tmesh)\n"
627 << indent << " 6: shapes (plane, sphere, cone, cylinder) \n"
628 << indent << " 7: overlap (overlapping volumes and surfaces) \n\n"
629
630 << indent << "[-user_program_mode n] \n"
631 << indent << " Enable user programs for scene elements (0:none, 1:only render, 2:with inquiry method)\n"
632 << indent << " (default: " << opt_map["user_program_mode"] << ")\n"
633 << indent << "[-user_values bool] \n"
634 << indent << " Enable user values for picking, (default: " << opt_map["user_values"] << ")\n"
635 << indent << "[-load_user_program FILENAME] \n"
636 << indent << " Load user program from file. \n"
637 << indent << "[-dump_user_program FILENAME] \n"
638 << indent << " Dump builtin user program to file. \n"
639 << indent << "[-profile bool]\n"
640 << indent << " Enable performance profiling (default:" << opt_map["profile"] << ")\n"
641 << indent << "[-run_sampling n]\n"
642 << indent << " How to perform ray sampling 1:post-render, 2:pre-render, 3:pre+post-render\n"
643 << indent << " (default: " << opt_map["run_sampling"] << ")\n"
644 << indent << "[-export_sample_file name] \n"
645 << indent << " Export file with sample values.\n"
646 << indent << "[-verify_sample_file name] \n"
647 << indent << " Verify sample values with file.\n"
648 << std::endl;
649
650 for (unsigned int i = 0; i < num_scenes; ++i) {
651 get_scene_setup(i)->usage_info(std::cout, indent, opt_map);
652 std::cout << "\n";
653 }
654
655 std::cout
656 << indent << "[-dice::verbose severity_level]\n"
657 << indent << " Verbosity level (3 is info.). (default: " + opt_map["dice::verbose"] << ")\n\n"
658 << indent << "[-roi \"float float float float float float\"]\n"
659 << indent << " Bounding box representing the region of interest (roi).\n"
660 << indent << "[-outfname string]\n"
661 << indent << " Name of the output ppm image file. When empty, no image file will be written.\n"
662 << indent << " A frame number and the extension (.ppm) will be added.\n"
663 << indent << " (default: '" << opt_map["outfname"] << "')\n\n"
664 << indent << "[-verify_image_fname [image_fname]]\n"
665 << indent << " When image_fname exist, verify the rendering image.\n"
666 << indent << " (default: '" << opt_map["verify_image_fname"] << "')\n\n"
667 << indent << "[-unittest bool]\n"
668 << indent << " When true, unit test mode.\n"
669 << indent << " (default: " << opt_map["unittest"] << ")\n"
670 << std::endl;
671 exit(1);
672 }
673
674 int iscene = nv::index::app::get_sint32(opt_map["scene"]);
675 const ray_sampling::IRay_sampling_scene_setup* scene_setup = get_scene_setup(iscene);
676
677 return scene_setup;
678}
679
680
681//----------------------------------------------------------------------
682void setup_scene(
683 Nvindex_access& nvindex_accessor,
685 App_rendering_context& arc,
686 /*const*/ std::map<std::string, std::string>& opt_map)
687{
688 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(
689 arc.m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
690 check_success(dice_transaction.is_valid_interface());
691 mi::neuraylib::IDice_transaction* transaction = dice_transaction.get();
692
693 // Setup session information
694 arc.m_session_tag = arc.m_iindex_session->create_session(transaction);
695 check_success(arc.m_session_tag.is_valid());
696 mi::base::Handle<const nv::index::ISession> session(
697 transaction->access<const nv::index::ISession>(arc.m_session_tag));
698 check_success(session.is_valid_interface());
699
700 {
701 mi::base::Handle<nv::index::IConfig_settings> config_settings(
702 transaction->edit<nv::index::IConfig_settings>(session->get_config()));
703 check_success(config_settings.is_valid_interface());
704
705 scene_setup->adjust_configuration(config_settings.get(), opt_map);
706
707 // test serial render/composite
708 if (false) {
709 config_settings->set_parallel_rendering_and_compositing(false);
710 }
711 }
712 //----------------------------------------------------------------------
713 // Scene setup: hierarchical scene description root node,
714 // scene parameters, camera.
715 //----------------------------------------------------------------------
716 mi::math::Bbox< mi::Float32, 3> roi_bbox = nv::index::app::get_bbox_from_string<mi::Float32,3>(std::string(opt_map["roi"]));
717 if (roi_bbox.empty() || roi_bbox.is_point()) {
718 roi_bbox = nv::index::app::get_bbox_from_string<mi::Float32,3>(scene_setup->get_roi_string());
719 }
720
721 // Create a hierarchical scene description
722 ray_sampling::Scene_info scene_info;
723 if (has_key(opt_map, "load_user_program")) {
724 load_text(opt_map["load_user_program"], scene_info.rtc_program_source);
725 }
726
727 check_success(scene_setup->create_scene(
728 nvindex_accessor.get_application_layer_interface(),
729 scene_info, roi_bbox, arc.m_session_tag, opt_map, transaction));
730
731 if (has_key(opt_map, "dump_user_program")) {
732 dump_text(opt_map["dump_user_program"], scene_info.rtc_program_source);
733 }
734
735 mi::neuraylib::Tag camera_tag = mi::neuraylib::NULL_TAG;
736 {
737 mi::base::Handle< nv::index::IScene > scene_edit(
738 dice_transaction->edit<nv::index::IScene>(session->get_scene()));
739 check_success(scene_edit.is_valid_interface());
740
741 // Create and edit a camera. Data distribution is based on the camera.
742 // (Because only visible massive data are considered)
743 mi::base::Handle< nv::index::IPerspective_camera > cam(
744 scene_edit->create_camera<nv::index::IPerspective_camera>());
745 check_success(cam.is_valid_interface());
746 camera_tag = dice_transaction->store(cam.get());
747 check_success(camera_tag.is_valid());
748 }
749
750 scene_setup->setup_camera(camera_tag, transaction);
751 const mi::math::Vector<mi::Uint32, 2> buffer_resolution(1024, 1024);
752 arc.m_image_canvas->set_resolution(buffer_resolution);
753
754 // scope for scene edit
755 {
756 mi::base::Handle<nv::index::IScene> scene(
757 transaction->edit<nv::index::IScene>(session->get_scene()));
758 check_success(scene.is_valid_interface());
759
760 // The the colormap to demonstrate color index color mapping.
761 mi::base::Handle<nv::index::IColormap> colormap(create_colormap(scene.get()));
762 check_success(colormap.is_valid_interface());
763
764 // Store in DiCE database.
765 const mi::neuraylib::Tag colormap_tag = transaction->store_for_reference_counting(
766 colormap.get(), mi::neuraylib::NULL_TAG, "colormap");
767 check_success(colormap_tag.is_valid());
768 scene->prepend(colormap_tag, transaction);
769
770
771 // Set the region of interest.
772 check_success(roi_bbox.is_volume());
773 scene->set_clipped_bounding_box(roi_bbox);
774
775
776 // Set the scene global transformation matrix.
777 // only change the coordinate system
778 const float sc = scene_setup->get_scene_scaling();
779 const mi::math::Matrix<mi::Float32, 4, 4> transform_mat(
780 sc, 0.f, 0.f, 0.f,
781 0.f, sc, 0.f, 0.f,
782 0.f, 0.f, -sc, 0.f,
783 0.f, 0.f, 0.f, 1.f
784 );
785 scene->set_transform_matrix(transform_mat);
786
787
788 // Set the current camera to the scene.
789 scene->set_camera(camera_tag);
790 }
791
792 if (false) {
793 const mi::math::Vector<mi::Float32, 3> from(0.0f, 0.0f, 1.0f);
794 const mi::math::Vector<mi::Float32, 3> up(0.0f, 1.0f, 0.0f);
795 view_all_bbox(from, up, roi_bbox, camera_tag, session->get_scene(), transaction);
796 }
797 transaction->commit();
798}
799
800
801//----------------------------------------------------------------------
802void handle_errors(const nv::index::IError_set* err_set)
803{
804 std::ostringstream os;
805 const mi::Uint32 nb_err = err_set->get_nb_errors();
806 for (mi::Uint32 e = 0; e < nb_err; ++e)
807 {
808 if (e != 0) os << '\n';
809 const mi::base::Handle<nv::index::IError> err(err_set->get_error(e));
810 os << err->get_error_string();
811 }
812
813 ERROR_LOG << "IIndex_rendering rendering call failed with the following error(s): " << '\n'
814 << os.str();
815}
816
817
818//----------------------------------------------------------------------
820 App_rendering_context& arc,
821 /*const*/ std::map<std::string, std::string>& opt_map)
822{
823 check_success(arc.m_global_scope.is_valid_interface());
824 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(
825 arc.m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
826 check_success(dice_transaction.is_valid_interface());
827 {
828 check_success(arc.m_session_tag.is_valid());
829 mi::base::Handle<const nv::index::ISession> session(
830 dice_transaction->access<nv::index::ISession const>(arc.m_session_tag));
831 check_success(session.is_valid_interface());
832
833 mi::base::Handle<nv::index::IConfig_settings> edit_config_settings(
834 dice_transaction->edit<nv::index::IConfig_settings>(session->get_config()));
835 check_success(edit_config_settings.is_valid_interface());
836
837 // performance related configuration examples.
838 const bool do_profiling = nv::index::app::get_bool(opt_map["profile"]);
839 edit_config_settings->set_monitor_performance_values(do_profiling);
840 }
841 dice_transaction->commit();
842}
843
844
845//----------------------------------------------------------------------
847 const nv::index::IPerformance_values* performance_values,
848 /*const*/ std::map<std::string, std::string>& opt_map,
849 const char* info = "")
850{
851 if (!performance_values) return;
852 if (nv::index::app::get_bool(opt_map["profile"]) == false) {
853 return;
854 }
855
856 Performance_table_logger perf_logger;
857
858 char const* const time_keys[] = {
859 // "time_rendering_horizon"
860 "time_rendering_volume",
861 // "time_rendering_volume_and_horizon"
862 // "time_intersection_lines_points",
863 "time_rendering_only",
864 "time_gpu_upload",
865 // "time_gpu_download",
866 "time_rendering",
867 "time_rendering_total_sum",
868 "time_compositing_stage",
869 // "time_image_compositing",
870 // "time_image_transfer",
871 "time_total_rendering",
872 // "time_total_compositing",
873 // "time_total_final_compositing",
874 "time_complete_frame",
875 // "time_frame_setup"
876 // "time_frame_finish"
877 // "time_avg_rendering",
878 0
879 };
880 char const* const value_keys[] = {
881 "frames_per_second",
882 // "nb_subcubes"
883 // "nb_subcubes_rendered"
884 // "size_volume_data_rendered",
885 // "size_horizon_data_rendered"
886 // "nb_horizon_triangles_rendered",
887 // "size_volume_data_upload"
888 // "size_rendering_results_download",
889 // "size_pinned_host_memory"
890 // "size_unpinned_host_memory"
891 // "size_gpu_memory",
892 // "nb_fragments",
893 // "is_using_gpu",
894 // "size_span_transfer",
895 // "size_span_transfer_compressed",
896 // "size_intermediate_image_transfer",
897 // "size_intermediate_image_transfer_compressed",
898 // "size_intermediate_image_composited",
899 // "nb_composited_leafs"
900 // "nb_considered_leafs_per_span",
901 // "nb_active_hosts",
902 // "nb_horizontal_spans"
903 // "nb_rendering_results_in_queue",
904 0,
905 };
906
907 perf_logger.append_keys(time_keys);
908 perf_logger.append_keys(value_keys);
909
910 INFO_LOG << info << " " << perf_logger.get_table(performance_values);
911}
912
913void print_sampling_performance(
914 const nv::index::IRay_sampling_result* smpl_result,
915 /*const*/ std::map<std::string, std::string>& opt_map)
916
917{
918 if (smpl_result) {
919 const mi::base::Handle<const nv::index::IPerformance_values> performance_values(
920 smpl_result->get_performance_values());
921 print_performance(performance_values.get(), opt_map, "Ray Sampling");
922 }
923}
924
925
927 const nv::index::IFrame_results* frame_results,
928 /*const*/ std::map<std::string, std::string>& opt_map)
929{
930 if (frame_results) {
931 const mi::base::Handle<const nv::index::IPerformance_values> performance_values(
932 frame_results->get_performance_values());
933 print_performance(performance_values.get(), opt_map, "Rendering");
934 }
935}
936
937//----------------------------------------------------------------------
938
939template<typename T>
940struct Print_one { void print(std::ostream& os, const T& item) { os << item; } };
941
942template<>
943struct Print_one<mi::math::Color_struct> {
944 void print(std::ostream& os, const mi::math::Color_struct& c) {
945 os << "(" << c.r << " " << c.g << " " << c.b << " " << c.a << ")";
946 }
947};
948
949
950struct Printer
951{
952 Printer() : item_sep(" ") {}
953
954 std::string item_sep;
955 std::string postfix;
956
957 template<typename T>
958 void print_array(std::ostream& os, const T* items, mi::Uint32 nb_items) const {
959 Print_one<T> p;
960 for (mi::Uint32 i = 0; i < nb_items; ++i) {
961 p.print(os, items[i]); os << item_sep;
962 }
963 os << postfix;
964 }
965
966 template<typename T>
967 void print(std::ostream& os, const std::vector<T>& vec) const {
968 this->print_array(os, vec.data(), static_cast<mi::Uint32>(vec.size()));
969 }
970
971 template<typename T>
972 void print_masked(std::ostream& os, const T* items, mi::Uint32 nb_items,
973 const mi::Uint32* masks, const mi::Uint32 mask) const
974 {
975 Print_one<T> p;
976 for (mi::Uint32 i = 0; i < nb_items; ++i) {
977 if (masks[i] & mask) {
978 p.print(os, items[i]);
979 }
980 else {
981 p.print(os, T(0));
982 }
983 os << item_sep;
984 }
985 os << postfix;
986 }
987
988 template<typename T>
989 void print_masked(std::ostream& os, std::vector<T>& vec,
990 const std::vector<mi::Uint32> masks, const mi::Uint32 mask) const
991 {
992 this->print_masked(os, vec.data(), static_cast<mi::Uint32>(vec.size()),
993 masks.data(), mask);
994 }
995};
996
997//=================================================================================================
998//
999// Example of ray sampling.
1000//
1001//-------------------------------------------------------------------------------------------------
1002
1003inline void make_camera_ray(
1004 nv::index::IRay_sampling_query::Ray& ray,
1005 const Camera_ray_generator& camera_ray_gen,
1006 float raster_x, float raster_y)
1007{
1008 mi::math::Vector<mi::Float32, 3> origin, direction;
1009 camera_ray_gen.compute_ray(raster_x, raster_y, origin, direction);
1010 ray.origin = origin;
1011 ray.direction = direction;
1012 ray.range.x = 0.f;
1013 ray.range.y = 1.0e30f;
1014}
1015
1016inline float pixel_center_adjusted(unsigned int v) { return float(v) + 0.5f; }
1017
1018
1019
1020
1021void setup_sample_rays(
1022 const Camera_ray_generator& ray_gen,
1023 nv::index::IRay_sampling_query::Ray* rays,
1024 mi::Uint32 nb_rays)
1025{
1026 float center_x = static_cast<float>(pixel_center_adjusted(ray_gen.resolution().x / 2));
1027 float center_y = static_cast<float>(pixel_center_adjusted(ray_gen.resolution().y / 2));
1028
1029 for (mi::Uint32 i=0; i < nb_rays; ++i) {
1030 float x = center_x + float(i);
1031 float y = center_y + float(i/4);
1032 make_camera_ray(rays[i], ray_gen, x, y);
1033 }
1034}
1035
1036
1037//----------------------------------------------------------------------
1038
1039mi::base::Handle<const nv::index::IRay_sampling_result>
1040perform_ray_sampling(
1041 App_rendering_context& arc,
1042 nv::index::IIndex* nvindex,
1043 /*const*/ std::map<std::string, std::string>& opt_map)
1044{
1045
1046 mi::base::Handle<mi::neuraylib::IDice_transaction> transaction(
1047 arc.m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
1048 check_success(transaction.is_valid_interface());
1049
1050 mi::base::Handle<const nv::index::ISession> session(
1051 transaction->access<const nv::index::ISession>(arc.m_session_tag));
1052 check_success(session.is_valid_interface());
1053
1054 mi::base::Handle<const nv::index::IScene> scene(
1055 transaction->access<const nv::index::IScene>(session->get_scene()));
1056 check_success(scene.is_valid_interface());
1057
1058 mi::base::Handle<const nv::index::ICamera> camera(
1059 transaction->access<const nv::index::ICamera>(scene->get_camera()));
1060 check_success(camera.is_valid_interface());
1061
1062 Camera_ray_generator ray_gen(
1063 scene.get(),
1064 camera.get(),
1065 arc.m_image_canvas->get_resolution());
1066
1067
1068 // needed?
1069 arc.m_iindex_session->update(arc.m_session_tag, transaction.get());
1070
1071
1072 // Access the ray sampling interface.
1073 mi::base::Handle<nv::index::IRay_sampling> ray_sampling(
1074 nvindex->get_api_component<nv::index::IRay_sampling>());
1075 check_success(ray_sampling.is_valid_interface());
1076
1077
1078 const bool enable_user_values =
1079 nv::index::app::get_bool(opt_map["user_values"]) &&
1080 (nv::index::app::get_sint32(opt_map["user_program_mode"]) >= 2);
1081 mi::base::Handle<nv::index::IRay_sampling_value_format> user_value_format;
1082 if (enable_user_values) {
1083 // Create user value format.
1084 // This is optional, only needed when the CUDA render program writes user values.
1085 // The value format is shared by all CUDA render programs of the scene.
1086 //
1087 user_value_format = ray_sampling->create_sampling_value_format();
1088 check_success(user_value_format.is_valid_interface());
1089 const mi::Uint32 nb_values = 3;
1090 const mi::Uint32 value_sizes[nb_values] = {
1091 static_cast<mi::Uint32>(sizeof(mi::Float32)),
1092 static_cast<mi::Uint32>(sizeof(mi::Sint32)),
1093 static_cast<mi::Uint32>(sizeof(mi::math::Vector<mi::Float32, 3>)), // Representing a normal (x,y,z).
1094 };
1095 user_value_format->set_value_sizes(value_sizes, nb_values);
1096 }
1097
1098 // Create ray sampling query.
1099 mi::base::Handle<nv::index::IRay_sampling_query> ray_query(ray_sampling->create_sampling_query());
1100 check_success(ray_query.is_valid_interface());
1101
1102
1103 // Set up the query.
1104 const mi::Uint32 max_samples = 1000;
1105 const mi::Uint32 nb_rays = 1;
1106 nv::index::IRay_sampling_query::Ray rays[nb_rays];
1107
1108
1109 if (is_overlap_scene(opt_map)) {
1110 // generate ray through explicit pixel
1111 make_camera_ray(rays[0], ray_gen, 313, 1024 - 444);
1112 }
1113 else {
1114 setup_sample_rays(ray_gen, rays, nb_rays);
1115 }
1116
1117 ray_query->set_rays(rays, nb_rays);
1118 ray_query->set_max_samples(max_samples);
1119 check_success(ray_query->is_valid());
1120
1121 // Perform the query.
1122 mi::base::Handle<const nv::index::IRay_sampling_result> smpl_result;
1123 smpl_result = ray_sampling->sample_scene(
1124 ray_query.get(),
1125 user_value_format.get(),
1126 arc.m_iindex_rendering.get(),
1127 arc.m_session_tag,
1128 transaction.get());
1129
1130 transaction->commit();
1131
1132
1133 return smpl_result;
1134}
1135
1136
1137//----------------------------------------------------------------------
1138
1139void print_sampling_diagnostics(
1140 const nv::index::IRay_sampling_result* smpl_result,
1141 mi::neuraylib::IDice_transaction* dice_transaction)
1142{
1143 check_success(smpl_result != NULL);
1144 if (!smpl_result->is_valid()) {
1145 ERROR_LOG << "Invalid ray sampling result.";
1146 return;
1147 }
1148
1149 mi::base::Handle<const nv::index::IRay_sampling_query> query(smpl_result->get_query());
1150 mi::base::Handle<const nv::index::IRay_sampling_value_format> value_format(smpl_result->get_value_format());
1151
1152 check_success(query.is_valid_interface());
1153 if (query->get_nb_rays() < 1) {
1154 return;
1155 }
1156
1157 const mi::Uint32 ray_idx = 0;
1158 const mi::Uint32 nb_samples = smpl_result->get_nb_samples(ray_idx);
1159 std::ostringstream ss;
1160 ss << "Ray sampling - got " << nb_samples << " samples.";
1161
1162 if (nb_samples == 0) {
1163 INFO_LOG << ss.str();
1164 return;
1165 }
1166
1167 // Restrict print-out to first 15 samples.
1168 const mi::Uint32 nb_first_samples = std::min(nb_samples, 15u);
1169 nv::index::IRay_sampling_result::Sample_range srange;
1170 srange.first_sample = 0;
1171 srange.nb_samples = nb_first_samples;
1172 srange.ray_index = ray_idx;
1173
1174
1175 std::vector<mi::Float32> distances(nb_first_samples);
1176 check_success(smpl_result->get_distances(srange, distances.data()));
1177
1178 std::vector<mi::math::Color_struct> colors(nb_first_samples);
1179 check_success(smpl_result->get_colors(srange, colors.data()));
1180
1181 std::vector<mi::Uint32> object_ids(nb_first_samples);
1182 check_success(smpl_result->get_object_ids(srange, object_ids.data()));
1183
1184
1185 Printer printer;
1186 printer.postfix = nb_first_samples < nb_samples ? " ..." : "";
1187
1188 ss << "\ndistances: \n " << std::setprecision(4);
1189 printer.print(ss, distances);
1190
1191 ss << "\ncolors: \n " << std::setprecision(3);
1192 printer.item_sep = "\n ";
1193 printer.print(ss, colors);
1194
1195 ss << "\nobject ids: \n ";
1196 printer.item_sep = " ";
1197 printer.print(ss, object_ids);
1198
1199
1200 // Inspect object info.
1201 ss << "\nobject infos: #" << smpl_result->get_nb_object_infos() << "\n";
1202 // We could enumerate all object_infos from 0 to get_nb_object_infos()
1203 // but instead we collect all object ids found in the given sample range for demonstration purposes.
1204 std::vector<mi::Uint32> all_obj_ids = object_ids;
1205 std::sort(all_obj_ids.begin(), all_obj_ids.end());
1206 all_obj_ids.resize(std::distance(all_obj_ids.begin(),
1207 std::unique(all_obj_ids.begin(), all_obj_ids.end())));
1208 for (std::vector<mi::Uint32>::const_iterator it = all_obj_ids.begin();
1209 it != all_obj_ids.end(); ++it)
1210 {
1211 ss << " [" << *it << "]: ";
1212 mi::base::Handle<const nv::index::IRay_sampling_object_info> obj_info(
1213 smpl_result->get_object_info(*it));
1214 if (!obj_info.is_valid_interface()) {
1215 ss << "INVALID";
1216 }
1217 else {
1218 mi::neuraylib::Tag tag = obj_info->get_scene_element();
1219 ss << "tag: " << tag;
1220 if (const char* name = dice_transaction->tag_to_name(tag)) {
1221 ss << " ('" << name << "')";
1222 }
1223 mi::base::Handle<const nv::index::IScene_path> scene_path(
1224 obj_info->get_scene_path());
1225 if (scene_path.is_valid_interface()) {
1226 ss << " scene_path: ";
1227 for (mi::Uint32 si = 0, nb = scene_path->get_length(); si < nb; ++si) {
1228 ss << scene_path->get_node(si) << " ";
1229 }
1230 }
1231 }
1232 ss << "\n";
1233 }
1234
1235
1236 // user values
1237 if (value_format.is_valid_interface()) {
1238 check_success(value_format->get_nb_values() == 3);
1239 check_success(value_format->get_value_size(0) == static_cast<mi::Uint32>(sizeof(float)));
1240
1241 std::vector<mi::Float32> values1(nb_first_samples);
1242 std::vector<mi::Sint32> values2(nb_first_samples);
1243 std::vector<mi::math::Vector<mi::Float32, 3> > values3(nb_first_samples);
1244 std::vector<mi::Uint32> value_masks(nb_first_samples);
1245 check_success(smpl_result->get_user_value_masks(srange, value_masks.data()));
1246 check_success(smpl_result->get_user_values(srange, 0 /*value_index*/, values1.data()));
1247 check_success(smpl_result->get_user_values(srange, 1 /*value_index*/, values2.data()));
1248 check_success(smpl_result->get_user_values(srange, 2 /*value_index*/, values3.data()));
1249 ss << "\nuser value masks: \n ";
1250 printer.item_sep = " ";
1251 printer.print(ss, value_masks);
1252
1253 ss << "\nuser values1: \n ";
1254 printer.item_sep = "\n ";
1255 printer.print_masked(ss, values1, value_masks, 1u << 0);
1256 ss << "\nuser values2: \n ";
1257 printer.item_sep = " ";
1258 printer.print_masked(ss, values2, value_masks, 1u << 1);
1259 ss << "\nuser values3: \n ";
1260 printer.item_sep = "\n ";
1261 printer.print_masked(ss, values3, value_masks, 1u << 2);
1262 }
1263
1264 INFO_LOG << ss.str();
1265}
1266
1267
1268//----------------------------------------------------------------------
1269
1270void determine_first_opaque_sample(const nv::index::IRay_sampling_result* smpl_result)
1271{
1272 const char* info = " Determine first opaque sample:\n ";
1273
1274 check_success(smpl_result != 0);
1275 if (!smpl_result->is_valid()) {
1276 ERROR_LOG << info << "Invalid ray sampling result.\n";
1277 return;
1278 }
1279
1280 mi::base::Handle<const nv::index::IRay_sampling_query> query(smpl_result->get_query());
1281 mi::base::Handle<const nv::index::IRay_sampling_value_format> value_format(smpl_result->get_value_format());
1282
1283 check_success(query.is_valid_interface());
1284 if (query->get_nb_rays() < 1) {
1285 ERROR_LOG << info << "No sample ray.\n";
1286 return;
1287 }
1288
1289 const mi::Uint32 ray_idx = 0;
1290 const mi::Uint32 nb_samples = smpl_result->get_nb_samples(ray_idx);
1291
1292 if (nb_samples == 0) {
1293 INFO_LOG << info << "No sample found.\n";
1294 return;
1295 }
1296
1297 nv::index::IRay_sampling_result::Sample_range srange;
1298 srange.first_sample = 0;
1299 srange.nb_samples = nb_samples;
1300 srange.ray_index = ray_idx;
1301
1302 std::vector<mi::math::Color_struct> colors(nb_samples);
1303 check_success(smpl_result->get_colors(srange, colors.data()));
1304
1305 mi::Uint32 opaque_idx = nb_samples;
1306 for (mi::Uint32 i = 0; i < nb_samples; ++i) {
1307 if (colors[i].a >= 0.99f) {
1308 opaque_idx = i;
1309 break;
1310 }
1311 }
1312 if (opaque_idx == nb_samples) {
1313 INFO_LOG << info << "No opaque color was found in samples.\n";
1314 return;
1315 }
1316
1317 srange.first_sample = opaque_idx;
1318 srange.nb_samples = 1;
1319
1320 const mi::math::Color color = colors[opaque_idx];
1321
1322 mi::Float32 distance = 0.f;
1323 check_success(smpl_result->get_distances(srange, &distance));
1324 mi::Uint32 obj_id = 0;
1325 check_success(smpl_result->get_object_ids(srange, &obj_id));
1326
1327 mi::base::Handle<const nv::index::IRay_sampling_object_info>
1328 obj_info(smpl_result->get_object_info(obj_id));
1329 if (!obj_info.is_valid_interface())
1330 {
1331 ERROR_LOG << info << "The scene element id " << obj_id << " does not refer to a valid scene element tag.\n";
1332 return;
1333 }
1334
1335 const mi::neuraylib::Tag& scene_element_tag = obj_info->get_scene_element();
1336
1337 INFO_LOG << info << "The first opaque color value is at sample " << opaque_idx << " with color " << color
1338 << "\n and extracted from the scene element tag id " << scene_element_tag.id << "."
1339 << "\n The distance of the sample from the camera is " << distance << ".\n";
1340}
1341
1342
1343//----------------------------------------------------------------------
1344// Find the ray segment length between samples to perform opacity correction.
1345// Take distance between current and previous sample of same object_id as segment length.
1346// If the current sample is a surface sample, the result makes no sense (not checked here).
1347mi::Float32 get_ray_segment_length(
1348 mi::Uint32 isample,
1349 const std::vector<mi::Float32>& distances,
1350 const std::vector<mi::Uint32>& object_ids)
1351{
1352 const mi::Uint32 nb_samples = static_cast<mi::Uint32>(distances.size());
1353 if (nb_samples <= 1 || isample >= nb_samples) {
1354 return 0.f;
1355 }
1356 const mi::Uint32 obj_id = object_ids[isample];
1357 // for first sample, take distance to next sample of same object
1358 if (isample == 0) {
1359 mi::Uint32 inext = isample + 1;
1360 if (inext < nb_samples && object_ids[inext] == obj_id) {
1361 return distances[inext] - distances[isample];
1362 }
1363 }
1364 else {
1365 mi::Uint32 iprev = isample - 1;
1366 if (object_ids[iprev] == obj_id) {
1367 return distances[isample] - distances[iprev];
1368 }
1369 }
1370 return 0.f;
1371}
1372
1373
1374// Perform opacity correction for volume sample.
1375mi::Float32 opacity_correction(
1376 mi::Float32 alpha, // opacity
1377 mi::Float32 sampling_ratio) // ratio of used sample distance to the base sample distance (usually 1)
1378{
1379 if (sampling_ratio < 1.0e-6f) sampling_ratio = 1.0e-6f;
1380 return 1.f - powf(1.f - alpha, sampling_ratio);
1381}
1382
1383
1384// Get opacity corrected alpha value of sample.
1385mi::Float32 opacity_corrected_alpha(
1386 mi::Uint32 isample,
1387 const mi::Float32 alpha,
1388 const std::vector<mi::Float32>& distances,
1389 const std::vector<mi::Uint32>& object_ids)
1390{
1391 mi::Float32 seglen = get_ray_segment_length(isample, distances, object_ids);
1392 if (seglen == 0.f) return alpha;
1393
1394 const mi::Float32 ref_seg_len = 1.f; // reference sampling distance
1395 return opacity_correction(alpha, seglen / ref_seg_len);
1396}
1397
1398void determine_accumulated_alpha_value(
1399 mi::Float32 threshold,
1400 const nv::index::IRay_sampling_result* smpl_result)
1401{
1402 const char* info = " Determine accumulated alpha value:\n ";
1403
1404 check_success(smpl_result != 0);
1405 if (!smpl_result->is_valid()) {
1406 ERROR_LOG << info << "Invalid ray sampling result.\n";
1407 return;
1408 }
1409
1410 mi::base::Handle<const nv::index::IRay_sampling_query> query(smpl_result->get_query());
1411 mi::base::Handle<const nv::index::IRay_sampling_value_format> value_format(smpl_result->get_value_format());
1412
1413 check_success(query.is_valid_interface());
1414 if (query->get_nb_rays() < 1) {
1415 ERROR_LOG << info << "No sample ray.\n";
1416 return;
1417 }
1418
1419 const mi::Uint32 ray_idx = 0;
1420 const mi::Uint32 nb_samples = smpl_result->get_nb_samples(ray_idx);
1421
1422 if (nb_samples == 0) {
1423 INFO_LOG << info << "No sample found.\n";
1424 return;
1425 }
1426
1427 nv::index::IRay_sampling_result::Sample_range srange;
1428 srange.first_sample = 0;
1429 srange.nb_samples = nb_samples;
1430 srange.ray_index = ray_idx;
1431
1432 std::vector<mi::Float32> distances(nb_samples);
1433 check_success(smpl_result->get_distances(srange, distances.data()));
1434
1435 std::vector<mi::math::Color_struct> colors(nb_samples);
1436 check_success(smpl_result->get_colors(srange, colors.data()));
1437
1438 std::vector<mi::Uint32> object_ids(nb_samples);
1439 check_success(smpl_result->get_object_ids(srange, object_ids.data()));
1440
1441 mi::math::Color dst(0.f); // Accumulated result.
1442 mi::Uint32 thresh_idx = nb_samples;
1443 for (mi::Uint32 i = 0; i < nb_samples; ++i)
1444 {
1445 const mi::math::Color& src = colors[i];
1446 const mi::Float32 src_alpha = opacity_corrected_alpha(i, src.a, distances, object_ids);
1447 // front-to_back compositing (non-premultiplied alpha)
1448 const mi::Float32 da_sa = (1.0f - dst.a) * src_alpha;
1449 dst.r = mi::math::saturate(dst.r + da_sa * src.r);
1450 dst.g = mi::math::saturate(dst.g + da_sa * src.g);
1451 dst.b = mi::math::saturate(dst.b + da_sa * src.b);
1452 dst.a = mi::math::saturate(dst.a + da_sa);
1453
1454 if (dst.a >= threshold)
1455 {
1456 thresh_idx = i;
1457 break;
1458 }
1459 }
1460
1461 if (thresh_idx == nb_samples) {
1462 INFO_LOG << info << "The accumulated color's alpha did not reach the given threshold "
1463 << threshold << " when determining the accumulated alpha along the given ray sampling.\n";
1464 return;
1465 }
1466
1467 const mi::math::Color accumulated_color = dst;
1468
1469 srange.first_sample = thresh_idx;
1470 srange.nb_samples = 1;
1471 mi::Float32 distance = 0.f;
1472 check_success(smpl_result->get_distances(srange, &distance));
1473 mi::Uint32 obj_id = 0;
1474 check_success(smpl_result->get_object_ids(srange, &obj_id));
1475
1476 mi::base::Handle<const nv::index::IRay_sampling_object_info> obj_info(smpl_result->get_object_info(obj_id));
1477 if (!obj_info.is_valid_interface()) {
1478 ERROR_LOG << info << "The scene element id " << obj_id << " does not refer to a valid scene element tag.";
1479 }
1480 else {
1481 const mi::neuraylib::Tag_struct& scene_element_tag = obj_info->get_scene_element();
1482 INFO_LOG << info << "Based on an alpha threshold of " << threshold
1483 << " the accumulated color is " << accumulated_color << "."
1484 << "\n The threshold has been reached at sample " << thresh_idx
1485 << "\n when sampling the scene element with tag id " << scene_element_tag.id
1486 << "\n at a distance of " << distance << " from the camera.\n";
1487 }
1488}
1489
1490//----------------------------------------------------------------------
1491
1492
1493
1494void print_sampling_info(
1495 const mi::base::Handle<const nv::index::IRay_sampling_result>& smpl_result,
1496 App_rendering_context& arc,
1497 /*const*/ std::map<std::string, std::string>& opt_map)
1498{
1499 mi::base::Handle<mi::neuraylib::IDice_transaction> transaction(
1500 arc.m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
1501 check_success(transaction.is_valid_interface());
1502
1503 // Use the sampling result.
1504 print_sampling_diagnostics(smpl_result.get(), transaction.get());
1505
1506 if (!is_overlap_scene(opt_map)) {
1507 determine_first_opaque_sample(smpl_result.get());
1508
1509 determine_accumulated_alpha_value(0.95f, smpl_result.get());
1510
1511 print_sampling_performance(smpl_result.get(), opt_map);
1512 }
1513
1514 transaction->commit();
1515}
1516
1517//----------------------------------------------------------------------
1518} // namespace anonymous
1519//----------------------------------------------------------------------
1520
1521//=================================================================================================
1522// Testing functionality
1523
1524namespace test {
1525
1526// compare floats with relative error margin
1527inline bool equal_float_relative(float a, float b, const float rel_eps=1.0e-4f)
1528{
1529 const float magnitude = std::max(fabsf(a), fabsf(b));
1530 return fabsf(a - b) <= (magnitude * rel_eps);
1531}
1532
1534{
1535 std::vector<mi::Float32> distances;
1536 std::vector<mi::math::Color_struct> colors;
1537 std::vector<mi::Uint32> object_ids;
1538 std::vector<mi::Float32> values1;
1539 std::vector<mi::Sint32> values2;
1540 std::vector<mi::math::Vector<mi::Float32, 3> > values3;
1541 std::vector<mi::Uint32> value_masks;
1542
1543 void resize(mi::Uint32 new_size, bool user_values)
1544 {
1545 distances.resize(new_size);
1546 colors.resize(new_size);
1547 object_ids.resize(new_size);
1548 const mi::Uint32 user_size = user_values ? new_size : 0;
1549 values1.resize(user_size);
1550 values2.resize(user_size);
1551 values3.resize(user_size);
1552 value_masks.resize(user_size);
1553 }
1554};
1555
1556template<typename T> struct Stream_one {
1557 void write(std::ostream& os, const T& item) { os << item; }
1558 void read(std::istream& is, T& item) { is >> item; }
1559};
1560
1561template<> struct Stream_one<mi::math::Color_struct> {
1562 void write(std::ostream& os, const mi::math::Color_struct& c) {
1563 os << c.r << " " << c.g << " " << c.b << " " << c.a << " ";
1564 }
1565 void read(std::istream& is, mi::math::Color_struct& c) {
1566 is >> c.r >> c.g >> c.b >> c.a;
1567 }
1568};
1569
1570template<typename VE, mi::Size VDIM> struct Stream_one< mi::math::Vector<VE, VDIM> > {
1571 void write(std::ostream& os, const mi::math::Vector<VE, VDIM>& v) {
1572 for (mi::Size i = 0; i < VDIM; ++i) { os << v[i] << " "; }
1573 }
1574 void read(std::istream& is, mi::math::Vector<VE, VDIM>& v) {
1575 for (mi::Size i = 0; i < VDIM; ++i) { is >> v[i]; }
1576 }
1577};
1578
1579template<typename T> struct Verify_one {
1580 // precise comparison by default
1581 bool verify(const T& a, const T& b) const { return a == b; }
1582};
1583template<> struct Verify_one<float> {
1584 // relative epsilon for floating point
1585 bool verify(const float& a, const float& b) const { return equal_float_relative(a, b); }
1586};
1587template<> struct Verify_one<mi::math::Color_struct> {
1588 bool verify(const mi::math::Color_struct& a, const mi::math::Color_struct& b) const {
1590 if (!ver.verify(a.r, b.r)) return false;
1591 if (!ver.verify(a.g, b.g)) return false;
1592 if (!ver.verify(a.b, b.b)) return false;
1593 if (!ver.verify(a.a, b.a)) return false;
1594 return true;
1595 }
1596};
1597template<typename VE, mi::Size VDIM> struct Verify_one< mi::math::Vector<VE, VDIM> > {
1598 bool verify(const mi::math::Vector<VE, VDIM>& a, const mi::math::Vector<VE, VDIM>& b) const {
1600 for (mi::Size i = 0; i < VDIM; ++i) {
1601 if (!ver.verify(a[i], b[i])) return false;
1602 }
1603 return true;
1604 }
1605};
1606
1607template<typename T> void write_array(std::ostream& os, const std::vector<T>& v)
1608{
1609 typedef typename std::vector<T>::size_type sz_type;
1610 const sz_type nb = v.size();
1611 os << nb << " ";
1612 Stream_one<T> s;
1613 for (sz_type i = 0; i < nb; ++i) {
1614 s.write(os, v[i]);
1615 os << " ";
1616 }
1617 os << '\n';
1618}
1619template<typename T> void read_array(std::istream& is, std::vector<T>& v)
1620{
1621 typedef typename std::vector<T>::size_type sz_type;
1622 sz_type nb = 0;
1623 is >> nb;
1624 v.resize(nb);
1625 Stream_one<T> s;
1626 for (sz_type i = 0; i < nb; ++i) {
1627 s.read(is, v[i]);
1628 }
1629}
1630
1631template<typename T> bool verify_array(const std::vector<T>& v, const std::vector<T>& ref_v)
1632{
1633 typedef typename std::vector<T>::size_type sz_type;
1634 const sz_type nb = v.size();
1635 if (nb != ref_v.size()) return false;
1636
1637 Verify_one<T> ver;
1638 for (sz_type i = 0; i < nb; ++i) {
1639 if (!ver.verify(v[i], ref_v[i])) {
1640 return false;
1641 }
1642 }
1643 return true;
1644}
1645
1646
1647void write_sampling_data(std::ostream& os, const Sampling_data& smpl_data)
1648{
1649 write_array(os, smpl_data.distances);
1650 write_array(os, smpl_data.colors);
1651 //write_array(os, smpl_data.object_ids); // might not be unique
1652 write_array(os, smpl_data.value_masks);
1653 write_array(os, smpl_data.values1);
1654 write_array(os, smpl_data.values2);
1655 write_array(os, smpl_data.values3);
1656}
1657
1658void read_sampling_data(std::istream& is, Sampling_data& smpl_data)
1659{
1660 read_array(is, smpl_data.distances);
1661 read_array(is, smpl_data.colors);
1662 read_array(is, smpl_data.value_masks);
1663 read_array(is, smpl_data.values1);
1664 read_array(is, smpl_data.values2);
1665 read_array(is, smpl_data.values3);
1666}
1667
1668int verify_sample_data(const Sampling_data& smpl_data, const Sampling_data& ref_smpl_data)
1669{
1670 if (!verify_array(smpl_data.distances, ref_smpl_data.distances)) return 201;
1671 if (!verify_array(smpl_data.colors, ref_smpl_data.colors)) return 202;
1672 if (!verify_array(smpl_data.value_masks, ref_smpl_data.value_masks)) return 203;
1673 if (!verify_array(smpl_data.values1, ref_smpl_data.values1)) return 204;
1674 if (!verify_array(smpl_data.values2, ref_smpl_data.values2)) return 205;
1675 if (!verify_array(smpl_data.values3, ref_smpl_data.values3)) return 206;
1676 return 0;
1677}
1678
1679
1680template <typename T>
1682 const nv::index::IRay_sampling_result* smpl_result,
1683 const nv::index::IRay_sampling_result::Sample_range& srange,
1684 mi::Uint32 user_value_index,
1685 const std::vector<mi::Uint32>& value_masks,
1686 std::vector<T>& values,
1687 const T& default_value)
1688{
1689 smpl_result->get_user_values(srange, user_value_index, values.data());
1690 const mi::Uint32 mask = 1u << user_value_index;
1691 for (mi::Uint32 i = 0; i < srange.nb_samples; ++i) {
1692 if ((value_masks[i] & mask) == 0) {
1693 values[i] = default_value;
1694 }
1695 }
1696}
1697
1699 const nv::index::IRay_sampling_result* smpl_result,
1700 const nv::index::IRay_sampling_result::Sample_range& srange,
1701 bool has_user_values,
1702 Sampling_data& smpl_data)
1703{
1704 smpl_data.resize(srange.nb_samples, has_user_values);
1705
1706 smpl_result->get_distances(srange, smpl_data.distances.data());
1707 smpl_result->get_colors(srange, smpl_data.colors.data());
1708 //smpl_result->get_object_ids (srange, smpl_data.object_ids.data());
1709
1710 if (has_user_values) {
1711 smpl_result->get_user_value_masks(srange, smpl_data.value_masks.data());
1712 get_masked_user_value(smpl_result, srange, 0, smpl_data.value_masks, smpl_data.values1, 0.f);
1713 get_masked_user_value(smpl_result, srange, 1, smpl_data.value_masks, smpl_data.values2, 0);
1714 get_masked_user_value(smpl_result, srange, 2, smpl_data.value_masks, smpl_data.values3, mi::math::Vector<mi::Float32, 3>(0.f, 0.f, 0.f));
1715 }
1716}
1717
1718
1719
1720// Write samples of all rays into stream.
1721// Format:
1722//
1723// {nb_rays}
1724// {ray_idx nb_samples has_user_values}
1725// {nb_distances, ...}
1726// {nb_colors, ...}
1727// {nb_value_masks, ...}
1728// {nb_values1, ...}
1729// {nb_values2, ...}
1730// {nb_values3, ...}
1731// {ray_idx}
1732// ...
1733//
1735 std::ostream& os,
1736 mi::Uint32 max_nb_samples,
1737 const nv::index::IRay_sampling_result* smpl_result)
1738{
1739 if (!smpl_result->is_valid()) {
1740 return;
1741 }
1742
1743 mi::base::Handle<const nv::index::IRay_sampling_query> query(smpl_result->get_query());
1744 mi::base::Handle<const nv::index::IRay_sampling_value_format> value_format(smpl_result->get_value_format());
1745
1746 if (!query.is_valid_interface()) {
1747 return;
1748 }
1749 const mi::Uint32 nb_rays = query->get_nb_rays();
1750 if (nb_rays < 1) {
1751 return;
1752 }
1753
1754 os << nb_rays << '\n';
1755
1756 Sampling_data smpl_data;
1757 const bool has_user_values = value_format.is_valid_interface();
1758
1759 for (mi::Uint32 ray_idx = 0; ray_idx < nb_rays; ++ray_idx)
1760 {
1761 const mi::Uint32 nb_samples = smpl_result->get_nb_samples(ray_idx);
1762 const mi::Uint32 nb_first_samples = std::min(nb_samples, max_nb_samples);
1763
1764 os << ray_idx << " " << nb_first_samples << " " << has_user_values << '\n';
1765
1766 if (nb_samples == 0) {
1767 continue;
1768 }
1769
1770 nv::index::IRay_sampling_result::Sample_range srange;
1771 srange.first_sample = 0;
1772 srange.nb_samples = nb_first_samples;
1773 srange.ray_index = ray_idx;
1774
1775 get_sample_data(smpl_result, srange, has_user_values, smpl_data);
1776
1777 write_sampling_data(os, smpl_data);
1778 }
1779}
1780
1781
1783 std::istream& is,
1784 std::vector<Sampling_data>& smpl_data)
1785{
1786 mi::Uint32 nb_rays = 0;
1787 is >> nb_rays;
1788 smpl_data.resize(nb_rays);
1789
1790 for (mi::Uint32 ray_idx = 0; ray_idx < nb_rays; ++ray_idx)
1791 {
1792 mi::Uint32 in_ray_idx = 0;
1793 mi::Uint32 nb_values = 0;
1794 int has_user_values = 0;
1795 is >> in_ray_idx >> nb_values >> has_user_values;
1796 if (nb_values == 0) {
1797 continue;
1798 }
1799 smpl_data[ray_idx].resize(nb_values, has_user_values != 0);
1800 read_sampling_data(is, smpl_data[ray_idx]);
1801 }
1802}
1803
1804
1806 const std::string& basename,
1807 /*const*/ std::map<std::string, std::string>& opt_map,
1808 const std::string& info)
1809{
1810 const int user_prg = nv::index::app::get_sint32(opt_map["user_program_mode"]);
1811
1812 std::string filename = basename;
1813 if (!filename.empty()) {
1814 filename.append("__");
1815 filename.append(opt_map["scene"]);
1816 filename.append("_");
1817 filename.append(opt_map["user_program_mode"]);
1818 if (user_prg >= 2) {
1819 filename.append("_");
1820 filename.append(opt_map["user_values"]);
1821 }
1822 filename.append("_");
1823 filename.append(info); // post, pre
1824 filename.append(".samples");
1825 }
1826 return filename;
1827}
1828
1830 const nv::index::IRay_sampling_result* smpl_result,
1831 /*const*/ std::map<std::string, std::string>& opt_map,
1832 const std::string& basename,
1833 const std::string& info)
1834{
1835 std::string filename = make_sample_filename(basename, opt_map, info);
1836 std::ofstream export_file(filename.c_str(), std::ios::out | std::ios::trunc);
1837 export_sampling_result(export_file, 1000, smpl_result);
1838}
1839
1840
1842 const nv::index::IRay_sampling_result* smpl_result,
1843 /*const*/ std::map<std::string, std::string>& opt_map,
1844 const std::string& basename,
1845 const std::string& info)
1846{
1847 std::vector<Sampling_data> ref_smpl_data;
1848 {
1849 std::string filename = make_sample_filename(basename, opt_map, info);
1850 std::ifstream import_file(filename.c_str());
1851 import_sampling_result(import_file, ref_smpl_data);
1852 if (ref_smpl_data.empty()) {
1853 return 100;
1854 }
1855 }
1856
1857 if (!smpl_result->is_valid()) {
1858 return 101;
1859 }
1860
1861 mi::base::Handle<const nv::index::IRay_sampling_query> query(smpl_result->get_query());
1862 mi::base::Handle<const nv::index::IRay_sampling_value_format> value_format(smpl_result->get_value_format());
1863
1864 if (!query.is_valid_interface()) {
1865 return 102;
1866 }
1867 const mi::Uint32 nb_rays = query->get_nb_rays();
1868 if (nb_rays < 1) {
1869 return 103;
1870 }
1871 if (nb_rays != static_cast<mi::Uint32>(ref_smpl_data.size())) {
1872 return 104;
1873 }
1874
1875 Sampling_data smpl_data;
1876 const bool has_user_values = value_format.is_valid_interface();
1877
1878 for (mi::Uint32 ray_idx = 0; ray_idx < nb_rays; ++ray_idx)
1879 {
1880 const Sampling_data& ref_samples = ref_smpl_data[ray_idx];
1881
1882 const mi::Uint32 nb_samples = smpl_result->get_nb_samples(ray_idx);
1883 const mi::Uint32 nb_ref_samples = static_cast<mi::Uint32>(ref_samples.distances.size());
1884
1885 if (nb_samples != nb_ref_samples) return 105;
1886
1887 const mi::Uint32 nb_first_samples = std::min(nb_samples, nb_ref_samples);
1888 if (nb_first_samples == 0) continue;
1889
1890 nv::index::IRay_sampling_result::Sample_range srange;
1891 srange.first_sample = 0;
1892 srange.nb_samples = nb_first_samples;
1893 srange.ray_index = ray_idx;
1894
1895 get_sample_data(smpl_result, srange, has_user_values, smpl_data);
1896
1897 int code = verify_sample_data(smpl_data, ref_samples);
1898 if (code != 0) {
1899 return code;
1900 }
1901 }
1902 return 0;
1903}
1904
1905
1907 const nv::index::IRay_sampling_result* smpl_result,
1908 /*const*/ std::map<std::string, std::string>& opt_map,
1909 const std::string& info)
1910{
1911 int code = 0;
1912 if (!opt_map["export_sample_file"].empty()) {
1913 export_sample_file(smpl_result, opt_map, opt_map["export_sample_file"], info);
1914 }
1915 if (!opt_map["verify_sample_file"].empty()) {
1916 std::string ref_filename = opt_map["verify_sample_file"];
1917 code = test::verify_sample_file(smpl_result, opt_map, ref_filename, info);
1918 if (code != 0) {
1919 ERROR_LOG << "Verification failed (" << info << "): " << code;
1920 }
1921 else {
1922 INFO_LOG << "Verification succeeded (" << info << ")";
1923 }
1924 }
1925 return code;
1926}
1927
1928//----------------------------------------------------------------------
1929} // namespace anonymous
1930//----------------------------------------------------------------------
1931
1932//=================================================================================================
1933
1934int main(int argc, char* argv[])
1935{
1936 std::map<std::string, std::string> opt_map;
1937 const ray_sampling::IRay_sampling_scene_setup* scene_setup =
1938 handle_arguments(opt_map, argc, argv);
1939
1940 // Load IndeX library
1941 const std::string comp_dso_prefix = "libnvindex_application_layer_";
1942 const std::string plug_dso_prefix = "libnvindex_plugin_";
1943 Nvindex_access nvindex_accessor;
1944 check_success(nvindex_accessor.load_library());
1945 check_success(nvindex_accessor.load_application_layer_library());
1946 check_success(nvindex_accessor.load_application_layer_component((comp_dso_prefix + "canvas_infrastructure").c_str()));
1947 check_success(nvindex_accessor.load_application_layer_component((comp_dso_prefix + "data_analysis_and_processing").c_str()));
1948 check_success(nvindex_accessor.load_application_layer_component((comp_dso_prefix + "image").c_str()));
1949 check_success(nvindex_accessor.load_application_layer_component((comp_dso_prefix + "io").c_str()));
1950 check_success(nvindex_accessor.load_application_layer_plugin( (plug_dso_prefix + "base_importer"). c_str()));
1951 check_success(nvindex_accessor.load_application_layer_plugin( (plug_dso_prefix + "legacy_importer").c_str()));
1952
1953 start_nvindex_service(nvindex_accessor, opt_map, scene_setup);
1954 if (!nvindex_accessor.is_initialized())
1955 {
1956 info_cout("Fatal error! Initialization of the IndeX library failed.", opt_map);
1957 return 1;
1958 }
1959
1960 mi::Sint32 exit_code = 0;
1961
1962 const char* sep_line = "----------------------------------------------------------------------------";
1963 {
1964 App_rendering_context arc;
1965 setup_app_context(arc, nvindex_accessor);
1966
1967 // Verifying that local host has joined. This may fail when there is a license problem.
1968 check_success(arc.is_local_host_joined());
1969
1970 INFO_LOG << "\n" << sep_line << "\n Ray Sampling Example - Scene " << scene_setup->name() << "\n" << sep_line;
1971
1972 // Scene setup
1973 {
1974 setup_scene(nvindex_accessor, scene_setup, arc, opt_map);
1975 }
1976
1977 setup_performance_monitoring(arc, opt_map);
1978
1979 const mi::Uint32 ray_sampling_mode = nv::index::app::get_uint32(opt_map["run_sampling"]);
1980
1981 // Ray sampling, pre-render
1982 if (ray_sampling_mode >= 2)
1983 {
1984 mi::base::Handle<const nv::index::IRay_sampling_result> smpl_result =
1985 perform_ray_sampling(arc, nvindex_accessor.get_interface().get(), opt_map);
1986 INFO_LOG << sep_line;
1987 print_sampling_info(smpl_result, arc, opt_map);
1988
1989 const int code = test::handle_verification(smpl_result.get(), opt_map, "pre");
1990 if (code != 0) {
1991 exit_code = code;
1992 }
1993 }
1994
1995 // Rendering
1996 {
1997 // Render a frame and save the rendered image to a file.
1998 const mi::Sint32 frame_idx = 0;
1999 const std::string fname = get_output_file_name(opt_map["outfname"], frame_idx);
2000
2001
2002 INFO_LOG << sep_line;
2003 INFO_LOG << "Rendering one frame \n";
2004 mi::base::Handle<const nv::index::IFrame_results> frame_results(
2005 render_frame(arc, fname));
2006
2007
2008 mi::base::Handle<const nv::index::IError_set> err_set(frame_results->get_error_set());
2009 if (err_set->any_errors())
2010 {
2011 handle_errors(err_set.get());
2012 exit_code = 1;
2013 }
2014
2015 print_performance(frame_results.get(), opt_map);
2016
2017 // verify the generated frame
2018 if (!(verify_canvas_result(nvindex_accessor.get_application_layer_interface(),
2019 arc.m_image_canvas.get(), opt_map["verify_image_fname"], opt_map)))
2020 {
2021 exit_code = 1;
2022 }
2023 }
2024
2025 // Ray sampling, post-render
2026 if (ray_sampling_mode == 1 || ray_sampling_mode == 3)
2027 {
2028 mi::base::Handle<const nv::index::IRay_sampling_result> smpl_result =
2029 perform_ray_sampling(arc, nvindex_accessor.get_interface().get(), opt_map);
2030 INFO_LOG << sep_line;
2031 print_sampling_info(smpl_result, arc, opt_map);
2032
2033 const int code = test::handle_verification(smpl_result.get(), opt_map, "post");
2034 if (code != 0) {
2035 exit_code = code;
2036 }
2037 }
2038 arc.shutdown();
2039 }
2040 nvindex_accessor.shutdown();
2041
2042 return exit_code;
2043}
virtual void register_classes(nv::index::IIndex *) const
virtual bool create_scene(nv::index::app::IApplication_layer *app_layer, Scene_info &scene_info, const mi::math::Bbox< mi::Float32, 3 > &roi_bbox, const mi::neuraylib::Tag &session_tag, std::map< std::string, std::string > &opt_map, mi::neuraylib::IDice_transaction *transaction) const =0
virtual void setup_camera(const mi::neuraylib::Tag &camera_tag, mi::neuraylib::IDice_transaction *transaction) const =0
virtual void adjust_configuration(nv::index::IConfig_settings *config_settings, std::map< std::string, std::string > &opt_map) const
virtual const char * get_roi_string() const =0
virtual const char * name() const =0
virtual void usage_info(Usage_helper &) const
virtual void add_arguments(Option_map &opt_map) const
void get_sample_data(const nv::index::IRay_sampling_result *smpl_result, const nv::index::IRay_sampling_result::Sample_range &srange, bool has_user_values, Sampling_data &smpl_data)
std::string make_sample_filename(const std::string &basename, std::map< std::string, std::string > &opt_map, const std::string &info)
int verify_sample_data(const Sampling_data &smpl_data, const Sampling_data &ref_smpl_data)
void export_sampling_result(std::ostream &os, mi::Uint32 max_nb_samples, const nv::index::IRay_sampling_result *smpl_result)
void export_sample_file(const nv::index::IRay_sampling_result *smpl_result, std::map< std::string, std::string > &opt_map, const std::string &basename, const std::string &info)
void write_array(std::ostream &os, const std::vector<T> &v)
bool equal_float_relative(float a, float b, const float rel_eps=1.0e-4f)
void write_sampling_data(std::ostream &os, const Sampling_data &smpl_data)
int verify_sample_file(const nv::index::IRay_sampling_result *smpl_result, std::map< std::string, std::string > &opt_map, const std::string &basename, const std::string &info)
void read_sampling_data(std::istream &is, Sampling_data &smpl_data)
void get_masked_user_value(const nv::index::IRay_sampling_result *smpl_result, const nv::index::IRay_sampling_result::Sample_range &srange, mi::Uint32 user_value_index, const std::vector< mi::Uint32 > &value_masks, std::vector<T> &values, const T &default_value)
bool verify_array(const std::vector<T> &v, const std::vector<T> &ref_v)
void import_sampling_result(std::istream &is, std::vector<Sampling_data> &smpl_data)
int handle_verification(const nv::index::IRay_sampling_result *smpl_result, std::map< std::string, std::string > &opt_map, const std::string &info)
void read_array(std::istream &is, std::vector<T> &v)
void setup_app_context(App_rendering_context &arc, Nvindex_access &nvindex_accessor)
void start_nvindex_service(Nvindex_access &nvindex_accessor, const Option_map &opt_map, const xac_compute::IXac_compute_scene_setup *scene_setup)
void dump_text(const std::string &filename, const std::string &text)
static const int num_scenes
bool has_key(const Option_map &opt_map, const std::string &key)
Definition: xac_compute.h:85
const IXac_compute_scene_setup * handle_arguments(Option_map &opt_map, int argc, char *argv[])
void setup_scene(Nvindex_access &nvindex_accessor, const xac_compute::IXac_compute_scene_setup *scene_setup, Compute_launch_info &info, App_rendering_context &arc, const Option_map &opt_map)
static void view_all_bbox(const Vec3f &from, const Vec3f &up, const Bbox3f &bbox, mi::neuraylib::Tag camera_tag, mi::neuraylib::Tag scene_tag, mi::neuraylib::IDice_transaction *dice_transaction)
nv::index::IFrame_results * render_frame(App_rendering_context &arc, const std::string &output_fname)
void load_text(const std::string &filename, std::string &text)
const IXac_compute_scene_setup * get_scene_setup(int i)
void print_performance(const nv::index::IPerformance_values *performance_values, const Option_map &opt_map, const char *info)
void setup_performance_monitoring(App_rendering_context &arc, const Option_map &opt_map)
int main(int argc, char *argv[])
Irregular volume setup for ray sampling example.
Sparse volume setup for ray sampling example.
#define check_success(expr)
void resize(mi::Uint32 new_size, bool user_values)
std::vector< mi::Uint32 > object_ids
std::vector< mi::math::Color_struct > colors
std::vector< mi::Float32 > distances
std::vector< mi::Uint32 > value_masks
std::vector< mi::Sint32 > values2
std::vector< mi::Float32 > values1
std::vector< mi::math::Vector< mi::Float32, 3 > > values3
void read(std::istream &is, mi::math::Color_struct &c)
void write(std::ostream &os, const mi::math::Color_struct &c)
void write(std::ostream &os, const mi::math::Vector<VE, VDIM> &v)
void read(std::istream &is, mi::math::Vector<VE, VDIM> &v)
void read(std::istream &is, T &item)
void write(std::ostream &os, const T &item)
bool verify(const float &a, const float &b) const
bool verify(const mi::math::Color_struct &a, const mi::math::Color_struct &b) const
bool verify(const mi::math::Vector<VE, VDIM> &a, const mi::math::Vector<VE, VDIM> &b) const
bool verify(const T &a, const T &b) const